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