/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2013 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLQt/src/ICLQt/GLImg.h ** ** Module : ICLQt ** ** Authors: Christof Elbrechter ** ** ** ** ** ** GNU LESSER GENERAL PUBLIC LICENSE ** ** This file may be used under the terms of the GNU Lesser General ** ** Public License version 3.0 as published by the ** ** ** ** Free Software Foundation and appearing in the file LICENSE.LGPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the license requirements will ** ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** ********************************************************************/ #pragma once #include #include #include #include #include #include #include namespace icl{ namespace qt{ /// OpenGL Texture Map Image class /** The GLImg provides a simple interface to use ICL images as OpenGL texture maps. \section _TEX_ Image Textures Copying an image to a texture is applied in two steps. First, the image data is internally buffered. Then later the data is uploaded to the graphics memory. The buffering mechanism is restricted by the maximum texture size that is supported by the OpenGL system. Usually, the maximum texture size is 4096 or 8192, but the OpenGL standard does only say, that at least 64 must be supported. Therefore, it cannot be guaranteed that each image can be represented by a single OpenGL texture. Instead, larger images are represented by a 2D array of tiles, where each tile is represented by a single OpenGL texture. \section _BUF_ Internal Buffering Since the image data potentially needs to be split into several tiles, is is simpler to align the buffered data in image tiles. In order to minimize the amount of glTexImage2D calls, the data is furthermore buffered in interleaved data order. Here, byte-, short- and float- typed images (icl8u, icl16s and icl32f) are supported natively, i.e. they are buffered and uploaded in their native core::format. The other depths (icl32s and icl64f) are not supported natively, i.e. image of this core::depth are already buffered as floats. For int-typed images (icl32s) this, means, that very high image values cannot be represented correctly. And double typed images are also clipped to the float range and accuracy. \section _UP_ Uploading Texture Data While the image buffering step is applied immediately (usually in the working thread), uploading the texture data to the graphics hardware is applied in a deferred manner. This has to reasons: -# It is not allowed to access OpenGL from several threads. Due to the Qt-dependency, OpenGL will always live in the applications main thread. -# If textures are visualized more frequently then their data is changed. A simple internal dirty-flag can be used to decide, whether the OpenGL texture data is already up-to-date. In other words, when the texture is drawn (i.e. using GLImg::draw2D or GLImg::draw3D), the buffered data is automatically uploaded to the graphics hardware if this is necessary. */ class ICLQt_API GLImg : public utils::Uncopyable{ struct Data; //!< internal data structure Data *m_data; //!< internal data pointer public: /// creates a new GLImg instance /** optional parameters are @param src optionally given source image (if null, isNull() will return true) @param sm texture interpolation mode (either interpolateNN or interpolateLIN) @param maxCellSize the cells size (see \ref _BUF_) */ GLImg(const core::ImgBase *src=0, core::scalemode sm=core::interpolateNN, int maxCellSize=4096); /// destructor ~GLImg(); /// set new texture data /** if source is null, the texture handle is deleted and isNull() will return true */ void update(const core::ImgBase *src, int maxCellSize=4096); /// sets the texture interpolation mode void setScaleMode(core::scalemode sm); /// returns whether a non-null images was buffered bool isNull() const; /// draws the image to the given 2D rect /** This method is optimized for the OpenGL parameters set by the ICLQt::Widget class */ void draw2D(const utils::Rect &r, const utils::Size &windowSize); /// draws the image to the given quadrangle /** This method is optimized for the OpenGL parameters set by the ICLQt::Widget class */ void draw2D(const float a[2], const float b[2], const float c[2],const float e[2], const utils::Size &windowSize); /// draws the texture to the given nodes quad in 3D space /** the point order is
          a ---- b
          |      |
          |      |
          c ---- d
          
An addition to the corner 3D positions (a, b, c, and d), optionally normals (na, nb, nc and nd) can be given. The normals are only used, if none of the normal pointers is null. Additionally non-standard texture coordinates can be used to draw only parts of the texture. */ void draw3D(const float a[3],const float b[3],const float c[3],const float d[3], const float na[3]=0, const float nb[3]=0, const float nc[3]=0, const float nd[3]=0, const utils::Point32f &texCoordsA=utils::Point32f(0,0), const utils::Point32f &texCoordsB=utils::Point32f(1,0), const utils::Point32f &texCoordsC=utils::Point32f(0,1), const utils::Point32f &texCoordsD=utils::Point32f(1,1)); /// draws the texture using the given 3D Points, texture coordinates and optionally given normals /** The strides are given in float-units. If normals are not given (i.e. at least one of the points nxs, nys or nzs is null, no normals will be set. */ void draw3DGeneric(int numPoints, const float *xs, const float *ys, const float *zs, int xyzStride, const utils::Point32f *texCoords, const float *nxs=0, const float *nys=0, const float *nzs=0, int nxyzStride=1, bool invertNormals=false); /// draws the texture to given quad that is spanned by two vectors inline void draw3D(const float a[3],const float b[3],const float c[3]){ const float d[3] = { b[0] + c[0] -a[0], b[1] + c[1] -a[1], b[2] + c[2] -a[2] }; draw3D(a,b,c,d); } /// draws the single texture spread to a given grid of nodes /** \section _LIMIT_ size limitation This does only work, if the texture size (width and height) is smaller than the maximum texture size supported by openGL. Usually, this is >= 4096. \section _LAYOUT_ data layout The grid data layout is row-major, i.e. the grid node at (x,y) is obtained by (xs[idx], ys[idx], zs[idx]) where idx is stride*(x+nx*y). By using the stride parameter, this function can be used for both, planar and interleaved data. \section _INTER_ interleaved data \code typedef FixedColVector V4; const int nx = 20, ny = 30; icl::Array2D grid(nx,ny); // interleaved data with stride = 4 // (...) fill grid nodes with values ImgQ image = create("lena"); GLImg gli(&image); V4 &v = grid[0]; gli.drawToGrid(nx,ny,&v[0],&v[1],&v[2],0,0,0,4); \endcode \section _PLANAR_ planar data // add code from example above const int dim = nx*ny; std::vector xs(dim), ys(dim), zs(dim); // (...) fill xs, ys and zs with data gli.drawToGrid(nx,ny,xs.data(), ys.data(), zs.data()); */ void drawToGrid(int nx, int ny, const float *xs, const float *ys, const float *zs, const float *nxs=0, const float *nys=0, const float *nzs=0, const int stride = 1, bool invertNormals=false); /// 3D vector type typedef math::FixedColVector Vec3; /// a grid function returns a 3D pos from given 2D grid position typedef utils::Function grid_function; /// draws the texture to an nx x ny grid whose positions and normals are defined by functions /** The grid results are buffered internally in order to avoid extra function evaluations. Once, the data is buffered, it is passed to GLImg::drawGrid(int,int,const float*,const float*,const float*,const float*,const float*,const float*,int) \section _EX_ example \code GLImg::Vec3 grid_func(int x, int y){ float nx = 30, ny = 20; return GLImg::Vec3(x-(nx/2),y-(ny/2),(nx/10.) * sin(float(x)/5 + t*5 )) * (300./nx); } void renderGrid(){ GLImg gli(&image); static utils::Time first = utils::Time::now(); float t = (utils::Time::now() - first).toSecondsDouble(); gli.drawToGrid(30,20,grid_func); } \endcode */ void drawToGrid(int nx, int ny, grid_function gridVertices, grid_function gridNormals = grid_function()); /// returns the maximum texture map size that is supported by the present OpenGL system static int getMaxTextureSize(); /// returns the number of internal cells used for the texture utils::Size getCells() const; /// binds the given texture cell using glBindTexture(...) void bind(int xCell=0, int yCell=0, int textureUnit=0) const; /// returns the image size inline utils::Size getSize() const { return utils::Size(getWidth(), getHeight()); } /// returns current image height int getWidth() const; /// returns current image width int getHeight() const; /// returns current image channel count int getChannels() const; /// returns the image depth core::depth getDepth() const; /// returns the image format core::format getFormat() const; /// returns the image roi utils::Rect getROI() const; /// returns the current images time stamp utils::Time getTime() const; /// sets up current brightness contrast and intensity /** if b=c=i=-1 then, brightness is adapted automatically */ void setBCI(int b=-1, int c=-1, int i=-1); /// returns the current minimun and maximum values for all channels std::vector getMinMax() const; /// retuns the color at a given image location or a zero sized vector, (x,y) is outside the image std::vector getColor(int x, int y)const; /// creates core::ImgBase version of the currently buffered images /** Please note that the ownership is not passed to the caller! */ const core::ImgBase *extractImage() const; /// returns statistics of the currently buffered image const ImageStatistics &getStats() const; /// sets whether to visualize the pixel-grid or not void setDrawGrid(bool enabled, float *color=0); /// sets the grid color void setGridColor(float *color); /// returns the current grid color const float *getGridColor() const; /// returns the current scalemode core::scalemode getScaleMode() const; /// locks the texture buffer void lock() const; /// unlocks the texture buffer void unlock() const; }; } // namespace qt }