mirror of
https://github.com/opencv/opencv.git
synced 2024-12-11 22:59:16 +08:00
1590 lines
39 KiB
C++
1590 lines
39 KiB
C++
/*M///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
|
//
|
|
// By downloading, copying, installing or using the software you agree to this license.
|
|
// If you do not agree to this license, do not download, install,
|
|
// copy or use the software.
|
|
//
|
|
//
|
|
// License Agreement
|
|
// For Open Source Computer Vision Library
|
|
//
|
|
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
|
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
|
// Third party copyrights are property of their respective owners.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
// are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistribution's of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
//
|
|
// * Redistribution's in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
// * The name of the copyright holders may not be used to endorse or promote products
|
|
// derived from this software without specific prior written permission.
|
|
//
|
|
// This software is provided by the copyright holders and contributors "as is" and
|
|
// any express or implied warranties, including, but not limited to, the implied
|
|
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
|
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
|
// indirect, incidental, special, exemplary, or consequential damages
|
|
// (including, but not limited to, procurement of substitute goods or services;
|
|
// loss of use, data, or profits; or business interruption) however caused
|
|
// and on any theory of liability, whether in contract, strict liability,
|
|
// or tort (including negligence or otherwise) arising in any way out of
|
|
// the use of this software, even if advised of the possibility of such damage.
|
|
//
|
|
//M*/
|
|
|
|
#include "precomp.hpp"
|
|
#include <iostream>
|
|
#include "opencv2/core/opengl_interop.hpp"
|
|
#include "opencv2/core/gpumat.hpp"
|
|
|
|
#ifdef HAVE_OPENGL
|
|
#ifdef __APPLE__
|
|
#include <OpenGL/gl.h>
|
|
#include <OpenGL/glu.h>
|
|
#else
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_CUDA
|
|
#include <cuda_runtime.h>
|
|
#include <cuda_gl_interop.h>
|
|
#endif
|
|
#endif
|
|
|
|
using namespace std;
|
|
using namespace cv;
|
|
using namespace cv::gpu;
|
|
|
|
#ifndef HAVE_OPENGL
|
|
#define throw_nogl CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support")
|
|
#define throw_nocuda CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support")
|
|
#else
|
|
#define throw_nogl CV_Error(CV_OpenGlNotSupported, "OpenGL context doesn't exist")
|
|
|
|
#ifndef HAVE_CUDA
|
|
#define throw_nocuda CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support")
|
|
#else
|
|
#if defined(__GNUC__)
|
|
#define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__, __func__)
|
|
#else /* defined(__CUDACC__) || defined(__MSVC__) */
|
|
#define cudaSafeCall(expr) ___cudaSafeCall(expr, __FILE__, __LINE__)
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "")
|
|
{
|
|
if (cudaSuccess != err)
|
|
cv::gpu::error(cudaGetErrorString(err), file, line, func);
|
|
}
|
|
}
|
|
#endif // HAVE_CUDA
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
class EmptyGlFuncTab : public CvOpenGlFuncTab
|
|
{
|
|
public:
|
|
void genBuffers(int, unsigned int*) const { throw_nogl; }
|
|
void deleteBuffers(int, const unsigned int*) const { throw_nogl; }
|
|
|
|
void bufferData(unsigned int, ptrdiff_t, const void*, unsigned int) const { throw_nogl; }
|
|
void bufferSubData(unsigned int, ptrdiff_t, ptrdiff_t, const void*) const { throw_nogl; }
|
|
|
|
void bindBuffer(unsigned int, unsigned int) const { throw_nogl; }
|
|
|
|
void* mapBuffer(unsigned int, unsigned int) const { throw_nogl; return 0; }
|
|
void unmapBuffer(unsigned int) const { throw_nogl; }
|
|
|
|
void generateBitmapFont(const std::string&, int, int, bool, bool, int, int, int) const { throw_nogl; }
|
|
|
|
bool isGlContextInitialized() const { return false; }
|
|
};
|
|
|
|
const CvOpenGlFuncTab* g_glFuncTab = 0;
|
|
|
|
#if defined HAVE_CUDA || defined HAVE_OPENGL
|
|
const CvOpenGlFuncTab* glFuncTab()
|
|
{
|
|
static EmptyGlFuncTab empty;
|
|
return g_glFuncTab ? g_glFuncTab : ∅
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CvOpenGlFuncTab::~CvOpenGlFuncTab()
|
|
{
|
|
if (g_glFuncTab == this)
|
|
g_glFuncTab = 0;
|
|
}
|
|
|
|
void icvSetOpenGlFuncTab(const CvOpenGlFuncTab* tab)
|
|
{
|
|
g_glFuncTab = tab;
|
|
}
|
|
|
|
#ifdef HAVE_OPENGL
|
|
#ifndef GL_DYNAMIC_DRAW
|
|
#define GL_DYNAMIC_DRAW 0x88E8
|
|
#endif
|
|
|
|
#ifndef GL_READ_WRITE
|
|
#define GL_READ_WRITE 0x88BA
|
|
#endif
|
|
|
|
#ifndef GL_BGR
|
|
#define GL_BGR 0x80E0
|
|
#endif
|
|
|
|
#ifndef GL_BGRA
|
|
#define GL_BGRA 0x80E1
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
const GLenum gl_types[] = {GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE};
|
|
|
|
#ifdef HAVE_CUDA
|
|
bool g_isCudaGlDeviceInitialized = false;
|
|
#endif
|
|
}
|
|
#endif // HAVE_OPENGL
|
|
|
|
void cv::gpu::setGlDevice(int device)
|
|
{
|
|
#ifndef HAVE_CUDA
|
|
(void)device;
|
|
throw_nocuda;
|
|
#else
|
|
#ifndef HAVE_OPENGL
|
|
(void)device;
|
|
throw_nogl;
|
|
#else
|
|
if (!glFuncTab()->isGlContextInitialized())
|
|
throw_nogl;
|
|
|
|
cudaSafeCall( cudaGLSetGLDevice(device) );
|
|
|
|
g_isCudaGlDeviceInitialized = true;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// CudaGlInterop
|
|
|
|
#if defined HAVE_CUDA && defined HAVE_OPENGL
|
|
namespace
|
|
{
|
|
class CudaGlInterop
|
|
{
|
|
public:
|
|
CudaGlInterop();
|
|
~CudaGlInterop();
|
|
|
|
void registerBuffer(unsigned int buffer);
|
|
|
|
void copyFrom(const GpuMat& mat, cudaStream_t stream = 0);
|
|
|
|
GpuMat map(int rows, int cols, int type, cudaStream_t stream = 0);
|
|
void unmap(cudaStream_t stream = 0);
|
|
|
|
private:
|
|
cudaGraphicsResource_t resource_;
|
|
};
|
|
|
|
inline CudaGlInterop::CudaGlInterop() : resource_(0)
|
|
{
|
|
}
|
|
|
|
CudaGlInterop::~CudaGlInterop()
|
|
{
|
|
if (resource_)
|
|
{
|
|
cudaGraphicsUnregisterResource(resource_);
|
|
resource_ = 0;
|
|
}
|
|
}
|
|
|
|
void CudaGlInterop::registerBuffer(unsigned int buffer)
|
|
{
|
|
if (!g_isCudaGlDeviceInitialized)
|
|
cvError(CV_GpuApiCallError, "registerBuffer", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
|
|
|
|
cudaGraphicsResource_t resource;
|
|
cudaSafeCall( cudaGraphicsGLRegisterBuffer(&resource, buffer, cudaGraphicsMapFlagsNone) );
|
|
|
|
resource_ = resource;
|
|
}
|
|
|
|
void CudaGlInterop::copyFrom(const GpuMat& mat, cudaStream_t stream)
|
|
{
|
|
CV_Assert(resource_ != 0);
|
|
|
|
cudaSafeCall( cudaGraphicsMapResources(1, &resource_, stream) );
|
|
|
|
void* dst_ptr;
|
|
size_t num_bytes;
|
|
cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&dst_ptr, &num_bytes, resource_) );
|
|
|
|
const void* src_ptr = mat.ptr();
|
|
size_t widthBytes = mat.cols * mat.elemSize();
|
|
|
|
CV_Assert(widthBytes * mat.rows <= num_bytes);
|
|
|
|
if (stream == 0)
|
|
cudaSafeCall( cudaMemcpy2D(dst_ptr, widthBytes, src_ptr, mat.step, widthBytes, mat.rows, cudaMemcpyDeviceToDevice) );
|
|
else
|
|
cudaSafeCall( cudaMemcpy2DAsync(dst_ptr, widthBytes, src_ptr, mat.step, widthBytes, mat.rows, cudaMemcpyDeviceToDevice, stream) );
|
|
|
|
cudaGraphicsUnmapResources(1, &resource_, stream);
|
|
}
|
|
|
|
GpuMat CudaGlInterop::map(int rows, int cols, int type, cudaStream_t stream)
|
|
{
|
|
CV_Assert(resource_ != 0);
|
|
|
|
cudaSafeCall( cudaGraphicsMapResources(1, &resource_, stream) );
|
|
|
|
void* ptr;
|
|
size_t num_bytes;
|
|
cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&ptr, &num_bytes, resource_) );
|
|
|
|
CV_Assert( static_cast<size_t>(cols) * CV_ELEM_SIZE(type) * rows <= num_bytes );
|
|
|
|
return GpuMat(rows, cols, type, ptr);
|
|
}
|
|
|
|
inline void CudaGlInterop::unmap(cudaStream_t stream)
|
|
{
|
|
cudaGraphicsUnmapResources(1, &resource_, stream);
|
|
}
|
|
}
|
|
#endif // HAVE_CUDA && HAVE_OPENGL
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// GlBuffer
|
|
|
|
#ifndef HAVE_OPENGL
|
|
|
|
class cv::GlBuffer::Impl
|
|
{
|
|
};
|
|
|
|
#else
|
|
|
|
class cv::GlBuffer::Impl
|
|
{
|
|
public:
|
|
static const Ptr<Impl>& empty();
|
|
|
|
Impl(int rows, int cols, int type, unsigned int target);
|
|
Impl(const Mat& m, unsigned int target);
|
|
~Impl();
|
|
|
|
void copyFrom(const Mat& m, unsigned int target);
|
|
|
|
#ifdef HAVE_CUDA
|
|
void copyFrom(const GpuMat& mat, cudaStream_t stream = 0);
|
|
#endif
|
|
|
|
void bind(unsigned int target) const;
|
|
void unbind(unsigned int target) const;
|
|
|
|
Mat mapHost(int rows, int cols, int type, unsigned int target);
|
|
void unmapHost(unsigned int target);
|
|
|
|
#ifdef HAVE_CUDA
|
|
GpuMat mapDevice(int rows, int cols, int type, cudaStream_t stream = 0);
|
|
void unmapDevice(cudaStream_t stream = 0);
|
|
#endif
|
|
|
|
private:
|
|
Impl();
|
|
|
|
unsigned int buffer_;
|
|
|
|
#ifdef HAVE_CUDA
|
|
CudaGlInterop cudaGlInterop_;
|
|
#endif
|
|
};
|
|
|
|
inline const Ptr<cv::GlBuffer::Impl>& cv::GlBuffer::Impl::empty()
|
|
{
|
|
static Ptr<Impl> p(new Impl);
|
|
return p;
|
|
}
|
|
|
|
inline cv::GlBuffer::Impl::Impl() : buffer_(0)
|
|
{
|
|
}
|
|
|
|
cv::GlBuffer::Impl::Impl(int rows, int cols, int type, unsigned int target) : buffer_(0)
|
|
{
|
|
if (!glFuncTab()->isGlContextInitialized())
|
|
throw_nogl;
|
|
|
|
CV_DbgAssert(rows > 0 && cols > 0);
|
|
CV_DbgAssert(CV_MAT_DEPTH(type) >= 0 && CV_MAT_DEPTH(type) <= CV_64F);
|
|
|
|
glFuncTab()->genBuffers(1, &buffer_);
|
|
CV_CheckGlError();
|
|
CV_Assert(buffer_ != 0);
|
|
|
|
size_t size = rows * cols * CV_ELEM_SIZE(type);
|
|
|
|
glFuncTab()->bindBuffer(target, buffer_);
|
|
CV_CheckGlError();
|
|
|
|
glFuncTab()->bufferData(target, size, 0, GL_DYNAMIC_DRAW);
|
|
CV_CheckGlError();
|
|
|
|
glFuncTab()->bindBuffer(target, 0);
|
|
|
|
#ifdef HAVE_CUDA
|
|
if (g_isCudaGlDeviceInitialized)
|
|
cudaGlInterop_.registerBuffer(buffer_);
|
|
#endif
|
|
}
|
|
|
|
cv::GlBuffer::Impl::Impl(const Mat& m, unsigned int target) : buffer_(0)
|
|
{
|
|
if (!glFuncTab()->isGlContextInitialized())
|
|
throw_nogl;
|
|
|
|
CV_DbgAssert(m.rows > 0 && m.cols > 0);
|
|
CV_DbgAssert(m.depth() >= 0 && m.depth() <= CV_64F);
|
|
CV_Assert(m.isContinuous());
|
|
|
|
glFuncTab()->genBuffers(1, &buffer_);
|
|
CV_CheckGlError();
|
|
CV_Assert(buffer_ != 0);
|
|
|
|
size_t size = m.rows * m.cols * m.elemSize();
|
|
|
|
glFuncTab()->bindBuffer(target, buffer_);
|
|
CV_CheckGlError();
|
|
|
|
glFuncTab()->bufferData(target, size, m.data, GL_DYNAMIC_DRAW);
|
|
CV_CheckGlError();
|
|
|
|
glFuncTab()->bindBuffer(target, 0);
|
|
|
|
#ifdef HAVE_CUDA
|
|
if (g_isCudaGlDeviceInitialized)
|
|
cudaGlInterop_.registerBuffer(buffer_);
|
|
#endif
|
|
}
|
|
|
|
cv::GlBuffer::Impl::~Impl()
|
|
{
|
|
try
|
|
{
|
|
if (buffer_)
|
|
glFuncTab()->deleteBuffers(1, &buffer_);
|
|
}
|
|
#ifdef _DEBUG
|
|
catch(const exception& e)
|
|
{
|
|
cerr << e.what() << endl;
|
|
}
|
|
#endif
|
|
catch(...)
|
|
{
|
|
}
|
|
}
|
|
|
|
void cv::GlBuffer::Impl::copyFrom(const Mat& m, unsigned int target)
|
|
{
|
|
CV_Assert(buffer_ != 0);
|
|
|
|
CV_Assert(m.isContinuous());
|
|
|
|
bind(target);
|
|
|
|
size_t size = m.rows * m.cols * m.elemSize();
|
|
|
|
glFuncTab()->bufferSubData(target, 0, size, m.data);
|
|
CV_CheckGlError();
|
|
|
|
unbind(target);
|
|
}
|
|
|
|
#ifdef HAVE_CUDA
|
|
|
|
void cv::GlBuffer::Impl::copyFrom(const GpuMat& mat, cudaStream_t stream)
|
|
{
|
|
if (!g_isCudaGlDeviceInitialized)
|
|
cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
|
|
|
|
CV_Assert(buffer_ != 0);
|
|
|
|
cudaGlInterop_.copyFrom(mat, stream);
|
|
}
|
|
|
|
#endif // HAVE_CUDA
|
|
|
|
inline void cv::GlBuffer::Impl::bind(unsigned int target) const
|
|
{
|
|
CV_Assert(buffer_ != 0);
|
|
|
|
glFuncTab()->bindBuffer(target, buffer_);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
inline void cv::GlBuffer::Impl::unbind(unsigned int target) const
|
|
{
|
|
glFuncTab()->bindBuffer(target, 0);
|
|
}
|
|
|
|
inline Mat cv::GlBuffer::Impl::mapHost(int rows, int cols, int type, unsigned int target)
|
|
{
|
|
void* ptr = glFuncTab()->mapBuffer(target, GL_READ_WRITE);
|
|
CV_CheckGlError();
|
|
|
|
return Mat(rows, cols, type, ptr);
|
|
}
|
|
|
|
inline void cv::GlBuffer::Impl::unmapHost(unsigned int target)
|
|
{
|
|
glFuncTab()->unmapBuffer(target);
|
|
}
|
|
|
|
#ifdef HAVE_CUDA
|
|
|
|
inline GpuMat cv::GlBuffer::Impl::mapDevice(int rows, int cols, int type, cudaStream_t stream)
|
|
{
|
|
if (!g_isCudaGlDeviceInitialized)
|
|
cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
|
|
|
|
CV_Assert(buffer_ != 0);
|
|
|
|
return cudaGlInterop_.map(rows, cols, type, stream);
|
|
}
|
|
|
|
inline void cv::GlBuffer::Impl::unmapDevice(cudaStream_t stream)
|
|
{
|
|
if (!g_isCudaGlDeviceInitialized)
|
|
cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
|
|
|
|
cudaGlInterop_.unmap(stream);
|
|
}
|
|
|
|
#endif // HAVE_CUDA
|
|
|
|
#endif // HAVE_OPENGL
|
|
|
|
cv::GlBuffer::GlBuffer(Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_usage;
|
|
throw_nogl;
|
|
#else
|
|
impl_ = Impl::empty();
|
|
#endif
|
|
}
|
|
|
|
cv::GlBuffer::GlBuffer(int _rows, int _cols, int _type, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_rows;
|
|
(void)_cols;
|
|
(void)_type;
|
|
(void)_usage;
|
|
throw_nogl;
|
|
#else
|
|
impl_ = new Impl(_rows, _cols, _type, _usage);
|
|
rows_ = _rows;
|
|
cols_ = _cols;
|
|
type_ = _type;
|
|
#endif
|
|
}
|
|
|
|
cv::GlBuffer::GlBuffer(Size _size, int _type, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_size;
|
|
(void)_type;
|
|
(void)_usage;
|
|
throw_nogl;
|
|
#else
|
|
impl_ = new Impl(_size.height, _size.width, _type, _usage);
|
|
rows_ = _size.height;
|
|
cols_ = _size.width;
|
|
type_ = _type;
|
|
#endif
|
|
}
|
|
|
|
cv::GlBuffer::GlBuffer(InputArray mat_, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)mat_;
|
|
(void)_usage;
|
|
throw_nogl;
|
|
#else
|
|
int kind = mat_.kind();
|
|
Size _size = mat_.size();
|
|
int _type = mat_.type();
|
|
|
|
if (kind == _InputArray::GPU_MAT)
|
|
{
|
|
#ifndef HAVE_CUDA
|
|
throw_nocuda;
|
|
#else
|
|
GpuMat d_mat = mat_.getGpuMat();
|
|
impl_ = new Impl(d_mat.rows, d_mat.cols, d_mat.type(), _usage);
|
|
impl_->copyFrom(d_mat);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Mat mat = mat_.getMat();
|
|
impl_ = new Impl(mat, _usage);
|
|
}
|
|
|
|
rows_ = _size.height;
|
|
cols_ = _size.width;
|
|
type_ = _type;
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::create(int _rows, int _cols, int _type, Usage _usage)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_rows;
|
|
(void)_cols;
|
|
(void)_type;
|
|
(void)_usage;
|
|
throw_nogl;
|
|
#else
|
|
if (rows_ != _rows || cols_ != _cols || type_ != _type || usage_ != _usage)
|
|
{
|
|
impl_ = new Impl(_rows, _cols, _type, _usage);
|
|
rows_ = _rows;
|
|
cols_ = _cols;
|
|
type_ = _type;
|
|
usage_ = _usage;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::release()
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_ = Impl::empty();
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::copyFrom(InputArray mat_)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)mat_;
|
|
throw_nogl;
|
|
#else
|
|
int kind = mat_.kind();
|
|
Size _size = mat_.size();
|
|
int _type = mat_.type();
|
|
|
|
create(_size, _type);
|
|
|
|
switch (kind)
|
|
{
|
|
case _InputArray::OPENGL_BUFFER:
|
|
{
|
|
GlBuffer buf = mat_.getGlBuffer();
|
|
*this = buf;
|
|
break;
|
|
}
|
|
case _InputArray::GPU_MAT:
|
|
{
|
|
#ifndef HAVE_CUDA
|
|
throw_nocuda;
|
|
#else
|
|
GpuMat d_mat = mat_.getGpuMat();
|
|
impl_->copyFrom(d_mat);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Mat mat = mat_.getMat();
|
|
impl_->copyFrom(mat, usage_);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::bind() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_->bind(usage_);
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::unbind() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_->unbind(usage_);
|
|
#endif
|
|
}
|
|
|
|
Mat cv::GlBuffer::mapHost()
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
return Mat();
|
|
#else
|
|
return impl_->mapHost(rows_, cols_, type_, usage_);
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::unmapHost()
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_->unmapHost(usage_);
|
|
#endif
|
|
}
|
|
|
|
GpuMat cv::GlBuffer::mapDevice()
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
return GpuMat();
|
|
#else
|
|
#ifndef HAVE_CUDA
|
|
throw_nocuda;
|
|
return GpuMat();
|
|
#else
|
|
return impl_->mapDevice(rows_, cols_, type_);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void cv::GlBuffer::unmapDevice()
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
#ifndef HAVE_CUDA
|
|
throw_nocuda;
|
|
#else
|
|
impl_->unmapDevice();
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
template <> void cv::Ptr<cv::GlBuffer::Impl>::delete_obj()
|
|
{
|
|
if (obj) delete obj;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// GlTexture
|
|
|
|
#ifndef HAVE_OPENGL
|
|
|
|
class cv::GlTexture::Impl
|
|
{
|
|
};
|
|
|
|
#else
|
|
|
|
class cv::GlTexture::Impl
|
|
{
|
|
public:
|
|
static const Ptr<Impl> empty();
|
|
|
|
Impl(int rows, int cols, int type);
|
|
|
|
Impl(const Mat& mat, bool bgra);
|
|
Impl(const GlBuffer& buf, bool bgra);
|
|
|
|
~Impl();
|
|
|
|
void copyFrom(const Mat& mat, bool bgra);
|
|
void copyFrom(const GlBuffer& buf, bool bgra);
|
|
|
|
void bind() const;
|
|
void unbind() const;
|
|
|
|
private:
|
|
Impl();
|
|
|
|
GLuint tex_;
|
|
};
|
|
|
|
inline const Ptr<cv::GlTexture::Impl> cv::GlTexture::Impl::empty()
|
|
{
|
|
static Ptr<Impl> p(new Impl);
|
|
return p;
|
|
}
|
|
|
|
inline cv::GlTexture::Impl::Impl() : tex_(0)
|
|
{
|
|
}
|
|
|
|
cv::GlTexture::Impl::Impl(int rows, int cols, int type) : tex_(0)
|
|
{
|
|
if (!glFuncTab()->isGlContextInitialized())
|
|
throw_nogl;
|
|
|
|
int depth = CV_MAT_DEPTH(type);
|
|
int cn = CV_MAT_CN(type);
|
|
|
|
CV_DbgAssert(rows > 0 && cols > 0);
|
|
CV_Assert(cn == 1 || cn == 3 || cn == 4);
|
|
CV_Assert(depth >= 0 && depth <= CV_32F);
|
|
|
|
glGenTextures(1, &tex_);
|
|
CV_CheckGlError();
|
|
CV_Assert(tex_ != 0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex_);
|
|
CV_CheckGlError();
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
CV_CheckGlError();
|
|
|
|
GLenum format = cn == 1 ? GL_LUMINANCE : cn == 3 ? GL_BGR : GL_BGRA;
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
CV_CheckGlError();
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, cn, cols, rows, 0, format, gl_types[depth], 0);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
cv::GlTexture::Impl::Impl(const Mat& mat, bool bgra) : tex_(0)
|
|
{
|
|
if (!glFuncTab()->isGlContextInitialized())
|
|
throw_nogl;
|
|
|
|
int depth = mat.depth();
|
|
int cn = mat.channels();
|
|
|
|
CV_DbgAssert(mat.rows > 0 && mat.cols > 0);
|
|
CV_Assert(cn == 1 || cn == 3 || cn == 4);
|
|
CV_Assert(depth >= 0 && depth <= CV_32F);
|
|
CV_Assert(mat.isContinuous());
|
|
|
|
glGenTextures(1, &tex_);
|
|
CV_CheckGlError();
|
|
CV_Assert(tex_ != 0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex_);
|
|
CV_CheckGlError();
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
CV_CheckGlError();
|
|
|
|
GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
CV_CheckGlError();
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, cn, mat.cols, mat.rows, 0, format, gl_types[depth], mat.data);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
cv::GlTexture::Impl::Impl(const GlBuffer& buf, bool bgra) : tex_(0)
|
|
{
|
|
if (!glFuncTab()->isGlContextInitialized())
|
|
throw_nogl;
|
|
|
|
int depth = buf.depth();
|
|
int cn = buf.channels();
|
|
|
|
CV_DbgAssert(buf.rows() > 0 && buf.cols() > 0);
|
|
CV_Assert(cn == 1 || cn == 3 || cn == 4);
|
|
CV_Assert(depth >= 0 && depth <= CV_32F);
|
|
CV_Assert(buf.usage() == GlBuffer::TEXTURE_BUFFER);
|
|
|
|
glGenTextures(1, &tex_);
|
|
CV_CheckGlError();
|
|
CV_Assert(tex_ != 0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex_);
|
|
CV_CheckGlError();
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
CV_CheckGlError();
|
|
|
|
GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
|
|
|
|
buf.bind();
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
CV_CheckGlError();
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, cn, buf.cols(), buf.rows(), 0, format, gl_types[depth], 0);
|
|
CV_CheckGlError();
|
|
|
|
buf.unbind();
|
|
}
|
|
|
|
inline cv::GlTexture::Impl::~Impl()
|
|
{
|
|
if (tex_)
|
|
glDeleteTextures(1, &tex_);
|
|
}
|
|
|
|
void cv::GlTexture::Impl::copyFrom(const Mat& mat, bool bgra)
|
|
{
|
|
CV_Assert(tex_ != 0);
|
|
|
|
bind();
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
CV_CheckGlError();
|
|
|
|
int cn = mat.channels();
|
|
GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mat.cols, mat.rows, format, gl_types[mat.depth()], mat.data);
|
|
CV_CheckGlError();
|
|
|
|
unbind();
|
|
}
|
|
|
|
void cv::GlTexture::Impl::copyFrom(const GlBuffer& buf, bool bgra)
|
|
{
|
|
CV_Assert(tex_ != 0);
|
|
CV_Assert(buf.usage() == GlBuffer::TEXTURE_BUFFER);
|
|
|
|
bind();
|
|
|
|
buf.bind();
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
CV_CheckGlError();
|
|
|
|
int cn = buf.channels();
|
|
GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, buf.cols(), buf.rows(), format, gl_types[buf.depth()], 0);
|
|
CV_CheckGlError();
|
|
|
|
buf.unbind();
|
|
|
|
unbind();
|
|
}
|
|
|
|
inline void cv::GlTexture::Impl::bind() const
|
|
{
|
|
CV_Assert(tex_ != 0);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
CV_CheckGlError();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex_);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
inline void cv::GlTexture::Impl::unbind() const
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
#endif // HAVE_OPENGL
|
|
|
|
cv::GlTexture::GlTexture() : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_ = Impl::empty();
|
|
#endif
|
|
}
|
|
|
|
cv::GlTexture::GlTexture(int _rows, int _cols, int _type) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_rows;
|
|
(void)_cols;
|
|
(void)_type;
|
|
throw_nogl;
|
|
#else
|
|
impl_ = new Impl(_rows, _cols, _type);
|
|
rows_ = _rows;
|
|
cols_ = _cols;
|
|
type_ = _type;
|
|
#endif
|
|
}
|
|
|
|
cv::GlTexture::GlTexture(Size _size, int _type) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_size;
|
|
(void)_type;
|
|
throw_nogl;
|
|
#else
|
|
impl_ = new Impl(_size.height, _size.width, _type);
|
|
rows_ = _size.height;
|
|
cols_ = _size.width;
|
|
type_ = _type;
|
|
#endif
|
|
}
|
|
|
|
cv::GlTexture::GlTexture(InputArray mat_, bool bgra) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)mat_;
|
|
(void)bgra;
|
|
throw_nogl;
|
|
#else
|
|
int kind = mat_.kind();
|
|
Size _size = mat_.size();
|
|
int _type = mat_.type();
|
|
|
|
switch (kind)
|
|
{
|
|
case _InputArray::OPENGL_BUFFER:
|
|
{
|
|
GlBuffer buf = mat_.getGlBuffer();
|
|
impl_ = new Impl(buf, bgra);
|
|
break;
|
|
}
|
|
case _InputArray::GPU_MAT:
|
|
{
|
|
#ifndef HAVE_CUDA
|
|
throw_nocuda;
|
|
#else
|
|
GpuMat d_mat = mat_.getGpuMat();
|
|
GlBuffer buf(d_mat, GlBuffer::TEXTURE_BUFFER);
|
|
impl_ = new Impl(buf, bgra);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Mat mat = mat_.getMat();
|
|
impl_ = new Impl(mat, bgra);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rows_ = _size.height;
|
|
cols_ = _size.width;
|
|
type_ = _type;
|
|
#endif
|
|
}
|
|
|
|
void cv::GlTexture::create(int _rows, int _cols, int _type)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)_rows;
|
|
(void)_cols;
|
|
(void)_type;
|
|
throw_nogl;
|
|
#else
|
|
if (rows_ != _rows || cols_ != _cols || type_ != _type)
|
|
{
|
|
impl_ = new Impl(_rows, _cols, _type);
|
|
rows_ = _rows;
|
|
cols_ = _cols;
|
|
type_ = _type;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void cv::GlTexture::release()
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_ = Impl::empty();
|
|
#endif
|
|
}
|
|
|
|
void cv::GlTexture::copyFrom(InputArray mat_, bool bgra)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)mat_;
|
|
(void)bgra;
|
|
throw_nogl;
|
|
#else
|
|
int kind = mat_.kind();
|
|
Size _size = mat_.size();
|
|
int _type = mat_.type();
|
|
|
|
create(_size, _type);
|
|
|
|
switch(kind)
|
|
{
|
|
case _InputArray::OPENGL_TEXTURE:
|
|
{
|
|
GlTexture tex = mat_.getGlTexture();
|
|
*this = tex;
|
|
break;
|
|
}
|
|
case _InputArray::OPENGL_BUFFER:
|
|
{
|
|
GlBuffer buf = mat_.getGlBuffer();
|
|
impl_->copyFrom(buf, bgra);
|
|
break;
|
|
}
|
|
case _InputArray::GPU_MAT:
|
|
{
|
|
#ifndef HAVE_CUDA
|
|
throw_nocuda;
|
|
#else
|
|
GpuMat d_mat = mat_.getGpuMat();
|
|
buf_.copyFrom(d_mat);
|
|
impl_->copyFrom(buf_, bgra);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Mat mat = mat_.getMat();
|
|
impl_->copyFrom(mat, bgra);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void cv::GlTexture::bind() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_->bind();
|
|
#endif
|
|
}
|
|
|
|
void cv::GlTexture::unbind() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
impl_->unbind();
|
|
#endif
|
|
}
|
|
|
|
template <> void cv::Ptr<cv::GlTexture::Impl>::delete_obj()
|
|
{
|
|
if (obj) delete obj;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// GlArrays
|
|
|
|
void cv::GlArrays::setVertexArray(InputArray vertex)
|
|
{
|
|
int cn = vertex.channels();
|
|
int depth = vertex.depth();
|
|
|
|
CV_Assert(cn == 2 || cn == 3 || cn == 4);
|
|
CV_Assert(depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F);
|
|
|
|
vertex_.copyFrom(vertex);
|
|
}
|
|
|
|
void cv::GlArrays::setColorArray(InputArray color, bool bgra)
|
|
{
|
|
int cn = color.channels();
|
|
|
|
CV_Assert((cn == 3 && !bgra) || cn == 4);
|
|
|
|
color_.copyFrom(color);
|
|
bgra_ = bgra;
|
|
}
|
|
|
|
void cv::GlArrays::setNormalArray(InputArray normal)
|
|
{
|
|
int cn = normal.channels();
|
|
int depth = normal.depth();
|
|
|
|
CV_Assert(cn == 3);
|
|
CV_Assert(depth == CV_8S || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F);
|
|
|
|
normal_.copyFrom(normal);
|
|
}
|
|
|
|
void cv::GlArrays::setTexCoordArray(InputArray texCoord)
|
|
{
|
|
int cn = texCoord.channels();
|
|
int depth = texCoord.depth();
|
|
|
|
CV_Assert(cn >= 1 && cn <= 4);
|
|
CV_Assert(depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F);
|
|
|
|
texCoord_.copyFrom(texCoord);
|
|
}
|
|
|
|
void cv::GlArrays::bind() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
CV_DbgAssert(texCoord_.empty() || texCoord_.size().area() == vertex_.size().area());
|
|
CV_DbgAssert(normal_.empty() || normal_.size().area() == vertex_.size().area());
|
|
CV_DbgAssert(color_.empty() || color_.size().area() == vertex_.size().area());
|
|
|
|
if (!texCoord_.empty())
|
|
{
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
CV_CheckGlError();
|
|
|
|
texCoord_.bind();
|
|
|
|
glTexCoordPointer(texCoord_.channels(), gl_types[texCoord_.depth()], 0, 0);
|
|
CV_CheckGlError();
|
|
|
|
texCoord_.unbind();
|
|
}
|
|
|
|
if (!normal_.empty())
|
|
{
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
CV_CheckGlError();
|
|
|
|
normal_.bind();
|
|
|
|
glNormalPointer(gl_types[normal_.depth()], 0, 0);
|
|
CV_CheckGlError();
|
|
|
|
normal_.unbind();
|
|
}
|
|
|
|
if (!color_.empty())
|
|
{
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
CV_CheckGlError();
|
|
|
|
color_.bind();
|
|
|
|
int cn = color_.channels();
|
|
int format = cn == 3 ? cn : (bgra_ ? GL_BGRA : 4);
|
|
|
|
glColorPointer(format, gl_types[color_.depth()], 0, 0);
|
|
CV_CheckGlError();
|
|
|
|
color_.unbind();
|
|
}
|
|
|
|
if (!vertex_.empty())
|
|
{
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
CV_CheckGlError();
|
|
|
|
vertex_.bind();
|
|
|
|
glVertexPointer(vertex_.channels(), gl_types[vertex_.depth()], 0, 0);
|
|
CV_CheckGlError();
|
|
|
|
vertex_.unbind();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void cv::GlArrays::unbind() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
if (!texCoord_.empty())
|
|
{
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
if (!normal_.empty())
|
|
{
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
if (!color_.empty())
|
|
{
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
CV_CheckGlError();
|
|
}
|
|
|
|
if (!vertex_.empty())
|
|
{
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
CV_CheckGlError();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// GlFont
|
|
|
|
cv::GlFont::GlFont(const string& _family, int _height, Weight _weight, Style _style)
|
|
: family_(_family), height_(_height), weight_(_weight), style_(_style), base_(0)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
base_ = glGenLists(256);
|
|
CV_CheckGlError();
|
|
|
|
glFuncTab()->generateBitmapFont(family_, height_, weight_, (style_ & STYLE_ITALIC) != 0, (style_ & STYLE_UNDERLINE) != 0, 0, 256, base_);
|
|
#endif
|
|
}
|
|
|
|
void cv::GlFont::draw(const char* str, size_t len) const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)str;
|
|
(void)len;
|
|
throw_nogl;
|
|
#else
|
|
if (base_ && len > 0)
|
|
{
|
|
glPushAttrib(GL_LIST_BIT);
|
|
glListBase(base_);
|
|
|
|
glCallLists(static_cast<GLsizei>(len), GL_UNSIGNED_BYTE, str);
|
|
|
|
glPopAttrib();
|
|
|
|
CV_CheckGlError();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class FontCompare : public unary_function<Ptr<GlFont>, bool>
|
|
{
|
|
public:
|
|
inline FontCompare(const string& family, int height, GlFont::Weight weight, GlFont::Style style)
|
|
: family_(family), height_(height), weight_(weight), style_(style)
|
|
{
|
|
}
|
|
|
|
bool operator ()(const cv::Ptr<GlFont>& font)
|
|
{
|
|
return font->family() == family_ && font->height() == height_ && font->weight() == weight_ && font->style() == style_;
|
|
}
|
|
|
|
private:
|
|
string family_;
|
|
int height_;
|
|
GlFont::Weight weight_;
|
|
GlFont::Style style_;
|
|
};
|
|
}
|
|
|
|
Ptr<GlFont> cv::GlFont::get(const std::string& family, int height, Weight weight, Style style)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)family;
|
|
(void)height;
|
|
(void)weight;
|
|
(void)style;
|
|
throw_nogl;
|
|
return Ptr<GlFont>();
|
|
#else
|
|
static vector< Ptr<GlFont> > fonts;
|
|
fonts.reserve(10);
|
|
|
|
vector< Ptr<GlFont> >::iterator fontIt = find_if(fonts.begin(), fonts.end(), FontCompare(family, height, weight, style));
|
|
|
|
if (fontIt == fonts.end())
|
|
{
|
|
fonts.push_back(new GlFont(family, height, weight, style));
|
|
|
|
fontIt = fonts.end() - 1;
|
|
}
|
|
|
|
return *fontIt;
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Rendering
|
|
|
|
void cv::render(const GlTexture& tex, Rect_<double> wndRect, Rect_<double> texRect)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)tex;
|
|
(void)wndRect;
|
|
(void)texRect;
|
|
throw_nogl;
|
|
#else
|
|
if (!tex.empty())
|
|
{
|
|
tex.bind();
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2d(texRect.x, texRect.y);
|
|
glVertex2d(wndRect.x, wndRect.y);
|
|
|
|
glTexCoord2d(texRect.x, texRect.y + texRect.height);
|
|
glVertex2d(wndRect.x, (wndRect.y + wndRect.height));
|
|
|
|
glTexCoord2d(texRect.x + texRect.width, texRect.y + texRect.height);
|
|
glVertex2d(wndRect.x + wndRect.width, (wndRect.y + wndRect.height));
|
|
|
|
glTexCoord2d(texRect.x + texRect.width, texRect.y);
|
|
glVertex2d(wndRect.x + wndRect.width, wndRect.y);
|
|
glEnd();
|
|
|
|
CV_CheckGlError();
|
|
|
|
tex.unbind();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void cv::render(const GlArrays& arr, int mode, Scalar color)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)arr;
|
|
(void)mode;
|
|
(void)color;
|
|
throw_nogl;
|
|
#else
|
|
glColor3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
|
|
|
|
arr.bind();
|
|
|
|
glDrawArrays(mode, 0, arr.size().area());
|
|
|
|
arr.unbind();
|
|
#endif
|
|
}
|
|
|
|
void cv::render(const string& str, const Ptr<GlFont>& font, Scalar color, Point2d pos)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)str;
|
|
(void)font;
|
|
(void)color;
|
|
(void)pos;
|
|
throw_nogl;
|
|
#else
|
|
glPushAttrib(GL_DEPTH_BUFFER_BIT);
|
|
|
|
GLint viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glColor3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
|
|
|
|
glRasterPos2d(2.0 * (viewport[0] + pos.x) / viewport[2] - 1.0, 1.0 - 2.0 * (viewport[1] + pos.y + font->height()) / viewport[3]);
|
|
|
|
font->draw(str.c_str(), str.length());
|
|
|
|
glPopAttrib();
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// GlCamera
|
|
|
|
cv::GlCamera::GlCamera() :
|
|
eye_(0.0, 0.0, -5.0), center_(0.0, 0.0, 0.0), up_(0.0, 1.0, 0.0),
|
|
pos_(0.0, 0.0, -5.0), yaw_(0.0), pitch_(0.0), roll_(0.0),
|
|
useLookAtParams_(false),
|
|
|
|
scale_(1.0, 1.0, 1.0),
|
|
|
|
projectionMatrix_(),
|
|
fov_(45.0), aspect_(0.0),
|
|
left_(0.0), right_(1.0), bottom_(1.0), top_(0.0),
|
|
zNear_(-1.0), zFar_(1.0),
|
|
perspectiveProjection_(false)
|
|
{
|
|
}
|
|
|
|
void cv::GlCamera::lookAt(Point3d eye, Point3d center, Point3d up)
|
|
{
|
|
eye_ = eye;
|
|
center_ = center;
|
|
up_ = up;
|
|
useLookAtParams_ = true;
|
|
}
|
|
|
|
void cv::GlCamera::setCameraPos(Point3d pos, double yaw, double pitch, double roll)
|
|
{
|
|
pos_ = pos;
|
|
yaw_ = yaw;
|
|
pitch_ = pitch;
|
|
roll_ = roll;
|
|
useLookAtParams_ = false;
|
|
}
|
|
|
|
void cv::GlCamera::setScale(Point3d scale)
|
|
{
|
|
scale_ = scale;
|
|
}
|
|
|
|
void cv::GlCamera::setProjectionMatrix(const Mat& projectionMatrix, bool transpose)
|
|
{
|
|
CV_Assert(projectionMatrix.type() == CV_32F || projectionMatrix.type() == CV_64F);
|
|
CV_Assert(projectionMatrix.cols == 4 && projectionMatrix.rows == 4);
|
|
|
|
projectionMatrix_ = transpose ? projectionMatrix.t() : projectionMatrix;
|
|
}
|
|
|
|
void cv::GlCamera::setPerspectiveProjection(double fov, double aspect, double zNear, double zFar)
|
|
{
|
|
fov_ = fov;
|
|
aspect_ = aspect;
|
|
zNear_ = zNear;
|
|
zFar_ = zFar;
|
|
|
|
projectionMatrix_.release();
|
|
perspectiveProjection_ = true;
|
|
}
|
|
|
|
void cv::GlCamera::setOrthoProjection(double left, double right, double bottom, double top, double zNear, double zFar)
|
|
{
|
|
left_ = left;
|
|
right_ = right;
|
|
bottom_ = bottom;
|
|
top_ = top;
|
|
zNear_ = zNear;
|
|
zFar_ = zFar;
|
|
|
|
projectionMatrix_.release();
|
|
perspectiveProjection_ = false;
|
|
}
|
|
|
|
void cv::GlCamera::setupProjectionMatrix() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
if (projectionMatrix_.empty())
|
|
{
|
|
if (perspectiveProjection_)
|
|
gluPerspective(fov_, aspect_, zNear_, zFar_);
|
|
else
|
|
glOrtho(left_, right_, bottom_, top_, zNear_, zFar_);
|
|
}
|
|
else
|
|
{
|
|
if (projectionMatrix_.type() == CV_32F)
|
|
glLoadMatrixf(projectionMatrix_.ptr<float>());
|
|
else
|
|
glLoadMatrixd(projectionMatrix_.ptr<double>());
|
|
}
|
|
|
|
CV_CheckGlError();
|
|
#endif
|
|
}
|
|
|
|
void cv::GlCamera::setupModelViewMatrix() const
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
throw_nogl;
|
|
#else
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
if (useLookAtParams_)
|
|
gluLookAt(eye_.x, eye_.y, eye_.z, center_.x, center_.y, center_.z, up_.x, up_.y, up_.z);
|
|
else
|
|
{
|
|
glRotated(-yaw_, 0.0, 1.0, 0.0);
|
|
glRotated(-pitch_, 1.0, 0.0, 0.0);
|
|
glRotated(-roll_, 0.0, 0.0, 1.0);
|
|
glTranslated(-pos_.x, -pos_.y, -pos_.z);
|
|
}
|
|
|
|
glScaled(scale_.x, scale_.y, scale_.z);
|
|
|
|
CV_CheckGlError();
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Error handling
|
|
|
|
bool icvCheckGlError(const char* file, const int line, const char* func)
|
|
{
|
|
#ifndef HAVE_OPENGL
|
|
(void)file;
|
|
(void)line;
|
|
(void)func;
|
|
return true;
|
|
#else
|
|
GLenum err = glGetError();
|
|
|
|
if (err != GL_NO_ERROR)
|
|
{
|
|
const char* msg;
|
|
|
|
switch (err)
|
|
{
|
|
case GL_INVALID_ENUM:
|
|
msg = "An unacceptable value is specified for an enumerated argument";
|
|
break;
|
|
case GL_INVALID_VALUE:
|
|
msg = "A numeric argument is out of range";
|
|
break;
|
|
case GL_INVALID_OPERATION:
|
|
msg = "The specified operation is not allowed in the current state";
|
|
break;
|
|
case GL_STACK_OVERFLOW:
|
|
msg = "This command would cause a stack overflow";
|
|
break;
|
|
case GL_STACK_UNDERFLOW:
|
|
msg = "This command would cause a stack underflow";
|
|
break;
|
|
case GL_OUT_OF_MEMORY:
|
|
msg = "There is not enough memory left to execute the command";
|
|
break;
|
|
default:
|
|
msg = "Unknown error";
|
|
};
|
|
|
|
cvError(CV_OpenGlApiCallError, func, msg, file, line);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
#endif
|
|
}
|