3cbec2c01a202193bec590239dac0cb505210c1e
[profile/ivi/opencv.git] / modules / core / src / opengl_interop.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "precomp.hpp"
44 #include <iostream>
45 #include "opencv2/core/opengl_interop.hpp"
46 #include "opencv2/core/gpumat.hpp"
47
48 #if defined WIN32 || defined _WIN32 || defined WINCE
49 #include <windows.h>
50 #undef small
51 #undef min
52 #undef max
53 #undef abs
54 #endif
55
56 #ifdef HAVE_OPENGL
57     #ifdef __APPLE__
58         #include <OpenGL/gl.h>
59         #include <OpenGL/glu.h>
60     #else
61         #include <GL/gl.h>
62         #include <GL/glu.h>
63     #endif
64
65     #ifdef HAVE_CUDA
66         #include <cuda_runtime.h>
67         #include <cuda_gl_interop.h>
68     #endif
69 #endif
70
71 using namespace std;
72 using namespace cv;
73 using namespace cv::gpu;
74
75 #ifndef HAVE_OPENGL
76     #define throw_nogl CV_Error(CV_OpenGlNotSupported, "The library is compiled without OpenGL support")
77     #define throw_nocuda CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support")
78 #else
79     #define throw_nogl CV_Error(CV_OpenGlNotSupported, "OpenGL context doesn't exist")
80
81     #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
82         #define throw_nocuda CV_Error(CV_GpuNotSupported, "The library is compiled without CUDA support")
83     #else
84         #if defined(__GNUC__)
85             #define cudaSafeCall(expr)  ___cudaSafeCall(expr, __FILE__, __LINE__, __func__)
86         #else /* defined(__CUDACC__) || defined(__MSVC__) */
87             #define cudaSafeCall(expr)  ___cudaSafeCall(expr, __FILE__, __LINE__)
88         #endif
89
90         namespace
91         {
92             inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "")
93             {
94                 if (cudaSuccess != err)
95                     cv::gpu::error(cudaGetErrorString(err), file, line, func);
96             }
97         }
98     #endif // HAVE_CUDA
99 #endif
100
101 namespace
102 {
103     class EmptyGlFuncTab : public CvOpenGlFuncTab
104     {
105     public:
106         void genBuffers(int, unsigned int*) const { throw_nogl; }
107         void deleteBuffers(int, const unsigned int*) const { throw_nogl; }
108
109         void bufferData(unsigned int, ptrdiff_t, const void*, unsigned int) const { throw_nogl; }
110         void bufferSubData(unsigned int, ptrdiff_t, ptrdiff_t, const void*) const { throw_nogl; }
111
112         void bindBuffer(unsigned int, unsigned int) const { throw_nogl; }
113
114         void* mapBuffer(unsigned int, unsigned int) const { throw_nogl; return 0; }
115         void unmapBuffer(unsigned int) const { throw_nogl; }
116
117         void generateBitmapFont(const std::string&, int, int, bool, bool, int, int, int) const { throw_nogl; }
118
119         bool isGlContextInitialized() const { return false; }
120     };
121
122     const CvOpenGlFuncTab* g_glFuncTab = 0;
123
124 #if defined HAVE_CUDA || defined HAVE_OPENGL
125     const CvOpenGlFuncTab* glFuncTab()
126     {
127         static EmptyGlFuncTab empty;
128         return g_glFuncTab ? g_glFuncTab : &empty;
129     }
130 #endif
131 }
132
133 CvOpenGlFuncTab::~CvOpenGlFuncTab()
134 {
135     if (g_glFuncTab == this)
136         g_glFuncTab = 0;
137 }
138
139 void icvSetOpenGlFuncTab(const CvOpenGlFuncTab* tab)
140 {
141     g_glFuncTab = tab;
142 }
143
144 #ifdef HAVE_OPENGL
145     #ifndef GL_DYNAMIC_DRAW
146         #define GL_DYNAMIC_DRAW 0x88E8
147     #endif
148
149     #ifndef GL_READ_WRITE
150         #define GL_READ_WRITE 0x88BA
151     #endif
152
153     #ifndef GL_BGR
154         #define GL_BGR 0x80E0
155     #endif
156
157     #ifndef GL_BGRA
158         #define GL_BGRA 0x80E1
159     #endif
160
161     namespace
162     {
163         const GLenum gl_types[] = {GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE};
164
165     #ifdef HAVE_CUDA
166         bool g_isCudaGlDeviceInitialized = false;
167     #endif
168     }
169 #endif // HAVE_OPENGL
170
171 void cv::gpu::setGlDevice(int device)
172 {
173 #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
174     (void)device;
175     throw_nocuda;
176 #else
177     #ifndef HAVE_OPENGL
178         (void)device;
179         throw_nogl;
180     #else
181         if (!glFuncTab()->isGlContextInitialized())
182             throw_nogl;
183
184         cudaSafeCall( cudaGLSetGLDevice(device) );
185
186         g_isCudaGlDeviceInitialized = true;
187     #endif
188 #endif
189 }
190
191 ////////////////////////////////////////////////////////////////////////
192 // CudaGlInterop
193
194 #if defined HAVE_CUDA && defined HAVE_OPENGL
195 namespace
196 {
197     class CudaGlInterop
198     {
199     public:
200         CudaGlInterop();
201         ~CudaGlInterop();
202
203         void registerBuffer(unsigned int buffer);
204
205         void copyFrom(const GpuMat& mat, cudaStream_t stream = 0);
206
207         GpuMat map(int rows, int cols, int type, cudaStream_t stream = 0);
208         void unmap(cudaStream_t stream = 0);
209
210     private:
211         cudaGraphicsResource_t resource_;
212     };
213
214     inline CudaGlInterop::CudaGlInterop() : resource_(0)
215     {
216     }
217
218     CudaGlInterop::~CudaGlInterop()
219     {
220         if (resource_)
221         {
222             cudaGraphicsUnregisterResource(resource_);
223             resource_ = 0;
224         }
225     }
226
227     void CudaGlInterop::registerBuffer(unsigned int buffer)
228     {
229         if (!g_isCudaGlDeviceInitialized)
230             cvError(CV_GpuApiCallError, "registerBuffer", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
231
232         cudaGraphicsResource_t resource;
233         cudaSafeCall( cudaGraphicsGLRegisterBuffer(&resource, buffer, cudaGraphicsMapFlagsNone) );
234
235         resource_ = resource;
236     }
237
238     void CudaGlInterop::copyFrom(const GpuMat& mat, cudaStream_t stream)
239     {
240         CV_Assert(resource_ != 0);
241
242         cudaSafeCall( cudaGraphicsMapResources(1, &resource_, stream) );
243
244         void* dst_ptr;
245         size_t num_bytes;
246         cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&dst_ptr, &num_bytes, resource_) );
247
248         const void* src_ptr = mat.ptr();
249         size_t widthBytes = mat.cols * mat.elemSize();
250
251         CV_Assert(widthBytes * mat.rows <= num_bytes);
252
253         if (stream == 0)
254             cudaSafeCall( cudaMemcpy2D(dst_ptr, widthBytes, src_ptr, mat.step, widthBytes, mat.rows, cudaMemcpyDeviceToDevice) );
255         else
256             cudaSafeCall( cudaMemcpy2DAsync(dst_ptr, widthBytes, src_ptr, mat.step, widthBytes, mat.rows, cudaMemcpyDeviceToDevice, stream) );
257
258         cudaGraphicsUnmapResources(1, &resource_, stream);
259     }
260
261     GpuMat CudaGlInterop::map(int rows, int cols, int type, cudaStream_t stream)
262     {
263         CV_Assert(resource_ != 0);
264
265         cudaSafeCall( cudaGraphicsMapResources(1, &resource_, stream) );
266
267         void* ptr;
268         size_t num_bytes;
269         cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&ptr, &num_bytes, resource_) );
270
271         CV_Assert( static_cast<size_t>(cols) * CV_ELEM_SIZE(type) * rows <= num_bytes );
272
273         return GpuMat(rows, cols, type, ptr);
274     }
275
276     inline void CudaGlInterop::unmap(cudaStream_t stream)
277     {
278         cudaGraphicsUnmapResources(1, &resource_, stream);
279     }
280 }
281 #endif // HAVE_CUDA && HAVE_OPENGL
282
283 ////////////////////////////////////////////////////////////////////////
284 // GlBuffer
285
286 #ifndef HAVE_OPENGL
287
288 class cv::GlBuffer::Impl
289 {
290 };
291
292 #else
293
294 class cv::GlBuffer::Impl
295 {
296 public:
297     static const Ptr<Impl>& empty();
298
299     Impl(int rows, int cols, int type, unsigned int target);
300     Impl(const Mat& m, unsigned int target);
301     ~Impl();
302
303     void copyFrom(const Mat& m, unsigned int target);
304
305 #ifdef HAVE_CUDA
306     void copyFrom(const GpuMat& mat, cudaStream_t stream = 0);
307 #endif
308
309     void bind(unsigned int target) const;
310     void unbind(unsigned int target) const;
311
312     Mat mapHost(int rows, int cols, int type, unsigned int target);
313     void unmapHost(unsigned int target);
314
315 #ifdef HAVE_CUDA
316     GpuMat mapDevice(int rows, int cols, int type, cudaStream_t stream = 0);
317     void unmapDevice(cudaStream_t stream = 0);
318 #endif
319
320 private:
321     Impl();
322
323     unsigned int buffer_;
324
325 #ifdef HAVE_CUDA
326     CudaGlInterop cudaGlInterop_;
327 #endif
328 };
329
330 inline const Ptr<cv::GlBuffer::Impl>& cv::GlBuffer::Impl::empty()
331 {
332     static Ptr<Impl> p(new Impl);
333     return p;
334 }
335
336 inline cv::GlBuffer::Impl::Impl() : buffer_(0)
337 {
338 }
339
340 cv::GlBuffer::Impl::Impl(int rows, int cols, int type, unsigned int target) : buffer_(0)
341 {
342     if (!glFuncTab()->isGlContextInitialized())
343         throw_nogl;
344
345     CV_DbgAssert(rows > 0 && cols > 0);
346     CV_DbgAssert(CV_MAT_DEPTH(type) >= 0 && CV_MAT_DEPTH(type) <= CV_64F);
347
348     glFuncTab()->genBuffers(1, &buffer_);
349     CV_CheckGlError();
350     CV_Assert(buffer_ != 0);
351
352     size_t size = rows * cols * CV_ELEM_SIZE(type);
353
354     glFuncTab()->bindBuffer(target, buffer_);
355     CV_CheckGlError();
356
357     glFuncTab()->bufferData(target, size, 0, GL_DYNAMIC_DRAW);
358     CV_CheckGlError();
359
360     glFuncTab()->bindBuffer(target, 0);
361
362 #ifdef HAVE_CUDA
363     if (g_isCudaGlDeviceInitialized)
364         cudaGlInterop_.registerBuffer(buffer_);
365 #endif
366 }
367
368 cv::GlBuffer::Impl::Impl(const Mat& m, unsigned int target) : buffer_(0)
369 {
370     if (!glFuncTab()->isGlContextInitialized())
371         throw_nogl;
372
373     CV_DbgAssert(m.rows > 0 && m.cols > 0);
374     CV_DbgAssert(m.depth() >= 0 && m.depth() <= CV_64F);
375     CV_Assert(m.isContinuous());
376
377     glFuncTab()->genBuffers(1, &buffer_);
378     CV_CheckGlError();
379     CV_Assert(buffer_ != 0);
380
381     size_t size = m.rows * m.cols * m.elemSize();
382
383     glFuncTab()->bindBuffer(target, buffer_);
384     CV_CheckGlError();
385
386     glFuncTab()->bufferData(target, size, m.data, GL_DYNAMIC_DRAW);
387     CV_CheckGlError();
388
389     glFuncTab()->bindBuffer(target, 0);
390
391 #ifdef HAVE_CUDA
392     if (g_isCudaGlDeviceInitialized)
393         cudaGlInterop_.registerBuffer(buffer_);
394 #endif
395 }
396
397 cv::GlBuffer::Impl::~Impl()
398 {
399     try
400     {
401         if (buffer_)
402             glFuncTab()->deleteBuffers(1, &buffer_);
403     }
404 #ifdef _DEBUG
405     catch(const exception& e)
406     {
407         cerr << e.what() << endl;
408     }
409 #endif
410     catch(...)
411     {
412     }
413 }
414
415 void cv::GlBuffer::Impl::copyFrom(const Mat& m, unsigned int target)
416 {
417     CV_Assert(buffer_ != 0);
418
419     CV_Assert(m.isContinuous());
420
421     bind(target);
422
423     size_t size = m.rows * m.cols * m.elemSize();
424
425     glFuncTab()->bufferSubData(target, 0, size, m.data);
426     CV_CheckGlError();
427
428     unbind(target);
429 }
430
431 #ifdef HAVE_CUDA
432
433 void cv::GlBuffer::Impl::copyFrom(const GpuMat& mat, cudaStream_t stream)
434 {
435     if (!g_isCudaGlDeviceInitialized)
436         cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
437
438     CV_Assert(buffer_ != 0);
439
440     cudaGlInterop_.copyFrom(mat, stream);
441 }
442
443 #endif // HAVE_CUDA
444
445 inline void cv::GlBuffer::Impl::bind(unsigned int target) const
446 {
447     CV_Assert(buffer_ != 0);
448
449     glFuncTab()->bindBuffer(target, buffer_);
450     CV_CheckGlError();
451 }
452
453 inline void cv::GlBuffer::Impl::unbind(unsigned int target) const
454 {
455     glFuncTab()->bindBuffer(target, 0);
456 }
457
458 inline Mat cv::GlBuffer::Impl::mapHost(int rows, int cols, int type, unsigned int target)
459 {
460     void* ptr = glFuncTab()->mapBuffer(target, GL_READ_WRITE);
461     CV_CheckGlError();
462
463     return Mat(rows, cols, type, ptr);
464 }
465
466 inline void cv::GlBuffer::Impl::unmapHost(unsigned int target)
467 {
468     glFuncTab()->unmapBuffer(target);
469 }
470
471 #ifdef HAVE_CUDA
472
473 inline GpuMat cv::GlBuffer::Impl::mapDevice(int rows, int cols, int type, cudaStream_t stream)
474 {
475     if (!g_isCudaGlDeviceInitialized)
476         cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
477
478     CV_Assert(buffer_ != 0);
479
480     return cudaGlInterop_.map(rows, cols, type, stream);
481 }
482
483 inline void cv::GlBuffer::Impl::unmapDevice(cudaStream_t stream)
484 {
485     if (!g_isCudaGlDeviceInitialized)
486         cvError(CV_GpuApiCallError, "copyFrom", "cuda GL device wasn't initialized, call setGlDevice", __FILE__, __LINE__);
487
488     cudaGlInterop_.unmap(stream);
489 }
490
491 #endif // HAVE_CUDA
492
493 #endif // HAVE_OPENGL
494
495 cv::GlBuffer::GlBuffer(Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
496 {
497 #ifndef HAVE_OPENGL
498     (void)_usage;
499     throw_nogl;
500 #else
501     impl_ = Impl::empty();
502 #endif
503 }
504
505 cv::GlBuffer::GlBuffer(int _rows, int _cols, int _type, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
506 {
507 #ifndef HAVE_OPENGL
508     (void)_rows;
509     (void)_cols;
510     (void)_type;
511     (void)_usage;
512     throw_nogl;
513 #else
514     impl_ = new Impl(_rows, _cols, _type, _usage);
515     rows_ = _rows;
516     cols_ = _cols;
517     type_ = _type;
518 #endif
519 }
520
521 cv::GlBuffer::GlBuffer(Size _size, int _type, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
522 {
523 #ifndef HAVE_OPENGL
524     (void)_size;
525     (void)_type;
526     (void)_usage;
527     throw_nogl;
528 #else
529     impl_ = new Impl(_size.height, _size.width, _type, _usage);
530     rows_ = _size.height;
531     cols_ = _size.width;
532     type_ = _type;
533 #endif
534 }
535
536 cv::GlBuffer::GlBuffer(InputArray mat_, Usage _usage) : rows_(0), cols_(0), type_(0), usage_(_usage)
537 {
538 #ifndef HAVE_OPENGL
539     (void)mat_;
540     (void)_usage;
541     throw_nogl;
542 #else
543     int kind = mat_.kind();
544     Size _size = mat_.size();
545     int _type = mat_.type();
546
547     if (kind == _InputArray::GPU_MAT)
548     {
549         #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
550             throw_nocuda;
551         #else
552             GpuMat d_mat = mat_.getGpuMat();
553             impl_ = new Impl(d_mat.rows, d_mat.cols, d_mat.type(), _usage);
554             impl_->copyFrom(d_mat);
555         #endif
556     }
557     else
558     {
559         Mat mat = mat_.getMat();
560         impl_ = new Impl(mat, _usage);
561     }
562
563     rows_ = _size.height;
564     cols_ = _size.width;
565     type_ = _type;
566 #endif
567 }
568
569 void cv::GlBuffer::create(int _rows, int _cols, int _type, Usage _usage)
570 {
571 #ifndef HAVE_OPENGL
572     (void)_rows;
573     (void)_cols;
574     (void)_type;
575     (void)_usage;
576     throw_nogl;
577 #else
578     if (rows_ != _rows || cols_ != _cols || type_ != _type || usage_ != _usage)
579     {
580         impl_ = new Impl(_rows, _cols, _type, _usage);
581         rows_ = _rows;
582         cols_ = _cols;
583         type_ = _type;
584         usage_ = _usage;
585     }
586 #endif
587 }
588
589 void cv::GlBuffer::release()
590 {
591 #ifndef HAVE_OPENGL
592     throw_nogl;
593 #else
594     impl_ = Impl::empty();
595 #endif
596 }
597
598 void cv::GlBuffer::copyFrom(InputArray mat_)
599 {
600 #ifndef HAVE_OPENGL
601     (void)mat_;
602     throw_nogl;
603 #else
604     int kind = mat_.kind();
605     Size _size = mat_.size();
606     int _type = mat_.type();
607
608     create(_size, _type);
609
610     switch (kind)
611     {
612     case _InputArray::OPENGL_BUFFER:
613         {
614             GlBuffer buf = mat_.getGlBuffer();
615             *this = buf;
616             break;
617         }
618     case _InputArray::GPU_MAT:
619         {
620             #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
621                 throw_nocuda;
622             #else
623                 GpuMat d_mat = mat_.getGpuMat();
624                 impl_->copyFrom(d_mat);
625             #endif
626
627             break;
628         }
629     default:
630         {
631             Mat mat = mat_.getMat();
632             impl_->copyFrom(mat, usage_);
633         }
634     }
635 #endif
636 }
637
638 void cv::GlBuffer::bind() const
639 {
640 #ifndef HAVE_OPENGL
641     throw_nogl;
642 #else
643     impl_->bind(usage_);
644 #endif
645 }
646
647 void cv::GlBuffer::unbind() const
648 {
649 #ifndef HAVE_OPENGL
650     throw_nogl;
651 #else
652     impl_->unbind(usage_);
653 #endif
654 }
655
656 Mat cv::GlBuffer::mapHost()
657 {
658 #ifndef HAVE_OPENGL
659     throw_nogl;
660     return Mat();
661 #else
662     return impl_->mapHost(rows_, cols_, type_, usage_);
663 #endif
664 }
665
666 void cv::GlBuffer::unmapHost()
667 {
668 #ifndef HAVE_OPENGL
669     throw_nogl;
670 #else
671     impl_->unmapHost(usage_);
672 #endif
673 }
674
675 GpuMat cv::GlBuffer::mapDevice()
676 {
677 #ifndef HAVE_OPENGL
678     throw_nogl;
679     return GpuMat();
680 #else
681     #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
682         throw_nocuda;
683         return GpuMat();
684     #else
685         return impl_->mapDevice(rows_, cols_, type_);
686     #endif
687 #endif
688 }
689
690 void cv::GlBuffer::unmapDevice()
691 {
692 #ifndef HAVE_OPENGL
693     throw_nogl;
694 #else
695     #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
696         throw_nocuda;
697     #else
698         impl_->unmapDevice();
699     #endif
700 #endif
701 }
702
703 template <> void cv::Ptr<cv::GlBuffer::Impl>::delete_obj()
704 {
705     if (obj) delete obj;
706 }
707
708 //////////////////////////////////////////////////////////////////////////////////////////
709 // GlTexture
710
711 #ifndef HAVE_OPENGL
712
713 class cv::GlTexture::Impl
714 {
715 };
716
717 #else
718
719 class cv::GlTexture::Impl
720 {
721 public:
722     static const Ptr<Impl> empty();
723
724     Impl(int rows, int cols, int type);
725
726     Impl(const Mat& mat, bool bgra);
727     Impl(const GlBuffer& buf, bool bgra);
728
729     ~Impl();
730
731     void copyFrom(const Mat& mat, bool bgra);
732     void copyFrom(const GlBuffer& buf, bool bgra);
733
734     void bind() const;
735     void unbind() const;
736
737 private:
738     Impl();
739
740     GLuint tex_;
741 };
742
743 inline const Ptr<cv::GlTexture::Impl> cv::GlTexture::Impl::empty()
744 {
745     static Ptr<Impl> p(new Impl);
746     return p;
747 }
748
749 inline cv::GlTexture::Impl::Impl() : tex_(0)
750 {
751 }
752
753 cv::GlTexture::Impl::Impl(int rows, int cols, int type) : tex_(0)
754 {
755     if (!glFuncTab()->isGlContextInitialized())
756         throw_nogl;
757
758     int depth = CV_MAT_DEPTH(type);
759     int cn = CV_MAT_CN(type);
760
761     CV_DbgAssert(rows > 0 && cols > 0);
762     CV_Assert(cn == 1 || cn == 3 || cn == 4);
763     CV_Assert(depth >= 0 && depth <= CV_32F);
764
765     glGenTextures(1, &tex_);
766     CV_CheckGlError();
767     CV_Assert(tex_ != 0);
768
769     glBindTexture(GL_TEXTURE_2D, tex_);
770     CV_CheckGlError();
771
772     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
773     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
774     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
775     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
776     CV_CheckGlError();
777
778     GLenum format = cn == 1 ? GL_LUMINANCE : cn == 3 ? GL_BGR : GL_BGRA;
779
780     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
781     CV_CheckGlError();
782
783     glTexImage2D(GL_TEXTURE_2D, 0, cn, cols, rows, 0, format, gl_types[depth], 0);
784     CV_CheckGlError();
785 }
786
787 cv::GlTexture::Impl::Impl(const Mat& mat, bool bgra) : tex_(0)
788 {
789     if (!glFuncTab()->isGlContextInitialized())
790         throw_nogl;
791
792     int depth = mat.depth();
793     int cn = mat.channels();
794
795     CV_DbgAssert(mat.rows > 0 && mat.cols > 0);
796     CV_Assert(cn == 1 || cn == 3 || cn == 4);
797     CV_Assert(depth >= 0 && depth <= CV_32F);
798     CV_Assert(mat.isContinuous());
799
800     glGenTextures(1, &tex_);
801     CV_CheckGlError();
802     CV_Assert(tex_ != 0);
803
804     glBindTexture(GL_TEXTURE_2D, tex_);
805     CV_CheckGlError();
806
807     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
808     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
809     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
810     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
811     CV_CheckGlError();
812
813     GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
814
815     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
816     CV_CheckGlError();
817
818     glTexImage2D(GL_TEXTURE_2D, 0, cn, mat.cols, mat.rows, 0, format, gl_types[depth], mat.data);
819     CV_CheckGlError();
820 }
821
822 cv::GlTexture::Impl::Impl(const GlBuffer& buf, bool bgra) : tex_(0)
823 {
824     if (!glFuncTab()->isGlContextInitialized())
825         throw_nogl;
826
827     int depth = buf.depth();
828     int cn = buf.channels();
829
830     CV_DbgAssert(buf.rows() > 0 && buf.cols() > 0);
831     CV_Assert(cn == 1 || cn == 3 || cn == 4);
832     CV_Assert(depth >= 0 && depth <= CV_32F);
833     CV_Assert(buf.usage() == GlBuffer::TEXTURE_BUFFER);
834
835     glGenTextures(1, &tex_);
836     CV_CheckGlError();
837     CV_Assert(tex_ != 0);
838
839     glBindTexture(GL_TEXTURE_2D, tex_);
840     CV_CheckGlError();
841
842     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
843     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
844     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
845     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
846     CV_CheckGlError();
847
848     GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
849
850     buf.bind();
851
852     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
853     CV_CheckGlError();
854
855     glTexImage2D(GL_TEXTURE_2D, 0, cn, buf.cols(), buf.rows(), 0, format, gl_types[depth], 0);
856     CV_CheckGlError();
857
858     buf.unbind();
859 }
860
861 inline cv::GlTexture::Impl::~Impl()
862 {
863     if (tex_)
864         glDeleteTextures(1, &tex_);
865 }
866
867 void cv::GlTexture::Impl::copyFrom(const Mat& mat, bool bgra)
868 {
869     CV_Assert(tex_ != 0);
870
871     bind();
872
873     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
874     CV_CheckGlError();
875
876     int cn = mat.channels();
877     GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
878
879     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mat.cols, mat.rows, format, gl_types[mat.depth()], mat.data);
880     CV_CheckGlError();
881
882     unbind();
883 }
884
885 void cv::GlTexture::Impl::copyFrom(const GlBuffer& buf, bool bgra)
886 {
887     CV_Assert(tex_ != 0);
888     CV_Assert(buf.usage() == GlBuffer::TEXTURE_BUFFER);
889
890     bind();
891
892     buf.bind();
893
894     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
895     CV_CheckGlError();
896
897     int cn = buf.channels();
898     GLenum format = cn == 1 ? GL_LUMINANCE : (cn == 3 ? (bgra ? GL_BGR : GL_RGB) : (bgra ? GL_BGRA : GL_RGBA));
899
900     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, buf.cols(), buf.rows(), format, gl_types[buf.depth()], 0);
901     CV_CheckGlError();
902
903     buf.unbind();
904
905     unbind();
906 }
907
908 inline void cv::GlTexture::Impl::bind() const
909 {
910     CV_Assert(tex_ != 0);
911
912     glEnable(GL_TEXTURE_2D);
913     CV_CheckGlError();
914
915     glBindTexture(GL_TEXTURE_2D, tex_);
916     CV_CheckGlError();
917 }
918
919 inline void cv::GlTexture::Impl::unbind() const
920 {
921     glBindTexture(GL_TEXTURE_2D, 0);
922
923     glDisable(GL_TEXTURE_2D);
924 }
925
926 #endif // HAVE_OPENGL
927
928 cv::GlTexture::GlTexture() : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
929 {
930 #ifndef HAVE_OPENGL
931     throw_nogl;
932 #else
933     impl_ = Impl::empty();
934 #endif
935 }
936
937 cv::GlTexture::GlTexture(int _rows, int _cols, int _type) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
938 {
939 #ifndef HAVE_OPENGL
940     (void)_rows;
941     (void)_cols;
942     (void)_type;
943     throw_nogl;
944 #else
945     impl_ = new Impl(_rows, _cols, _type);
946     rows_ = _rows;
947     cols_ = _cols;
948     type_ = _type;
949 #endif
950 }
951
952 cv::GlTexture::GlTexture(Size _size, int _type) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
953 {
954 #ifndef HAVE_OPENGL
955     (void)_size;
956     (void)_type;
957     throw_nogl;
958 #else
959     impl_ = new Impl(_size.height, _size.width, _type);
960     rows_ = _size.height;
961     cols_ = _size.width;
962     type_ = _type;
963 #endif
964 }
965
966 cv::GlTexture::GlTexture(InputArray mat_, bool bgra) : rows_(0), cols_(0), type_(0), buf_(GlBuffer::TEXTURE_BUFFER)
967 {
968 #ifndef HAVE_OPENGL
969     (void)mat_;
970     (void)bgra;
971     throw_nogl;
972 #else
973     int kind = mat_.kind();
974     Size _size = mat_.size();
975     int _type = mat_.type();
976
977     switch (kind)
978     {
979     case _InputArray::OPENGL_BUFFER:
980         {
981             GlBuffer buf = mat_.getGlBuffer();
982             impl_ = new Impl(buf, bgra);
983             break;
984         }
985     case _InputArray::GPU_MAT:
986         {
987             #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
988                 throw_nocuda;
989             #else
990                 GpuMat d_mat = mat_.getGpuMat();
991                 GlBuffer buf(d_mat, GlBuffer::TEXTURE_BUFFER);
992                 impl_ = new Impl(buf, bgra);
993             #endif
994
995             break;
996         }
997     default:
998         {
999             Mat mat = mat_.getMat();
1000             impl_ = new Impl(mat, bgra);
1001             break;
1002         }
1003     }
1004
1005     rows_ = _size.height;
1006     cols_ = _size.width;
1007     type_ = _type;
1008 #endif
1009 }
1010
1011 void cv::GlTexture::create(int _rows, int _cols, int _type)
1012 {
1013 #ifndef HAVE_OPENGL
1014     (void)_rows;
1015     (void)_cols;
1016     (void)_type;
1017     throw_nogl;
1018 #else
1019     if (rows_ != _rows || cols_ != _cols || type_ != _type)
1020     {
1021         impl_ = new Impl(_rows, _cols, _type);
1022         rows_ = _rows;
1023         cols_ = _cols;
1024         type_ = _type;
1025     }
1026 #endif
1027 }
1028
1029 void cv::GlTexture::release()
1030 {
1031 #ifndef HAVE_OPENGL
1032     throw_nogl;
1033 #else
1034     impl_ = Impl::empty();
1035 #endif
1036 }
1037
1038 void cv::GlTexture::copyFrom(InputArray mat_, bool bgra)
1039 {
1040 #ifndef HAVE_OPENGL
1041     (void)mat_;
1042     (void)bgra;
1043     throw_nogl;
1044 #else
1045     int kind = mat_.kind();
1046     Size _size = mat_.size();
1047     int _type = mat_.type();
1048
1049     create(_size, _type);
1050
1051     switch(kind)
1052     {
1053     case _InputArray::OPENGL_TEXTURE:
1054         {
1055             GlTexture tex = mat_.getGlTexture();
1056             *this = tex;
1057             break;
1058         }
1059     case _InputArray::OPENGL_BUFFER:
1060         {
1061             GlBuffer buf = mat_.getGlBuffer();
1062             impl_->copyFrom(buf, bgra);
1063             break;
1064         }
1065     case _InputArray::GPU_MAT:
1066         {
1067             #if !defined HAVE_CUDA || defined(CUDA_DISABLER)
1068                 throw_nocuda;
1069             #else
1070                 GpuMat d_mat = mat_.getGpuMat();
1071                 buf_.copyFrom(d_mat);
1072                 impl_->copyFrom(buf_, bgra);
1073             #endif
1074
1075             break;
1076         }
1077     default:
1078         {
1079             Mat mat = mat_.getMat();
1080             impl_->copyFrom(mat, bgra);
1081         }
1082     }
1083 #endif
1084 }
1085
1086 void cv::GlTexture::bind() const
1087 {
1088 #ifndef HAVE_OPENGL
1089     throw_nogl;
1090 #else
1091     impl_->bind();
1092 #endif
1093 }
1094
1095 void cv::GlTexture::unbind() const
1096 {
1097 #ifndef HAVE_OPENGL
1098     throw_nogl;
1099 #else
1100     impl_->unbind();
1101 #endif
1102 }
1103
1104 template <> void cv::Ptr<cv::GlTexture::Impl>::delete_obj()
1105 {
1106     if (obj) delete obj;
1107 }
1108
1109 ////////////////////////////////////////////////////////////////////////
1110 // GlArrays
1111
1112 void cv::GlArrays::setVertexArray(InputArray vertex)
1113 {
1114     int cn = vertex.channels();
1115     int depth = vertex.depth();
1116
1117     CV_Assert(cn == 2 || cn == 3 || cn == 4);
1118     CV_Assert(depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F);
1119
1120     vertex_.copyFrom(vertex);
1121 }
1122
1123 void cv::GlArrays::setColorArray(InputArray color, bool bgra)
1124 {
1125     int cn = color.channels();
1126
1127     CV_Assert((cn == 3 && !bgra) || cn == 4);
1128
1129     color_.copyFrom(color);
1130     bgra_ = bgra;
1131 }
1132
1133 void cv::GlArrays::setNormalArray(InputArray normal)
1134 {
1135     int cn = normal.channels();
1136     int depth = normal.depth();
1137
1138     CV_Assert(cn == 3);
1139     CV_Assert(depth == CV_8S || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F);
1140
1141     normal_.copyFrom(normal);
1142 }
1143
1144 void cv::GlArrays::setTexCoordArray(InputArray texCoord)
1145 {
1146     int cn = texCoord.channels();
1147     int depth = texCoord.depth();
1148
1149     CV_Assert(cn >= 1 && cn <= 4);
1150     CV_Assert(depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F);
1151
1152     texCoord_.copyFrom(texCoord);
1153 }
1154
1155 void cv::GlArrays::bind() const
1156 {
1157 #ifndef HAVE_OPENGL
1158     throw_nogl;
1159 #else
1160     CV_DbgAssert(texCoord_.empty() || texCoord_.size().area() == vertex_.size().area());
1161     CV_DbgAssert(normal_.empty() || normal_.size().area() == vertex_.size().area());
1162     CV_DbgAssert(color_.empty() || color_.size().area() == vertex_.size().area());
1163
1164     if (!texCoord_.empty())
1165     {
1166         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1167         CV_CheckGlError();
1168
1169         texCoord_.bind();
1170
1171         glTexCoordPointer(texCoord_.channels(), gl_types[texCoord_.depth()], 0, 0);
1172         CV_CheckGlError();
1173
1174         texCoord_.unbind();
1175     }
1176
1177     if (!normal_.empty())
1178     {
1179         glEnableClientState(GL_NORMAL_ARRAY);
1180         CV_CheckGlError();
1181
1182         normal_.bind();
1183
1184         glNormalPointer(gl_types[normal_.depth()], 0, 0);
1185         CV_CheckGlError();
1186
1187         normal_.unbind();
1188     }
1189
1190     if (!color_.empty())
1191     {
1192         glEnableClientState(GL_COLOR_ARRAY);
1193         CV_CheckGlError();
1194
1195         color_.bind();
1196
1197         int cn = color_.channels();
1198         int format = cn == 3 ? cn : (bgra_ ? GL_BGRA : 4);
1199
1200         glColorPointer(format, gl_types[color_.depth()], 0, 0);
1201         CV_CheckGlError();
1202
1203         color_.unbind();
1204     }
1205
1206     if (!vertex_.empty())
1207     {
1208         glEnableClientState(GL_VERTEX_ARRAY);
1209         CV_CheckGlError();
1210
1211         vertex_.bind();
1212
1213         glVertexPointer(vertex_.channels(), gl_types[vertex_.depth()], 0, 0);
1214         CV_CheckGlError();
1215
1216         vertex_.unbind();
1217     }
1218 #endif
1219 }
1220
1221 void cv::GlArrays::unbind() const
1222 {
1223 #ifndef HAVE_OPENGL
1224     throw_nogl;
1225 #else
1226     if (!texCoord_.empty())
1227     {
1228         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1229         CV_CheckGlError();
1230     }
1231
1232     if (!normal_.empty())
1233     {
1234         glDisableClientState(GL_NORMAL_ARRAY);
1235         CV_CheckGlError();
1236     }
1237
1238     if (!color_.empty())
1239     {
1240         glDisableClientState(GL_COLOR_ARRAY);
1241         CV_CheckGlError();
1242     }
1243
1244     if (!vertex_.empty())
1245     {
1246         glDisableClientState(GL_VERTEX_ARRAY);
1247         CV_CheckGlError();
1248     }
1249 #endif
1250 }
1251
1252 ////////////////////////////////////////////////////////////////////////
1253 // GlFont
1254
1255 cv::GlFont::GlFont(const string& _family, int _height, Weight _weight, Style _style)
1256     : family_(_family), height_(_height), weight_(_weight), style_(_style), base_(0)
1257 {
1258 #ifndef HAVE_OPENGL
1259     throw_nogl;
1260 #else
1261     base_ = glGenLists(256);
1262     CV_CheckGlError();
1263
1264     glFuncTab()->generateBitmapFont(family_, height_, weight_, (style_ & STYLE_ITALIC) != 0, (style_ & STYLE_UNDERLINE) != 0, 0, 256, base_);
1265 #endif
1266 }
1267
1268 void cv::GlFont::draw(const char* str, int len) const
1269 {
1270 #ifndef HAVE_OPENGL
1271     (void)str;
1272     (void)len;
1273     throw_nogl;
1274 #else
1275     if (base_ && len > 0)
1276     {
1277         glPushAttrib(GL_LIST_BIT);
1278         glListBase(base_);
1279
1280         glCallLists(static_cast<GLsizei>(len), GL_UNSIGNED_BYTE, str);
1281
1282         glPopAttrib();
1283
1284         CV_CheckGlError();
1285     }
1286 #endif
1287 }
1288
1289 namespace
1290 {
1291     class FontCompare : public unary_function<Ptr<GlFont>, bool>
1292     {
1293     public:
1294         inline FontCompare(const string& family, int height, GlFont::Weight weight, GlFont::Style style)
1295             : family_(family), height_(height), weight_(weight), style_(style)
1296         {
1297         }
1298
1299         bool operator ()(const cv::Ptr<GlFont>& font)
1300         {
1301             return font->family() == family_ && font->height() == height_ && font->weight() == weight_ && font->style() == style_;
1302         }
1303
1304     private:
1305         string family_;
1306         int height_;
1307         GlFont::Weight weight_;
1308         GlFont::Style style_;
1309     };
1310 }
1311
1312 Ptr<GlFont> cv::GlFont::get(const std::string& family, int height, Weight weight, Style style)
1313 {
1314 #ifndef HAVE_OPENGL
1315     (void)family;
1316     (void)height;
1317     (void)weight;
1318     (void)style;
1319     throw_nogl;
1320     return Ptr<GlFont>();
1321 #else
1322     static vector< Ptr<GlFont> > fonts;
1323     fonts.reserve(10);
1324
1325     vector< Ptr<GlFont> >::iterator fontIt = find_if(fonts.begin(), fonts.end(), FontCompare(family, height, weight, style));
1326
1327     if (fontIt == fonts.end())
1328     {
1329         fonts.push_back(new GlFont(family, height, weight, style));
1330
1331         fontIt = fonts.end() - 1;
1332     }
1333
1334     return *fontIt;
1335 #endif
1336 }
1337
1338 ////////////////////////////////////////////////////////////////////////
1339 // Rendering
1340
1341 void cv::render(const GlTexture& tex, Rect_<double> wndRect, Rect_<double> texRect)
1342 {
1343 #ifndef HAVE_OPENGL
1344     (void)tex;
1345     (void)wndRect;
1346     (void)texRect;
1347     throw_nogl;
1348 #else
1349     if (!tex.empty())
1350     {
1351         tex.bind();
1352
1353         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1354
1355         glBegin(GL_QUADS);
1356             glTexCoord2d(texRect.x, texRect.y);
1357             glVertex2d(wndRect.x, wndRect.y);
1358
1359             glTexCoord2d(texRect.x, texRect.y + texRect.height);
1360             glVertex2d(wndRect.x, (wndRect.y + wndRect.height));
1361
1362             glTexCoord2d(texRect.x + texRect.width, texRect.y + texRect.height);
1363             glVertex2d(wndRect.x + wndRect.width, (wndRect.y + wndRect.height));
1364
1365             glTexCoord2d(texRect.x + texRect.width, texRect.y);
1366             glVertex2d(wndRect.x + wndRect.width, wndRect.y);
1367         glEnd();
1368
1369         CV_CheckGlError();
1370
1371         tex.unbind();
1372     }
1373 #endif
1374 }
1375
1376 void cv::render(const GlArrays& arr, int mode, Scalar color)
1377 {
1378 #ifndef HAVE_OPENGL
1379     (void)arr;
1380     (void)mode;
1381     (void)color;
1382     throw_nogl;
1383 #else
1384     glColor3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
1385
1386     arr.bind();
1387
1388     glDrawArrays(mode, 0, arr.size().area());
1389
1390     arr.unbind();
1391 #endif
1392 }
1393
1394 void cv::render(const string& str, const Ptr<GlFont>& font, Scalar color, Point2d pos)
1395 {
1396 #ifndef HAVE_OPENGL
1397     (void)str;
1398     (void)font;
1399     (void)color;
1400     (void)pos;
1401     throw_nogl;
1402 #else
1403     glPushAttrib(GL_DEPTH_BUFFER_BIT);
1404
1405     GLint viewport[4];
1406     glGetIntegerv(GL_VIEWPORT, viewport);
1407
1408     glDisable(GL_DEPTH_TEST);
1409
1410     glMatrixMode(GL_PROJECTION);
1411     glLoadIdentity();
1412
1413     glMatrixMode(GL_MODELVIEW);
1414     glLoadIdentity();
1415
1416     glColor3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
1417
1418     glRasterPos2d(2.0 * (viewport[0] + pos.x) / viewport[2] - 1.0, 1.0 - 2.0 * (viewport[1] + pos.y + font->height()) / viewport[3]);
1419
1420     font->draw(str.c_str(), (int)str.length());
1421
1422     glPopAttrib();
1423 #endif
1424 }
1425
1426 ////////////////////////////////////////////////////////////////////////
1427 // GlCamera
1428
1429 cv::GlCamera::GlCamera() :
1430     eye_(0.0, 0.0, -5.0), center_(0.0, 0.0, 0.0), up_(0.0, 1.0, 0.0),
1431     pos_(0.0, 0.0, -5.0), yaw_(0.0), pitch_(0.0), roll_(0.0),
1432     useLookAtParams_(false),
1433
1434     scale_(1.0, 1.0, 1.0),
1435
1436     projectionMatrix_(),
1437     fov_(45.0), aspect_(0.0),
1438     left_(0.0), right_(1.0), bottom_(1.0), top_(0.0),
1439     zNear_(-1.0), zFar_(1.0),
1440     perspectiveProjection_(false)
1441 {
1442 }
1443
1444 void cv::GlCamera::lookAt(Point3d eye, Point3d center, Point3d up)
1445 {
1446     eye_ = eye;
1447     center_ = center;
1448     up_ = up;
1449     useLookAtParams_ = true;
1450 }
1451
1452 void cv::GlCamera::setCameraPos(Point3d pos, double yaw, double pitch, double roll)
1453 {
1454     pos_ = pos;
1455     yaw_ = yaw;
1456     pitch_ = pitch;
1457     roll_ = roll;
1458     useLookAtParams_ = false;
1459 }
1460
1461 void cv::GlCamera::setScale(Point3d scale)
1462 {
1463     scale_ = scale;
1464 }
1465
1466 void cv::GlCamera::setProjectionMatrix(const Mat& projectionMatrix, bool transpose)
1467 {
1468     CV_Assert(projectionMatrix.type() == CV_32F || projectionMatrix.type() == CV_64F);
1469     CV_Assert(projectionMatrix.cols == 4 && projectionMatrix.rows == 4);
1470
1471     projectionMatrix_ = transpose ? projectionMatrix.t() : projectionMatrix;
1472 }
1473
1474 void cv::GlCamera::setPerspectiveProjection(double fov, double aspect, double zNear, double zFar)
1475 {
1476     fov_ = fov;
1477     aspect_ = aspect;
1478     zNear_ = zNear;
1479     zFar_ = zFar;
1480
1481     projectionMatrix_.release();
1482     perspectiveProjection_ = true;
1483 }
1484
1485 void cv::GlCamera::setOrthoProjection(double left, double right, double bottom, double top, double zNear, double zFar)
1486 {
1487     left_ = left;
1488     right_ = right;
1489     bottom_ = bottom;
1490     top_ = top;
1491     zNear_ = zNear;
1492     zFar_ = zFar;
1493
1494     projectionMatrix_.release();
1495     perspectiveProjection_ = false;
1496 }
1497
1498 void cv::GlCamera::setupProjectionMatrix() const
1499 {
1500 #ifndef HAVE_OPENGL
1501     throw_nogl;
1502 #else
1503     glMatrixMode(GL_PROJECTION);
1504     glLoadIdentity();
1505
1506     if (projectionMatrix_.empty())
1507     {
1508         if (perspectiveProjection_)
1509             gluPerspective(fov_, aspect_, zNear_, zFar_);
1510         else
1511             glOrtho(left_, right_, bottom_, top_, zNear_, zFar_);
1512     }
1513     else
1514     {
1515         if (projectionMatrix_.type() == CV_32F)
1516             glLoadMatrixf(projectionMatrix_.ptr<float>());
1517         else
1518             glLoadMatrixd(projectionMatrix_.ptr<double>());
1519     }
1520
1521     CV_CheckGlError();
1522 #endif
1523 }
1524
1525 void cv::GlCamera::setupModelViewMatrix() const
1526 {
1527 #ifndef HAVE_OPENGL
1528     throw_nogl;
1529 #else
1530     glMatrixMode(GL_MODELVIEW);
1531     glLoadIdentity();
1532
1533     if (useLookAtParams_)
1534         gluLookAt(eye_.x, eye_.y, eye_.z, center_.x, center_.y, center_.z, up_.x, up_.y, up_.z);
1535     else
1536     {
1537         glRotated(-yaw_, 0.0, 1.0, 0.0);
1538         glRotated(-pitch_, 1.0, 0.0, 0.0);
1539         glRotated(-roll_, 0.0, 0.0, 1.0);
1540         glTranslated(-pos_.x, -pos_.y, -pos_.z);
1541     }
1542
1543     glScaled(scale_.x, scale_.y, scale_.z);
1544
1545     CV_CheckGlError();
1546 #endif
1547 }
1548
1549 ////////////////////////////////////////////////////////////////////////
1550 // Error handling
1551
1552 bool icvCheckGlError(const char* file, const int line, const char* func)
1553 {
1554 #ifndef HAVE_OPENGL
1555     (void)file;
1556     (void)line;
1557     (void)func;
1558     return true;
1559 #else
1560     GLenum err = glGetError();
1561
1562     if (err != GL_NO_ERROR)
1563     {
1564         const char* msg;
1565
1566         switch (err)
1567         {
1568         case GL_INVALID_ENUM:
1569             msg = "An unacceptable value is specified for an enumerated argument";
1570             break;
1571         case GL_INVALID_VALUE:
1572             msg = "A numeric argument is out of range";
1573             break;
1574         case GL_INVALID_OPERATION:
1575             msg = "The specified operation is not allowed in the current state";
1576             break;
1577         case GL_STACK_OVERFLOW:
1578             msg = "This command would cause a stack overflow";
1579             break;
1580         case GL_STACK_UNDERFLOW:
1581             msg = "This command would cause a stack underflow";
1582             break;
1583         case GL_OUT_OF_MEMORY:
1584             msg = "There is not enough memory left to execute the command";
1585             break;
1586         default:
1587             msg = "Unknown error";
1588         };
1589
1590         cvError(CV_OpenGlApiCallError, func, msg, file, line);
1591
1592         return false;
1593     }
1594
1595     return true;
1596 #endif
1597 }