JeVois  1.22
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
GPUimage.C
Go to the documentation of this file.
1// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2//
3// JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2020 by Laurent Itti, the University of Southern
4// California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5//
6// This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7// redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8// Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10// License for more details. You should have received a copy of the GNU General Public License along with this program;
11// if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12//
13// Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14// Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16/*! \file */
17
18#ifdef JEVOIS_PRO
19
20#include <jevois/GPU/GPUimage.H>
21
22#include <jevois/Util/Utils.H>
26#include <glm/glm.hpp>
27#include <glm/gtc/type_ptr.hpp>
28
29// ##############################################################################################################
30// Shaders used here:
31namespace jevois
32{
33 //! OpenGL shaders for video rendering
34 namespace shader
35 {
36 extern char const * vert; // Vertex shader
37 extern char const * frag_rgba; // To display an RGBA image
38 extern char const * frag_rgb; // To display an RGB image
39 extern char const * frag_grey; // To display a greyscale image
40 extern char const * frag_yuyv; // To display a YUYV image
41 extern char const * frag_oes; // To display a DMABUF camera image
42 extern char const * frag_rgba_twirl; // To display an RGBA image with a twirl effect
43 extern char const * frag_rgb_twirl; // To display an RGB image with a twirl effect
44 extern char const * frag_grey_twirl; // To display a greyscale image with a twirl effect
45 extern char const * frag_yuyv_twirl; // To display a YUYV image with a twirl effect
46 extern char const * frag_oes_twirl; // To display a DMABUF camera image with a twirl effect
47 }
48}
49
50// ##############################################################################################################
53
54// ##############################################################################################################
56{
57 if (itsVertexArray) glDeleteVertexArrays(1, &itsVertexArray);
58 if (itsVertexBuffers[0]) glDeleteBuffers(2, itsVertexBuffers);
59}
60
61// ##############################################################################################################
62void jevois::GPUimage::setInternal(unsigned int width, unsigned int height, unsigned int fmt,
63 unsigned char const * data)
64{
65 if (width == 0 || height == 0) LFATAL("Cannot handle zero image width or height");
66
67 // If image format has changed, load the appropriate program:
68 if (fmt != itsFormat)
69 {
70 char const * frag_shader;
71 switch (fmt)
72 {
73 case V4L2_PIX_FMT_YUYV: // YUYV shader gets YUYV (2 pixels) from one RGBA texture value (1 texel)
74 if (itsTwirl) frag_shader = jevois::shader::frag_yuyv_twirl;
75 else frag_shader = jevois::shader::frag_yuyv;
76 itsGLtextureFmt = GL_RGBA;
77 break;
78
79 case V4L2_PIX_FMT_RGB32: // RGBA shader is simple pass-through
80 if (itsTwirl) frag_shader = jevois::shader::frag_rgba_twirl;
81 else frag_shader = jevois::shader::frag_rgba;
82 itsGLtextureFmt = GL_RGBA;
83 break;
84
85 case V4L2_PIX_FMT_GREY: // GRAY shader just converts from greyscale to RGBA
86 if (itsTwirl) frag_shader = jevois::shader::frag_grey_twirl;
87 else frag_shader = jevois::shader::frag_grey;
88 itsGLtextureFmt = GL_LUMINANCE;
89 break;
90
91 case V4L2_PIX_FMT_RGB24: // RGB shader gets R,G,B from 3 successive texels in a 3x wide luminance texture
92 if (itsTwirl) frag_shader = jevois::shader::frag_rgb_twirl;
93 else frag_shader = jevois::shader::frag_rgb;
94 itsGLtextureFmt = GL_LUMINANCE;
95 break;
96
97 case V4L2_PIX_FMT_BGR24:
98 case V4L2_PIX_FMT_SRGGB8:
99 case V4L2_PIX_FMT_RGB565:
100 case V4L2_PIX_FMT_MJPEG:
101 case V4L2_PIX_FMT_UYVY:
102 case V4L2_PIX_FMT_SBGGR16:
103 case V4L2_PIX_FMT_SGRBG16:
104 case V4L2_PIX_FMT_NV12:
105 case V4L2_PIX_FMT_YUV444:
106 case 0:
107 default: LFATAL("Unsupported pixel format " << jevois::fccstr(fmt));
108 }
109
110 // Load the appropriate program:
111 itsProgram.reset(new GPUprogram(jevois::shader::vert, frag_shader));
112
113 // Get a handle to s_texture variable in the fragment shader, to update the texture with each new camera frame:
114 itsLocation = glGetUniformLocation(itsProgram->id(), "s_texture");
115 }
116
117 // Generate a texture for incoming image data if needed:
118 if (width != itsTextureWidth || height != itsTextureHeight || fmt != itsFormat || !itsTexture)
119 {
120 // If the width has changed, we need to update itsGLtextureWidth:
121 if (width != itsTextureWidth)
122 switch (fmt)
123 {
124 // YUYV shader gets YUYV (2 pixels) from one RGBA texture value (1 texel)
125 case V4L2_PIX_FMT_YUYV: itsGLtextureWidth = width / 2; break;
126
127 // RGBA shader is simple pass-through
128 case V4L2_PIX_FMT_RGB32: itsGLtextureWidth = width; break;
129
130 // GRAY shader just converts from greyscale to RGBA
131 case V4L2_PIX_FMT_GREY: itsGLtextureWidth = width; break;
132
133 // RGB shader gets R,G,B from 3 successive texels in a 3x wide luminance texture
134 case V4L2_PIX_FMT_RGB24: itsGLtextureWidth = width * 3; break;
135
136 default: LFATAL("Unsupported pixel format " << jevois::fccstr(fmt));
137 }
138
139 // Create the texture:
140 itsTexture.reset(new jevois::GPUtexture(itsGLtextureWidth, height, itsGLtextureFmt, false));
141 LDEBUG("Input texture for " << width << 'x' << height << ' ' << jevois::fccstr(fmt) << " ready.");
142
143 // Remember our latest size and format:
144 itsTextureWidth = width; itsTextureHeight = height; itsFormat = fmt;
145 }
146
147#ifdef JEVOIS_PLATFORM_PRO
148 if (itsTextureDmaBuf) itsTextureDmaBuf.reset(); // invalidate any previously used dmabuf texture
149#endif
150
151 // Assign pixel data to our texture:
152 itsTexture->setPixels(data);
153}
154
155// ##############################################################################################################
157{
158 setInternal(img.width, img.height, img.fmt, static_cast<unsigned char const *>(img.buf->data()));
159}
160
161// ##############################################################################################################
162void jevois::GPUimage::set(cv::Mat const & img, bool rgb)
163{
164 unsigned int fmt;
165
166 switch(img.type())
167 {
168 case CV_8UC4: if (rgb) fmt = V4L2_PIX_FMT_RGB32; else fmt = V4L2_PIX_FMT_BGR32; break;
169 case CV_8UC3: if (rgb) fmt = V4L2_PIX_FMT_RGB24; else fmt = V4L2_PIX_FMT_BGR24; break;
170 case CV_8UC2: fmt = V4L2_PIX_FMT_YUYV; break;
171 case CV_8UC1: fmt = V4L2_PIX_FMT_GREY; break;
172 default: LFATAL("Unsupported OpenCV image format: " << img.type());
173 }
174
175 setInternal(img.cols, img.rows, fmt, img.data);
176}
177
178#ifdef JEVOIS_PLATFORM_PRO
179// ##############################################################################################################
180void jevois::GPUimage::set(jevois::InputFrame const & frame, EGLDisplay display)
181{
182 jevois::RawImage const img = frame.get();
183 int const dmafd = img.buf->dmaFd();
184
185 // EGLimageKHR which we use with DMAbuf requires width to be a multiple of 32; otherwise revert to normal texture:
186 if ((img.width % 32) || dmafd < 0) { set(img); return; }
187
188 // DMAbuf only supports some formats, otherwise revert to normal texture. Keep in sync with GPUtextureDmaBuf:
189 switch (img.fmt)
190 {
191 case V4L2_PIX_FMT_YUYV:
192 case V4L2_PIX_FMT_RGB32:
193 case V4L2_PIX_FMT_RGB565:
194 case V4L2_PIX_FMT_BGR24:
195 case V4L2_PIX_FMT_RGB24:
196 case V4L2_PIX_FMT_UYVY:
197 setWithDmaBuf(img, dmafd, display);
198 break;
199
200 default:
201 set(img);
202 }
203}
204
205// ##############################################################################################################
206void jevois::GPUimage::set2(jevois::InputFrame const & frame, EGLDisplay display)
207{
208 jevois::RawImage const img = frame.get2();
209 int const dmafd = img.buf->dmaFd();
210
211 // EGLimageKHR which we use with DMAbuf requires width to be a multiple of 32; otherwise revert to normal texture:
212 if ((img.width % 32) || dmafd < 0) { set(img); return; }
213
214 // DMAbuf only supports some formats, otherwise revert to normal texture. Keep in sync with GPUtextureDmaBuf:
215 switch (img.fmt)
216 {
217 case V4L2_PIX_FMT_YUYV:
218 case V4L2_PIX_FMT_RGB32:
219 case V4L2_PIX_FMT_RGB565:
220 case V4L2_PIX_FMT_BGR24:
221 case V4L2_PIX_FMT_RGB24:
222 case V4L2_PIX_FMT_UYVY:
223 setWithDmaBuf(img, dmafd, display);
224 break;
225
226 default:
227 set(img);
228 }
229}
230
231// ##############################################################################################################
232void jevois::GPUimage::setWithDmaBuf(jevois::RawImage const & img, int dmafd, EGLDisplay display)
233{
234 if (img.width == 0 || img.height == 0) LFATAL("Cannot handle zero image width or height");
235
236 // Generate a dmabuf texture for incoming image data if needed:
237 if (img.width != itsTextureWidth || img.height != itsTextureHeight || img.fmt != itsFormat ||
238 itsTexture || !itsTextureDmaBuf)
239 {
240 itsTextureDmaBuf.reset(new jevois::GPUtextureDmaBuf(display, img.width, img.height, img.fmt, dmafd));
241 itsTexture.reset(); // invalidate any previously used regular texture
242 LDEBUG("Input DMABUF texture for " << img.width <<'x'<< img.height << ' ' << jevois::fccstr(img.fmt) << " ready.");
243
244 // Remember our latest size:
245 itsTextureWidth = img.width; itsTextureHeight = img.height;
246
247 // Load the appropriate program:
248 if (itsTwirl) itsProgram.reset(new GPUprogram(jevois::shader::vert, jevois::shader::frag_oes_twirl));
249 else itsProgram.reset(new GPUprogram(jevois::shader::vert, jevois::shader::frag_oes));
250
251 // Get a handle to s_texture variable in the fragment shader, to update the texture with each new camera frame:
252 itsLocation = glGetUniformLocation(itsProgram->id(), "s_texture");
253
254 // Remember our latest format:
255 itsFormat = img.fmt;
256 }
257
258 // All done. No need to assign pixel data, it will be DMA'd over.
259}
260
261#else // JEVOIS_PLATFORM_PRO
262
263// ##############################################################################################################
264void jevois::GPUimage::set(jevois::InputFrame const & frame, EGLDisplay)
265{
266 // DMABUF acceleration not supported:
267 jevois::RawImage const img = frame.get();
268 set(img);
269}
270
271// ##############################################################################################################
272void jevois::GPUimage::set2(jevois::InputFrame const & frame, EGLDisplay)
273{
274 // DMABUF acceleration not supported:
275 jevois::RawImage const img = frame.get2();
276 set(img);
277}
278
279#endif // JEVOIS_PLATFORM_PRO
280
281// ##############################################################################################################
282void jevois::GPUimage::draw(int & x, int & y, unsigned short & w, unsigned short & h, bool noalias,
283 glm::mat4 const & pvm)
284{
285 if (itsTextureWidth == 0) throw std::runtime_error("You must call set() before draw()");
286
287 // Enable blending, used for RGBA textures that have transparency:
288 glEnable(GL_BLEND);
289 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
290
291 // Get the current viewport size:
292 GLint viewport[4];
293 glGetIntegerv(GL_VIEWPORT, viewport);
294
295 if (w == 0 || h == 0)
296 {
297 // Letterbox the image into the window to occupy as much space as possible without changing aspect ratio:
298 unsigned int winw = viewport[2], winh = viewport[3];
299 itsDrawWidth = itsTextureWidth; itsDrawHeight = itsTextureHeight;
300 jevois::applyLetterBox(itsDrawWidth, itsDrawHeight, winw, winh, noalias);
301 x = (winw - itsDrawWidth) / 2; y = (winh - itsDrawHeight) / 2; w = itsDrawWidth; h = itsDrawHeight;
302 }
303
304 // Flip the ordinate. Our OpenGL texture rendering uses 0,0 at the bottom-left corner, with increasing y going up on
305 // the screen. But machine vision (and our users) assumes 0,0 at top left of the screen with increasing y going down:
306 int const yy = viewport[3] - y - h;
307
308 // Allocate/update vertex arrays if needed (including on first frame):
309 if (itsDrawX != x || itsDrawY != y || itsDrawWidth != w || itsDrawHeight != h)
310 {
311 // Compute vertex coordinates: We here assume that the projection matrix is such that at the pixel perfect plane,
312 // our vertex x,y coordinates match their pixel counterparts, except that image center is at 0,0. The view matrix is
313 // responsible for translating our z from 0 here to the pixel pixel perfect plane:
314 float const tx = x - 0.5 * viewport[2];
315 float const ty = yy - 0.5 * viewport[3];
316 float const bx = tx + w;
317 float const by = ty + h;
318
319 // Create a new vertex array. A group of vertices and indices stored in GPU memory. The frame being drawn is static
320 // for the program duration, upload all the information to the GPU at the beginning then reference the location each
321 // frame without copying the data each frame.
322 GLfloat const vertices[] = { tx, by, 0.0f, 0.0f, 0.0f,
323 tx, ty, 0.0f, 0.0f, 1.0f,
324 bx, ty, 0.0f, 1.0f, 1.0f,
325 bx, by, 0.0f, 1.0f, 0.0f };
326 static GLushort const indices[] = { 0, 1, 2, 0, 2, 3 };
327
328 if (itsVertexArray) { glDeleteVertexArrays(1, &itsVertexArray); glDeleteBuffers(2, itsVertexBuffers); }
329 glGenVertexArrays(1, &itsVertexArray);
330
331 // Select the vertex array that was just created and bind the new vertex buffers to the array:
332 glBindVertexArray(itsVertexArray);
333
334 // Generate vertex buffers in GPU memory. First buffer is for vertex data, second for index data:
335 if (itsVertexBuffers[0]) glDeleteBuffers(2, itsVertexBuffers);
336 glGenBuffers(2, itsVertexBuffers);
337
338 // Bind the first vertex buffer with the vertices to the vertex array:
339 glBindBuffer(GL_ARRAY_BUFFER, itsVertexBuffers[0]);
340 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
341
342 // Bind the second vertex buffer with the indices to the vertex array:
343 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, itsVertexBuffers[1]);
344 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
345
346 // Enable a_position (location 0) and a_tex_coord (location 1) in the vertex shader:
347 glEnableVertexAttribArray(0);
348 glEnableVertexAttribArray(1);
349
350 // Copy the vertices to the GPU to be used in a_position:
351 GL_CHECK(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0));
352
353 // Copy the texture co-ordinates to the GPU to be used in a_tex_coord:
354 GL_CHECK(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void const *)(3 * sizeof(GLfloat))));
355
356 // Select the default vertex array, allowing the application's array to be unbound:
357 glBindVertexArray(0);
358
359 // Remember our latest draw location and size:
360 itsDrawX = x; itsDrawY = y; itsDrawWidth = w; itsDrawHeight = h;
361 }
362
363 if (!itsProgram) throw std::runtime_error("You must call set() before draw()");
364
365 // Tell OpenGL to use our program:
366 glUseProgram(itsProgram->id());
367
368 // Select the vertex array which includes the vertices and indices describing the window rectangle:
369 glBindVertexArray(itsVertexArray);
370
371 // Bind our texture, regular or DMABUF:
372 GL_CHECK(glActiveTexture(GL_TEXTURE0));
373 if (itsTexture)
374 GL_CHECK(glBindTexture(GL_TEXTURE_2D, itsTexture->Id));
375#ifdef JEVOIS_PLATFORM_PRO
376 else if (itsTextureDmaBuf)
377 GL_CHECK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, itsTextureDmaBuf->Id));
378#endif
379 else throw std::runtime_error("You must call set() before draw()");
380
381 // Indicate that GL_TEXTURE0 is s_texture from previous lookup:
382 glUniform1i(itsLocation, 0);
383
384 // Let the fragment shader know the true (unscaled by bpp) image width and height. Also set the PVM matrix. Ignore any
385 // errors as some shaders may not have these variables:
386 glUniform2f(glGetUniformLocation(itsProgram->id(), "tdim"), GLfloat(itsTextureWidth), GLfloat(itsTextureHeight));
387 glUniformMatrix4fv(glGetUniformLocation(itsProgram->id(), "pvm"), 1, GL_FALSE, glm::value_ptr(pvm));
388
389 if (itsTwirl)
390 {
391 glUniform1f(glGetUniformLocation(itsProgram->id(), "twirlamount"), itsTwirl);
392 glUniform1f(glGetUniformLocation(itsProgram->id(), "alpha"), itsAlpha);
393 }
394
395 // Draw the two triangles from 6 indices to form a rectangle from the data in the vertex array.
396 // The fourth parameter, indices value here is passed as null since the values are already
397 // available in the GPU memory through the vertex array
398 // GL_TRIANGLES - draw each set of three vertices as an individual triangle.
399 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
400
401 // Select the default vertex array, allowing the application array to be unbound:
402 glBindVertexArray(0);
403}
404
405// ##############################################################################################################
406ImVec2 jevois::GPUimage::i2d(ImVec2 const & p)
407{
408 if (itsDrawWidth == 0) throw std::runtime_error("Need to call set() then draw() first");
409 return ImVec2(itsDrawX + p.x * itsDrawWidth / itsTextureWidth, itsDrawY + p.y * itsDrawHeight / itsTextureHeight);
410}
411
412// ##############################################################################################################
413ImVec2 jevois::GPUimage::i2ds(ImVec2 const & p)
414{
415 if (itsDrawWidth == 0) throw std::runtime_error("Need to call set() then draw() first");
416 return ImVec2(p.x * itsDrawWidth / itsTextureWidth, p.y * itsDrawHeight / itsTextureHeight);
417}
418
419// ##############################################################################################################
420ImVec2 jevois::GPUimage::d2i(ImVec2 const & p)
421{
422 if (itsDrawWidth == 0) throw std::runtime_error("Need to call set() then draw() first");
423 return ImVec2((p.x - itsDrawX) * itsTextureWidth / itsDrawWidth, (p.y - itsDrawY) * itsTextureHeight / itsDrawHeight);
424}
425
426// ##############################################################################################################
427ImVec2 jevois::GPUimage::d2is(ImVec2 const & p)
428{
429 if (itsDrawWidth == 0) throw std::runtime_error("Need to call set() then draw() first");
430 return ImVec2(p.x * itsTextureWidth / itsDrawWidth, p.y * itsTextureHeight / itsDrawHeight);
431}
432
433// ##############################################################################################################
434void jevois::GPUimage::twirl(float t, float alpha)
435{
436 // If we are not already twirling, or we want to stop twirling, force a reload of the shader program:
437 if (itsTwirl == 0.0F || t == 0.0F) itsFormat = 0;
438
439 // Remember the new twirl amount:
440 itsTwirl = t;
441 itsAlpha = alpha;
442}
443
444#endif // JEVOIS_PRO
int h
Definition GUIhelper.C:2520
#define GL_CHECK(stmt)
Simple macro to check for OpenGL errors.
Definition OpenGL.H:77
GPUimage()
Constructor.
Definition GPUimage.C:51
ImVec2 i2ds(ImVec2 const &p)
Convert a 2D size from within a rendered image to on-screen.
Definition GPUimage.C:413
void setWithDmaBuf(jevois::RawImage const &img, int dmafd, EGLDisplay display)
Definition GPUimage.C:232
ImVec2 i2d(ImVec2 const &p)
Convert coordinates of a point from within a rendered image to on-screen.
Definition GPUimage.C:406
void set(RawImage const &img)
Set pixel data from a vanilla RawImage, pixel data will be copied to texture.
Definition GPUimage.C:156
~GPUimage()
Destructor.
Definition GPUimage.C:55
void twirl(float t, float alpha=1.0F)
Optional twirl and alpha fading effect to the image, useful mostly for demos/transitions.
Definition GPUimage.C:434
ImVec2 d2i(ImVec2 const &p)
Convert coordinates of a point from on-screen to within a rendered image.
Definition GPUimage.C:420
void set2(InputFrame const &frame, EGLDisplay display)
Set pixel data from camera input second (scaled) frame, sharing data with camera kernel driver using ...
Definition GPUimage.C:206
void setInternal(unsigned int width, unsigned int height, unsigned int fmt, unsigned char const *data)
Definition GPUimage.C:62
ImVec2 d2is(ImVec2 const &p)
Convert a 2D size from on-screen to within a rendered image.
Definition GPUimage.C:427
void draw(int &x, int &y, unsigned short &w, unsigned short &h, bool noalias, glm::mat4 const &pvm)
Draw to OpenGL.
Definition GPUimage.C:282
Simple class to load and compile some OpenGL-ES program.
Definition GPUprogram.H:26
Simple class to hold an OpenGL texture with in-GPU pixel format conversion and DMABUF acceleration.
Simple class to hold an OpenGL texture.
Definition GPUtexture.H:29
Exception-safe wrapper around a raw camera input frame.
Definition InputFrame.H:51
RawImage const & get(bool casync=false) const
Get the next captured camera image.
Definition InputFrame.C:50
RawImage const & get2(bool casync=false) const
Get the next captured camera image, ISP-scaled second frame.
Definition InputFrame.C:67
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition RawImage.H:111
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition RawImage.H:147
unsigned int width
Image width in pixels.
Definition RawImage.H:145
unsigned int height
Image height in pixels.
Definition RawImage.H:146
std::shared_ptr< VideoBuf > buf
The pixel data buffer.
Definition RawImage.H:149
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
Definition Log.H:230
#define LDEBUG(msg)
Convenience macro for users to print out console or syslog messages, DEBUG level.
Definition Log.H:173
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
Definition Utils.C:45
void applyLetterBox(unsigned int &imw, unsigned int &imh, unsigned int const winw, unsigned int const winh, bool noalias)
Apply a letterbox resizing to fit an image into a window.
Definition Utils.C:222
char const * frag_rgb
char const * frag_oes_twirl
char const * frag_rgba_twirl
char const * frag_rgba
char const * frag_yuyv_twirl
char const * frag_rgb_twirl
char const * frag_yuyv
char const * frag_oes
char const * frag_grey
char const * frag_grey_twirl
char const * vert
Main namespace for all JeVois classes and functions.
Definition Concepts.dox:2