mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
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.
1589 lines
39 KiB
1589 lines
39 KiB
/*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 |
|
}
|
|
|