1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <math.h>
21 #include <stdlib.h>
22
23 #include "cairo-dock-icon-manager.h" // myIconsParam.iIconWidth
24 #include "cairo-dock-desklet-manager.h" // CAIRO_DOCK_IS_DESKLET
25 #include "cairo-dock-surface-factory.h"
26 #include "cairo-dock-log.h"
27 #include "cairo-dock-draw.h"
28 #include "cairo-dock-draw-opengl.h"
29 #include "cairo-dock-opengl.h" // gldi_gl_container_make_current
30 #include "cairo-dock-image-buffer.h"
31
32 extern gchar *g_cCurrentThemePath;
33 extern gchar *g_cCurrentIconsPath;
34 extern gchar *g_cCurrentImagesPath;
35
36 extern gboolean g_bUseOpenGL;
37 extern CairoDockGLConfig g_openglConfig;
38 extern GldiContainer *g_pPrimaryContainer;
39 extern gboolean g_bEasterEggs;
40
41
cairo_dock_search_image_s_path(const gchar * cImageFile)42 gchar *cairo_dock_search_image_s_path (const gchar *cImageFile)
43 {
44 g_return_val_if_fail (cImageFile != NULL, NULL);
45 gchar *cImagePath;
46 if (*cImageFile == '~')
47 {
48 cImagePath = g_strdup_printf ("%s%s", getenv("HOME"), cImageFile + 1);
49 if (!g_file_test (cImagePath, G_FILE_TEST_EXISTS))
50 {
51 g_free (cImagePath);
52 cImagePath = NULL;
53 }
54 }
55 else if (*cImageFile == '/')
56 {
57 if (!g_file_test (cImageFile, G_FILE_TEST_EXISTS))
58 cImagePath = NULL;
59 else
60 cImagePath = g_strdup (cImageFile);
61 }
62 else
63 {
64 cImagePath = g_strdup_printf ("%s/%s", g_cCurrentImagesPath, cImageFile);
65 if (!g_file_test (cImagePath, G_FILE_TEST_EXISTS))
66 {
67 g_free (cImagePath);
68 cImagePath = g_strdup_printf ("%s/%s", g_cCurrentThemePath, cImageFile);
69 if (!g_file_test (cImagePath, G_FILE_TEST_EXISTS))
70 {
71 g_free (cImagePath);
72 cImagePath = g_strdup_printf ("%s/%s", g_cCurrentIconsPath, cImageFile);
73 if (!g_file_test (cImagePath, G_FILE_TEST_EXISTS))
74 {
75 g_free (cImagePath);
76 cImagePath = NULL;
77 }
78 }
79 }
80 }
81 return cImagePath;
82 }
83
84
cairo_dock_load_image_buffer_full(CairoDockImageBuffer * pImage,const gchar * cImageFile,int iWidth,int iHeight,CairoDockLoadImageModifier iLoadModifier,double fAlpha)85 void cairo_dock_load_image_buffer_full (CairoDockImageBuffer *pImage, const gchar *cImageFile, int iWidth, int iHeight, CairoDockLoadImageModifier iLoadModifier, double fAlpha)
86 {
87 if (cImageFile == NULL)
88 return;
89 gchar *cImagePath = cairo_dock_search_image_s_path (cImageFile);
90 double w=0, h=0;
91 pImage->pSurface = cairo_dock_create_surface_from_image (
92 cImagePath,
93 1.,
94 iWidth,
95 iHeight,
96 iLoadModifier,
97 &w,
98 &h,
99 &pImage->fZoomX,
100 &pImage->fZoomY);
101 pImage->iWidth = w;
102 pImage->iHeight = h;
103
104 if ((iLoadModifier & CAIRO_DOCK_ANIMATED_IMAGE) && h != 0)
105 {
106 //g_print ("%dx%d\n", (int)w, (int)h);
107 if (w >= 2*h) // we need at least 2 frames (Note: we assume that frames are wide).
108 {
109 if ((int)w % (int)h == 0) // w = k*h
110 {
111 pImage->iNbFrames = w / h;
112 }
113 else if (w > 2 * h) // if we're pretty sure this image is an animated one, try to be smart, to handle the case of non-square frames.
114 {
115 // assume we have wide frames => w > h
116 int w_ = h+1;
117 do
118 {
119 //g_print (" %d/%d\n", w_, (int)w);
120 if ((int)w % w_ == 0)
121 {
122 pImage->iNbFrames = w / w_;
123 break;
124 }
125 w_ ++;
126 } while (w_ < w / 2);
127 }
128 }
129 //g_print ("CAIRO_DOCK_ANIMATED_IMAGE -> %d frames\n", pImage->iNbFrames);
130 if (pImage->iNbFrames != 0)
131 {
132 pImage->fDeltaFrame = 1. / pImage->iNbFrames; // default value
133 gettimeofday (&pImage->time, NULL);
134 }
135 }
136
137 if (fAlpha < 1 && pImage->pSurface != NULL)
138 {
139 cairo_surface_t *pNewSurfaceAlpha = cairo_dock_create_blank_surface (
140 w,
141 h);
142 cairo_t *pCairoContext = cairo_create (pNewSurfaceAlpha);
143
144 cairo_set_source_surface (pCairoContext, pImage->pSurface, 0, 0);
145 cairo_paint_with_alpha (pCairoContext, fAlpha);
146 cairo_destroy (pCairoContext);
147
148 cairo_surface_destroy (pImage->pSurface);
149 pImage->pSurface = pNewSurfaceAlpha;
150 }
151
152 if (g_bUseOpenGL)
153 pImage->iTexture = cairo_dock_create_texture_from_surface (pImage->pSurface);
154
155 g_free (cImagePath);
156 }
157
cairo_dock_load_image_buffer_from_surface(CairoDockImageBuffer * pImage,cairo_surface_t * pSurface,int iWidth,int iHeight)158 void cairo_dock_load_image_buffer_from_surface (CairoDockImageBuffer *pImage, cairo_surface_t *pSurface, int iWidth, int iHeight)
159 {
160 if ((iWidth == 0 || iHeight == 0) && pSurface != NULL) // should never happen, but just in case, prevent any inconsistency.
161 {
162 cd_warning ("An image has an invalid size, will not be loaded.");
163 pSurface = NULL;
164 }
165 pImage->pSurface = pSurface;
166 pImage->iWidth = iWidth;
167 pImage->iHeight = iHeight;
168 pImage->fZoomX = 1.;
169 pImage->fZoomY = 1.;
170 if (g_bUseOpenGL)
171 pImage->iTexture = cairo_dock_create_texture_from_surface (pImage->pSurface);
172 }
173
cairo_dock_load_image_buffer_from_texture(CairoDockImageBuffer * pImage,GLuint iTexture,int iWidth,int iHeight)174 void cairo_dock_load_image_buffer_from_texture (CairoDockImageBuffer *pImage, GLuint iTexture, int iWidth, int iHeight)
175 {
176 pImage->iTexture = iTexture;
177 pImage->iWidth = iWidth;
178 pImage->iHeight = iHeight;
179 pImage->fZoomX = 1.;
180 pImage->fZoomY = 1.;
181 }
182
cairo_dock_create_image_buffer(const gchar * cImageFile,int iWidth,int iHeight,CairoDockLoadImageModifier iLoadModifier)183 CairoDockImageBuffer *cairo_dock_create_image_buffer (const gchar *cImageFile, int iWidth, int iHeight, CairoDockLoadImageModifier iLoadModifier)
184 {
185 CairoDockImageBuffer *pImage = g_new0 (CairoDockImageBuffer, 1);
186
187 cairo_dock_load_image_buffer (pImage, cImageFile, iWidth, iHeight, iLoadModifier);
188
189 return pImage;
190 }
191
cairo_dock_unload_image_buffer(CairoDockImageBuffer * pImage)192 void cairo_dock_unload_image_buffer (CairoDockImageBuffer *pImage)
193 {
194 if (pImage->pSurface != NULL)
195 {
196 cairo_surface_destroy (pImage->pSurface);
197 }
198 if (pImage->iTexture != 0)
199 {
200 _cairo_dock_delete_texture (pImage->iTexture);
201 }
202 memset (pImage, 0, sizeof (CairoDockImageBuffer));
203 }
204
cairo_dock_free_image_buffer(CairoDockImageBuffer * pImage)205 void cairo_dock_free_image_buffer (CairoDockImageBuffer *pImage)
206 {
207 if (pImage == NULL)
208 return;
209 cairo_dock_unload_image_buffer (pImage);
210 g_free (pImage);
211 }
212
cairo_dock_image_buffer_next_frame(CairoDockImageBuffer * pImage)213 void cairo_dock_image_buffer_next_frame (CairoDockImageBuffer *pImage)
214 {
215 if (pImage->iNbFrames == 0)
216 return;
217 struct timeval cur_time = pImage->time;
218 gettimeofday (&pImage->time, NULL);
219 double fElapsedTime = (pImage->time.tv_sec - cur_time.tv_sec) + (pImage->time.tv_usec - cur_time.tv_usec) * 1e-6;
220 double fElapsedFrame = fElapsedTime / pImage->fDeltaFrame;
221 pImage->iCurrentFrame += fElapsedFrame;
222
223 if (pImage->iCurrentFrame > pImage->iNbFrames - 1)
224 pImage->iCurrentFrame -= (pImage->iNbFrames - 1);
225 //g_print (" + %.2f => %.2f -> %.2f\n", fElapsedTime, fElapsedFrame, pImage->iCurrentFrame);
226 }
227
cairo_dock_image_buffer_next_frame_no_loop(CairoDockImageBuffer * pImage)228 gboolean cairo_dock_image_buffer_next_frame_no_loop (CairoDockImageBuffer *pImage)
229 {
230 if (pImage->iNbFrames == 0)
231 return FALSE;
232 double cur_frame = pImage->iCurrentFrame;
233 if (cur_frame == 0) // be sure to start from the first frame, since the image might have been loaded some time ago.
234 cairo_dock_image_buffer_rewind (pImage);
235
236 cairo_dock_image_buffer_next_frame (pImage);
237
238 if (pImage->iCurrentFrame < cur_frame || pImage->iCurrentFrame >= pImage->iNbFrames) // last frame reached -> stay on the last frame
239 {
240 pImage->iCurrentFrame = pImage->iNbFrames;
241 return TRUE;
242 }
243 return FALSE;
244 }
245
cairo_dock_apply_image_buffer_surface_with_offset(const CairoDockImageBuffer * pImage,cairo_t * pCairoContext,double x,double y,double fAlpha)246 void cairo_dock_apply_image_buffer_surface_with_offset (const CairoDockImageBuffer *pImage, cairo_t *pCairoContext, double x, double y, double fAlpha)
247 {
248 if (cairo_dock_image_buffer_is_animated (pImage))
249 {
250 int iFrameWidth = pImage->iWidth / pImage->iNbFrames;
251
252 cairo_save (pCairoContext);
253 cairo_translate (pCairoContext, x, y);
254 cairo_rectangle (pCairoContext, 0, 0, iFrameWidth, pImage->iHeight);
255 cairo_clip (pCairoContext);
256
257 int n = (int) pImage->iCurrentFrame;
258 double dn = pImage->iCurrentFrame - n;
259
260 cairo_set_source_surface (pCairoContext, pImage->pSurface, - n * iFrameWidth, 0.);
261 cairo_paint_with_alpha (pCairoContext, fAlpha * (1 - dn));
262
263 int n2 = n + 1;
264 if (n2 >= pImage->iNbFrames)
265 n2 = 0;
266 cairo_set_source_surface (pCairoContext, pImage->pSurface, - n2 * iFrameWidth, 0.);
267 cairo_paint_with_alpha (pCairoContext, fAlpha * dn);
268
269 cairo_restore (pCairoContext);
270 }
271 else
272 {
273 cairo_set_source_surface (pCairoContext, pImage->pSurface, x, y);
274 cairo_paint_with_alpha (pCairoContext, fAlpha);
275 }
276 }
277
cairo_dock_apply_image_buffer_texture_with_offset(const CairoDockImageBuffer * pImage,double x,double y)278 void cairo_dock_apply_image_buffer_texture_with_offset (const CairoDockImageBuffer *pImage, double x, double y)
279 {
280 glBindTexture (GL_TEXTURE_2D, pImage->iTexture);
281 if (cairo_dock_image_buffer_is_animated (pImage))
282 {
283 int iFrameWidth = pImage->iWidth / pImage->iNbFrames;
284
285 int n = (int) pImage->iCurrentFrame;
286 double dn = pImage->iCurrentFrame - n;
287
288 _cairo_dock_set_blend_alpha ();
289
290 _cairo_dock_set_alpha (1. - dn);
291 _cairo_dock_apply_current_texture_portion_at_size_with_offset ((double)n / pImage->iNbFrames, 0,
292 1. / pImage->iNbFrames, 1.,
293 iFrameWidth, pImage->iHeight,
294 x, y);
295
296 int n2 = n + 1;
297 if (n2 >= pImage->iNbFrames)
298 n2 = 0;
299 _cairo_dock_set_alpha (dn);
300 _cairo_dock_apply_current_texture_portion_at_size_with_offset ((double)n2 / pImage->iNbFrames, 0,
301 1. / pImage->iNbFrames, 1.,
302 iFrameWidth, pImage->iHeight,
303 x, y);
304 }
305 else
306 {
307 _cairo_dock_apply_current_texture_at_size_with_offset (pImage->iWidth, pImage->iHeight, x, y);
308 }
309 }
310
cairo_dock_apply_image_buffer_surface_at_size(const CairoDockImageBuffer * pImage,cairo_t * pCairoContext,int w,int h,double x,double y,double fAlpha)311 void cairo_dock_apply_image_buffer_surface_at_size (const CairoDockImageBuffer *pImage, cairo_t *pCairoContext, int w, int h, double x, double y, double fAlpha)
312 {
313 if (cairo_dock_image_buffer_is_animated (pImage))
314 {
315 int iFrameWidth = pImage->iWidth / pImage->iNbFrames;
316
317 cairo_save (pCairoContext);
318 cairo_translate (pCairoContext, x, y);
319
320 cairo_scale (pCairoContext, (double) w/pImage->iWidth, (double) h/pImage->iHeight);
321
322 cairo_rectangle (pCairoContext, 0, 0, iFrameWidth, pImage->iHeight);
323 cairo_clip (pCairoContext);
324
325 int n = (int) pImage->iCurrentFrame;
326 double dn = pImage->iCurrentFrame - n;
327
328 cairo_set_source_surface (pCairoContext, pImage->pSurface, - n * iFrameWidth, 0.);
329 cairo_paint_with_alpha (pCairoContext, fAlpha * (1 - dn));
330
331 int n2 = n + 1;
332 if (n2 >= pImage->iNbFrames)
333 n2 = 0;
334 cairo_set_source_surface (pCairoContext, pImage->pSurface, - n2 * iFrameWidth, 0.);
335 cairo_paint_with_alpha (pCairoContext, fAlpha * dn);
336
337 cairo_restore (pCairoContext);
338 }
339 else
340 {
341 cairo_save (pCairoContext);
342 cairo_translate (pCairoContext, x, y);
343
344 cairo_scale (pCairoContext, (double) w/pImage->iWidth, (double) h/pImage->iHeight);
345
346 cairo_set_source_surface (pCairoContext, pImage->pSurface, 0, 0);
347 cairo_paint_with_alpha (pCairoContext, fAlpha);
348
349 cairo_restore (pCairoContext);
350 }
351 }
352
cairo_dock_apply_image_buffer_texture_at_size(const CairoDockImageBuffer * pImage,int w,int h,double x,double y)353 void cairo_dock_apply_image_buffer_texture_at_size (const CairoDockImageBuffer *pImage, int w, int h, double x, double y)
354 {
355 glBindTexture (GL_TEXTURE_2D, pImage->iTexture);
356 if (cairo_dock_image_buffer_is_animated (pImage))
357 {
358 int n = (int) pImage->iCurrentFrame;
359 double dn = pImage->iCurrentFrame - n;
360
361 _cairo_dock_set_blend_alpha ();
362
363 _cairo_dock_set_alpha (1. - dn);
364 _cairo_dock_apply_current_texture_portion_at_size_with_offset ((double)n / pImage->iNbFrames, 0,
365 1. / pImage->iNbFrames, 1.,
366 w, h,
367 x, y);
368
369 int n2 = n + 1;
370 if (n2 >= pImage->iNbFrames)
371 n2 = 0;
372 _cairo_dock_set_alpha (dn);
373 _cairo_dock_apply_current_texture_portion_at_size_with_offset ((double)n2 / pImage->iNbFrames, 0,
374 1. / pImage->iNbFrames, 1.,
375 w, h,
376 x, y);
377 }
378 else
379 {
380 _cairo_dock_apply_current_texture_at_size_with_offset (w, h, x, y);
381 }
382 }
383
384
cairo_dock_apply_image_buffer_surface_with_offset_and_limit(const CairoDockImageBuffer * pImage,cairo_t * pCairoContext,double x,double y,double fAlpha,int iMaxWidth)385 void cairo_dock_apply_image_buffer_surface_with_offset_and_limit (const CairoDockImageBuffer *pImage, cairo_t *pCairoContext, double x, double y, double fAlpha, int iMaxWidth)
386 {
387 cairo_set_source_surface (pCairoContext,
388 pImage->pSurface,
389 x,
390 y);
391
392 const double a = .75; // 3/4 plain, 1/4 gradation
393 cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (x,
394 0.,
395 x + iMaxWidth,
396 0.);
397 cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE);
398 cairo_pattern_add_color_stop_rgba (pGradationPattern,
399 0.,
400 0.,
401 0.,
402 0.,
403 fAlpha);
404 cairo_pattern_add_color_stop_rgba (pGradationPattern,
405 a,
406 0.,
407 0.,
408 0.,
409 fAlpha);
410 cairo_pattern_add_color_stop_rgba (pGradationPattern,
411 1.,
412 0.,
413 0.,
414 0.,
415 0.);
416 cairo_mask (pCairoContext, pGradationPattern);
417 cairo_pattern_destroy (pGradationPattern);
418 }
419
cairo_dock_apply_image_buffer_texture_with_limit(const CairoDockImageBuffer * pImage,double fAlpha,int iMaxWidth)420 void cairo_dock_apply_image_buffer_texture_with_limit (const CairoDockImageBuffer *pImage, double fAlpha, int iMaxWidth)
421 {
422 glBindTexture (GL_TEXTURE_2D, pImage->iTexture);
423
424 int w = iMaxWidth, h = pImage->iHeight;
425 double u0 = 0., u1 = (double) w / pImage->iWidth;
426 glBegin(GL_QUAD_STRIP);
427
428 double a = .75; // 3/4 plain, 1/4 gradation
429 a = (double) (floor ((-.5+a)*w)) / w + .5;
430 glColor4f (1., 1., 1., fAlpha);
431 glTexCoord2f(u0, 0); glVertex3f (-.5*w, .5*h, 0.); // top left
432 glTexCoord2f(u0, 1); glVertex3f (-.5*w, -.5*h, 0.); // bottom left
433
434 glTexCoord2f(u1*a, 0); glVertex3f ((-.5+a)*w, .5*h, 0.); // top middle
435 glTexCoord2f(u1*a, 1); glVertex3f ((-.5+a)*w, -.5*h, 0.); // bottom middle
436
437 glColor4f (1., 1., 1., 0.);
438
439 glTexCoord2f(u1, 0); glVertex3f (.5*w, .5*h, 0.); // top right
440 glTexCoord2f(u1, 1); glVertex3f (.5*w, -.5*h, 0.); // bottom right
441
442 glEnd();
443 }
444
445
446
447 // to draw on image buffers
448 static GLuint s_iFboId = 0;
449 static gboolean s_bRedirected = FALSE;
450 static GLuint s_iRedirectedTexture = 0;
451 static gboolean s_bSetPerspective = FALSE;
452 static gint s_iRedirectWidth = 0;
453 static gint s_iRedirectHeight = 0;
454
cairo_dock_create_icon_fbo(void)455 void cairo_dock_create_icon_fbo (void) // it has been found that you get a speed boost if your textures is the same size and you use 1 FBO for them. => c'est le cas general dans le dock. Du coup on est gagnant a ne faire qu'un seul FBO pour toutes les icones.
456 {
457 if (! g_openglConfig.bFboAvailable)
458 return ;
459 g_return_if_fail (s_iFboId == 0);
460
461 glGenFramebuffersEXT(1, &s_iFboId);
462
463 s_iRedirectWidth = myIconsParam.iIconWidth * (1 + myIconsParam.fAmplitude); // use a common size (it can be any size, but we'll often use it to draw on icons, so this choice will often avoid a glScale).
464 s_iRedirectHeight = myIconsParam.iIconHeight * (1 + myIconsParam.fAmplitude);
465 s_iRedirectedTexture = cairo_dock_create_texture_from_raw_data (NULL, s_iRedirectWidth, s_iRedirectHeight);
466 }
467
cairo_dock_destroy_icon_fbo(void)468 void cairo_dock_destroy_icon_fbo (void)
469 {
470 if (s_iFboId == 0)
471 return;
472 glDeleteFramebuffersEXT (1, &s_iFboId);
473 s_iFboId = 0;
474
475 _cairo_dock_delete_texture (s_iRedirectedTexture);
476 s_iRedirectedTexture = 0;
477 }
478
479
cairo_dock_begin_draw_image_buffer_cairo(CairoDockImageBuffer * pImage,gint iRenderingMode,cairo_t * pCairoContext)480 cairo_t *cairo_dock_begin_draw_image_buffer_cairo (CairoDockImageBuffer *pImage, gint iRenderingMode, cairo_t *pCairoContext)
481 {
482 g_return_val_if_fail (pImage->pSurface != NULL, NULL);
483 cairo_t *ctx = pCairoContext;
484 if (! ctx)
485 {
486 ctx = cairo_create (pImage->pSurface);
487 }
488 if (iRenderingMode != 1)
489 {
490 cairo_dock_erase_cairo_context (ctx);
491 }
492 return ctx;
493 }
494
cairo_dock_end_draw_image_buffer_cairo(CairoDockImageBuffer * pImage)495 void cairo_dock_end_draw_image_buffer_cairo (CairoDockImageBuffer *pImage)
496 {
497 if (g_bUseOpenGL)
498 cairo_dock_image_buffer_update_texture (pImage);
499 }
500
501
cairo_dock_begin_draw_image_buffer_opengl(CairoDockImageBuffer * pImage,GldiContainer * pContainer,gint iRenderingMode)502 gboolean cairo_dock_begin_draw_image_buffer_opengl (CairoDockImageBuffer *pImage, GldiContainer *pContainer, gint iRenderingMode)
503 {
504 int iWidth, iHeight;
505 /// TODO: test without FBO and dock when iRenderingMode == 2
506 if (CAIRO_DOCK_IS_DESKLET (pContainer))
507 {
508 if (! gldi_gl_container_make_current (pContainer))
509 {
510 return FALSE;
511 }
512 iWidth = pContainer->iWidth;
513 iHeight = pContainer->iHeight;
514 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
515 }
516 else if (s_iFboId != 0)
517 {
518 // we attach the texture to the FBO.
519 ///if (pContainer->iWidth == 1 && pContainer->iHeight == 1) // container not yet fully resized
520 if (pContainer == NULL)
521 pContainer = g_pPrimaryContainer;
522 if (pContainer->iWidth < pImage->iWidth || pContainer->iHeight < pImage->iHeight)
523 {
524 return FALSE;
525 }
526 iWidth = pImage->iWidth, iHeight = pImage->iHeight;
527 if (! gldi_gl_container_make_current (pContainer))
528 {
529 cd_warning ("couldn't set the opengl context");
530 return FALSE;
531 }
532 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, s_iFboId); // we redirect on our FBO.
533 s_bRedirected = (iRenderingMode == 2);
534 glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
535 GL_COLOR_ATTACHMENT0_EXT,
536 GL_TEXTURE_2D,
537 s_bRedirected ? s_iRedirectedTexture : pImage->iTexture,
538 0); // attach the texture to FBO color attachment point.
539
540 GLenum status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
541 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
542 {
543 cd_warning ("FBO not ready (tex:%d)", pImage->iTexture);
544 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch back to window-system-provided framebuffer
545 glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
546 GL_COLOR_ATTACHMENT0_EXT,
547 GL_TEXTURE_2D,
548 0,
549 0);
550 return FALSE;
551 }
552
553 if (iRenderingMode != 1)
554 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
555 }
556 else
557 return FALSE;
558
559 if (pContainer->bPerspectiveView)
560 {
561 gldi_gl_container_set_ortho_view (pContainer);
562 s_bSetPerspective = TRUE;
563 }
564 else
565 {
566 gldi_gl_container_set_ortho_view (pContainer); // at startup, the context doesn't have any view yet.
567 }
568
569 glLoadIdentity ();
570
571 if (s_bRedirected) // adapt to the size of the redirected texture
572 {
573 glScalef ((double)s_iRedirectWidth/iWidth, (double)s_iRedirectHeight/iHeight, 1.); // no need to revert the y-axis, since we'll apply the redirected texture on the image's texture, which will invert it.
574 glTranslatef (iWidth/2, iHeight/2, - iHeight/2); // translate to the middle of the drawing space.
575 }
576 else
577 {
578 glScalef (1., -1., 1.); // revert y-axis since texture are drawn reversed
579 glTranslatef (iWidth/2, -iHeight/2, - iHeight/2); // translate to the middle of the drawing space.
580 }
581
582 glColor4f (1., 1., 1., 1.);
583
584 return TRUE;
585 }
586
cairo_dock_end_draw_image_buffer_opengl(CairoDockImageBuffer * pImage,GldiContainer * pContainer)587 void cairo_dock_end_draw_image_buffer_opengl (CairoDockImageBuffer *pImage, GldiContainer *pContainer)
588 {
589 g_return_if_fail (pContainer != NULL && pImage->iTexture != 0);
590
591 if (CAIRO_DOCK_IS_DESKLET (pContainer))
592 {
593 // copy in our texture
594 _cairo_dock_enable_texture ();
595 _cairo_dock_set_blend_source ();
596 _cairo_dock_set_alpha (1.);
597 glBindTexture (GL_TEXTURE_2D, pImage->iTexture);
598
599 int iWidth, iHeight; // texture' size
600 iWidth = pImage->iWidth, iHeight = pImage->iHeight;
601 int x = (pContainer->iWidth - iWidth)/2;
602 int y = (pContainer->iHeight - iHeight)/2;
603 glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, x, y, iWidth, iHeight, 0); // target, num mipmap, format, x,y, w,h, border.
604
605 _cairo_dock_disable_texture ();
606 }
607 else if (s_iFboId != 0)
608 {
609 if (s_bRedirected) // copy in our texture
610 {
611 glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
612 GL_COLOR_ATTACHMENT0_EXT,
613 GL_TEXTURE_2D,
614 pImage->iTexture,
615 0); // now we draw in icon's texture.
616 _cairo_dock_enable_texture ();
617 _cairo_dock_set_blend_source ();
618
619 int iWidth, iHeight; // texture' size
620 iWidth = pImage->iWidth, iHeight = pImage->iHeight;
621
622 glLoadIdentity ();
623 glTranslatef (iWidth/2, iHeight/2, - iHeight/2);
624 _cairo_dock_apply_texture_at_size_with_alpha (s_iRedirectedTexture, iWidth, iHeight, 1.);
625
626 _cairo_dock_disable_texture ();
627 s_bRedirected = FALSE;
628 }
629 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch back to window-system-provided framebuffer
630 glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
631 GL_COLOR_ATTACHMENT0_EXT,
632 GL_TEXTURE_2D,
633 0,
634 0); // we detach the texture (precaution).
635 //glGenerateMipmapEXT(GL_TEXTURE_2D); // if we use mipmaps, we need to explicitely generate them when using FBO.
636 }
637
638 if (pContainer && s_bSetPerspective)
639 {
640 gldi_gl_container_set_perspective_view (pContainer);
641 s_bSetPerspective = FALSE;
642 }
643 }
644
cairo_dock_image_buffer_update_texture(CairoDockImageBuffer * pImage)645 void cairo_dock_image_buffer_update_texture (CairoDockImageBuffer *pImage)
646 {
647 if (pImage->iTexture == 0)
648 {
649 pImage->iTexture = cairo_dock_create_texture_from_surface (pImage->pSurface);
650 }
651 else
652 {
653 _cairo_dock_enable_texture ();
654 _cairo_dock_set_blend_source ();
655 _cairo_dock_set_alpha (1.); // full white
656
657 int w = cairo_image_surface_get_width (pImage->pSurface); // extra caution
658 int h = cairo_image_surface_get_height (pImage->pSurface);
659 glBindTexture (GL_TEXTURE_2D, pImage->iTexture);
660
661 glTexParameteri (GL_TEXTURE_2D,
662 GL_TEXTURE_MIN_FILTER,
663 g_bEasterEggs ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
664 if (g_bEasterEggs)
665 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
666 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
667
668 if (g_bEasterEggs)
669 gluBuild2DMipmaps (GL_TEXTURE_2D,
670 4,
671 w,
672 h,
673 GL_BGRA,
674 GL_UNSIGNED_BYTE,
675 cairo_image_surface_get_data (pImage->pSurface));
676 else
677 glTexImage2D (GL_TEXTURE_2D,
678 0,
679 4, // GL_ALPHA / GL_BGRA
680 w,
681 h,
682 0,
683 GL_BGRA, // GL_ALPHA / GL_BGRA
684 GL_UNSIGNED_BYTE,
685 cairo_image_surface_get_data (pImage->pSurface));
686 _cairo_dock_disable_texture ();
687 }
688 }
689
690
cairo_dock_image_buffer_to_pixbuf(CairoDockImageBuffer * pImage,int iWidth,int iHeight)691 GdkPixbuf *cairo_dock_image_buffer_to_pixbuf (CairoDockImageBuffer *pImage, int iWidth, int iHeight)
692 {
693 GdkPixbuf *pixbuf = NULL;
694 int w = iWidth, h = iHeight;
695 if (pImage->iWidth > 0 && pImage->iHeight > 0 && pImage->pSurface != NULL)
696 {
697 cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
698 w,
699 h);
700 cairo_t *pCairoContext = cairo_create (surface);
701 cairo_scale (pCairoContext, (double)w/pImage->iWidth, (double)h/pImage->iHeight);
702 cairo_set_source_surface (pCairoContext, pImage->pSurface, 0., 0.);
703 cairo_paint (pCairoContext);
704 cairo_destroy (pCairoContext);
705 guchar *d, *data = cairo_image_surface_get_data (surface);
706 int r = cairo_image_surface_get_stride (surface);
707
708 // we convert it in a pixbuf.
709 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
710 TRUE,
711 8,
712 w,
713 h);
714 guchar *p, *pixels = gdk_pixbuf_get_pixels (pixbuf);
715 int iNbChannels = gdk_pixbuf_get_n_channels (pixbuf);
716 int iRowstride = gdk_pixbuf_get_rowstride (pixbuf);
717
718 int x, y;
719 int red, green, blue;
720 float fAlphaFactor;
721 for (y = 0; y < h; y ++)
722 {
723 for (x = 0; x < w; x ++)
724 {
725 p = pixels + y * iRowstride + x * iNbChannels;
726 d = data + y * r + x * 4;
727
728 fAlphaFactor = (float) d[3] / 255;
729 if (fAlphaFactor != 0)
730 {
731 red = d[0] / fAlphaFactor;
732 green = d[1] / fAlphaFactor;
733 blue = d[2] / fAlphaFactor;
734 }
735 else
736 {
737 red = blue = green = 0;
738 }
739 p[0] = blue;
740 p[1] = green;
741 p[2] = red;
742 p[3] = d[3];
743 }
744 }
745
746 cairo_surface_destroy (surface);
747 }
748 return pixbuf;
749 }
750