Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include "ogl_spritedevicehelper.hxx"
11 : #include "ogl_spritecanvas.hxx"
12 : #include "ogl_canvasbitmap.hxx"
13 : #include "ogl_canvastools.hxx"
14 : #include "ogl_canvascustomsprite.hxx"
15 : #include "ogl_texturecache.hxx"
16 :
17 : #include <canvas/verbosetrace.hxx>
18 : #include <basegfx/tools/canvastools.hxx>
19 : #include <basegfx/tools/unopolypolygon.hxx>
20 :
21 : #include <osl/mutex.hxx>
22 : #include <rtl/instance.hxx>
23 : #include <com/sun/star/uno/Reference.hxx>
24 : #include <com/sun/star/lang/NoSupportException.hpp>
25 : #include <com/sun/star/rendering/XColorSpace.hpp>
26 : #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
27 :
28 : #include <vcl/sysdata.hxx>
29 : #include <vcl/syschild.hxx>
30 : #include <vcl/canvastools.hxx>
31 : #include <toolkit/helper/vclunohelper.hxx>
32 :
33 : #define GL_GLEXT_PROTOTYPES
34 : #include <GL/gl.h>
35 : #include <GL/glu.h>
36 : #include <GL/glext.h>
37 :
38 : namespace unx
39 : {
40 : #include <X11/keysym.h>
41 : #include <X11/X.h>
42 : #include <GL/glx.h>
43 : #include <GL/glxext.h>
44 : }
45 :
46 :
47 : using namespace ::com::sun::star;
48 :
49 : static bool lcl_bErrorTriggered=false;
50 0 : static int lcl_XErrorHandler( unx::Display*, unx::XErrorEvent* )
51 : {
52 0 : lcl_bErrorTriggered = true;
53 0 : return 0;
54 : }
55 :
56 : /** Dummy vertex processing. Simply uses default pipeline for vertex
57 : transformation, and forwards texture coodinates to fragment shader
58 : */
59 : static const char dummyVertexShader[] =
60 : {
61 : "varying vec2 v_textureCoords2d; "
62 : "void main(void) "
63 : "{ "
64 : " gl_Position = ftransform(); "
65 : " v_textureCoords2d = gl_MultiTexCoord0.st; "
66 : "} "
67 : };
68 :
69 : /** Two-color linear gradient
70 : */
71 : static const char linearTwoColorGradientFragmentShader[] =
72 : {
73 : "#version 120 \n"
74 : "uniform vec4 v_startColor4d; "
75 : "uniform vec4 v_endColor4d; "
76 : "uniform mat3x2 m_transform; "
77 : "varying vec2 v_textureCoords2d; "
78 : "void main(void) "
79 : "{ "
80 : " gl_FragColor = mix(v_startColor4d, "
81 : " v_endColor4d, "
82 : " clamp( "
83 : " (m_transform * vec3(v_textureCoords2d,1)).s, "
84 : " 0.0, 1.0)); "
85 : "} "
86 : };
87 :
88 : /** N-color linear gradient
89 : */
90 : static const char linearMultiColorGradientFragmentShader[] =
91 : {
92 : "#version 120 \n"
93 : "uniform int i_nColors; "
94 : "uniform sampler1D t_colorArray4d; "
95 : "uniform sampler1D t_stopArray1d; "
96 : "uniform mat3x2 m_transform; "
97 : "varying vec2 v_textureCoords2d; "
98 : " "
99 : "int findBucket(float t) "
100 : "{ "
101 : " int nMinBucket=0; "
102 : " while( nMinBucket < i_nColors && "
103 : " texture1D(t_stopArray1d, nMinBucket).s < t ) "
104 : " ++nMinBucket; "
105 : " return max(nMinBucket-1,0); "
106 : "} "
107 : " "
108 : "void main(void) "
109 : "{ "
110 : " const float fAlpha = "
111 : " clamp( (m_transform * vec3(v_textureCoords2d,1)).s, "
112 : " 0.0, 1.0 ); "
113 : " "
114 : " const int nMinBucket=findBucket( fAlpha ); "
115 : " "
116 : " const float fLerp = "
117 : " (fAlpha-texture1D(t_stopArray1d, nMinBucket).s) / "
118 : " (texture1D(t_stopArray1d, nMinBucket+1).s - "
119 : " texture1D(t_stopArray1d, nMinBucket).s); "
120 : " "
121 : " gl_FragColor = mix(texture1D(t_colorArray4d, nMinBucket), "
122 : " texture1D(t_colorArray4d, nMinBucket+1), "
123 : " fLerp); "
124 : "} "
125 : };
126 :
127 : /** Two-color radial gradient
128 : */
129 : static const char radialTwoColorGradientFragmentShader[] =
130 : {
131 : "#version 120 \n"
132 : "uniform vec4 v_startColor4d; "
133 : "uniform vec4 v_endColor4d; "
134 : "uniform mat3x2 m_transform; "
135 : "varying vec2 v_textureCoords2d; "
136 : "const vec2 v_center2d = vec2(0,0); "
137 : "void main(void) "
138 : "{ "
139 : " gl_FragColor = mix(v_startColor4d, "
140 : " v_endColor4d, "
141 : " 1.0 - distance( "
142 : " vec2( "
143 : " m_transform * vec3(v_textureCoords2d,1)), "
144 : " v_center2d)); "
145 : "} "
146 : };
147 :
148 : /** Multi-color radial gradient
149 : */
150 : static const char radialMultiColorGradientFragmentShader[] =
151 : {
152 : "#version 120 \n"
153 : "uniform int i_nColors; "
154 : "uniform sampler1D t_colorArray4d; "
155 : "uniform sampler1D t_stopArray1d; "
156 : "uniform mat3x2 m_transform; "
157 : "varying vec2 v_textureCoords2d; "
158 : "const vec2 v_center2d = vec2(0,0); "
159 : " "
160 : "int findBucket(float t) "
161 : "{ "
162 : " int nMinBucket=0; "
163 : " while( nMinBucket < i_nColors && "
164 : " texture1D(t_stopArray1d, nMinBucket).s < t ) "
165 : " ++nMinBucket; "
166 : " return max(nMinBucket-1,0); "
167 : "} "
168 : " "
169 : "void main(void) "
170 : "{ "
171 : " const float fAlpha = "
172 : " clamp( 1.0 - distance( "
173 : " vec2( m_transform * vec3(v_textureCoords2d,1)), "
174 : " v_center2d), "
175 : " 0.0, 1.0 ); "
176 : " "
177 : " const int nMinBucket=findBucket( fAlpha ); "
178 : " "
179 : " const float fLerp = "
180 : " (fAlpha-texture1D(t_stopArray1d, nMinBucket).s) / "
181 : " (texture1D(t_stopArray1d, nMinBucket+1).s - "
182 : " texture1D(t_stopArray1d, nMinBucket).s); "
183 : " "
184 : " gl_FragColor = mix(texture1D(t_colorArray4d, nMinBucket), "
185 : " texture1D(t_colorArray4d, nMinBucket+1), "
186 : " fLerp); "
187 : "} "
188 : };
189 :
190 : /** Two-color rectangular gradient
191 : */
192 : static const char rectangularTwoColorGradientFragmentShader[] =
193 : {
194 : "#version 120 \n"
195 : "uniform vec4 v_startColor4d; "
196 : "uniform vec4 v_endColor4d; "
197 : "uniform mat3x2 m_transform; "
198 : "varying vec2 v_textureCoords2d; "
199 : "void main(void) "
200 : "{ "
201 : " const vec2 v = abs( vec2(m_transform * vec3(v_textureCoords2d,1)) ); "
202 : " const float t = max(v.x, v.y); "
203 : " gl_FragColor = mix(v_startColor4d, "
204 : " v_endColor4d, "
205 : " 1.0-t); "
206 : "} "
207 : };
208 :
209 : /** Multi-color rectangular gradient
210 : */
211 : static const char rectangularMultiColorGradientFragmentShader[] =
212 : {
213 : "#version 120 \n"
214 : "uniform int i_nColors; "
215 : "uniform sampler1D t_colorArray4d; "
216 : "uniform sampler1D t_stopArray1d; "
217 : "uniform mat3x2 m_transform; "
218 : "varying vec2 v_textureCoords2d; "
219 : " "
220 : "int findBucket(float t) "
221 : "{ "
222 : " int nMinBucket=0; "
223 : " while( nMinBucket < i_nColors && "
224 : " texture1D(t_stopArray1d, nMinBucket).s < t ) "
225 : " ++nMinBucket; "
226 : " return max(nMinBucket-1,0); "
227 : "} "
228 : " "
229 : "void main(void) "
230 : "{ "
231 : " const vec2 v = abs( vec2(m_transform * vec3(v_textureCoords2d,1)) ); "
232 : " const float fAlpha = 1 - max(v.x, v.y); "
233 : " "
234 : " const int nMinBucket=findBucket( fAlpha ); "
235 : " "
236 : " const float fLerp = "
237 : " (fAlpha-texture1D(t_stopArray1d, nMinBucket).s) / "
238 : " (texture1D(t_stopArray1d, nMinBucket+1).s - "
239 : " texture1D(t_stopArray1d, nMinBucket).s); "
240 : " "
241 : " gl_FragColor = mix(texture1D(t_colorArray4d, nMinBucket), "
242 : " texture1D(t_colorArray4d, nMinBucket+1), "
243 : " fLerp); "
244 : "} "
245 : };
246 :
247 0 : static void initContext()
248 : {
249 : // need the backside for mirror effects
250 0 : glDisable(GL_CULL_FACE);
251 :
252 : // no perspective, we're 2D
253 0 : glMatrixMode(GL_PROJECTION);
254 0 : glLoadIdentity();
255 :
256 : // misc preferences
257 0 : glEnable(GL_POINT_SMOOTH);
258 0 : glEnable(GL_LINE_SMOOTH);
259 0 : glEnable(GL_POLYGON_SMOOTH);
260 0 : glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
261 0 : glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
262 0 : glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
263 0 : glShadeModel(GL_FLAT);
264 0 : }
265 :
266 0 : static void initTransformation(const ::Size& rSize, bool bMirror=false)
267 : {
268 : // use whole window
269 : glViewport( 0,0,
270 0 : (GLsizei)rSize.Width(),
271 0 : (GLsizei)rSize.Height() );
272 :
273 : // model coordinate system is already in device pixel
274 0 : glMatrixMode(GL_MODELVIEW);
275 0 : glLoadIdentity();
276 0 : glTranslated(-1.0, (bMirror ? -1.0 : 1.0), 0.0);
277 0 : glScaled( 2.0 / rSize.Width(),
278 0 : (bMirror ? 2.0 : -2.0) / rSize.Height(),
279 0 : 1.0 );
280 :
281 : // clear to black
282 0 : glClearColor(0,0,0,0);
283 0 : glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
284 0 : }
285 :
286 0 : static boost::shared_ptr<SystemChildWindow> createChildWindow( unx::XVisualInfo*& viWin,
287 : unx::XVisualInfo*& viPB,
288 : void*& fbConfig,
289 : Window& rWindow,
290 : unx::Display* pDisplay,
291 : int nScreen )
292 : {
293 : // select appropriate visual
294 : static int winAttrList3[] =
295 : {
296 : GLX_RGBA,//only TrueColor or DirectColor
297 : //single buffered
298 : GLX_RED_SIZE,4,//use the maximum red bits, with a minimum of 4 bits
299 : GLX_GREEN_SIZE,4,//use the maximum green bits, with a minimum of 4 bits
300 : GLX_BLUE_SIZE,4,//use the maximum blue bits, with a minimum of 4 bits
301 : GLX_DEPTH_SIZE,0,//no depth buffer
302 : None
303 : };
304 : static int pBufAttrList3[] =
305 : {
306 : GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
307 : GLX_RED_SIZE,4,//use the maximum red bits, with a minimum of 4 bits
308 : GLX_GREEN_SIZE,4,//use the maximum green bits, with a minimum of 4 bits
309 : GLX_BLUE_SIZE,4,//use the maximum blue bits, with a minimum of 4 bits
310 : GLX_ALPHA_SIZE,4,
311 : GLX_DEPTH_SIZE,0,//no depth buffer
312 : GLX_RENDER_TYPE, GLX_RGBA_BIT,
313 : GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
314 : None
315 : };
316 : static int winAttrList2[] =
317 : {
318 : GLX_RGBA,//only TrueColor or DirectColor
319 : /// single buffered
320 : GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
321 : GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
322 : GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
323 : GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
324 : None
325 : };
326 : static int pBufAttrList2[] =
327 : {
328 : GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
329 : GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
330 : GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
331 : GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
332 : GLX_ALPHA_SIZE,4,
333 : GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
334 : GLX_RENDER_TYPE, GLX_RGBA_BIT,
335 : GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
336 : None
337 : };
338 : static int winAttrList1[] =
339 : {
340 : GLX_RGBA,//only TrueColor or DirectColor
341 : GLX_DOUBLEBUFFER,/// only double buffer
342 : GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
343 : GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
344 : GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
345 : GLX_DEPTH_SIZE,0,/// no depth buffer
346 : None
347 : };
348 : static int pBufAttrList1[] =
349 : {
350 : GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
351 : GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
352 : GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
353 : GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
354 : GLX_ALPHA_SIZE,4,
355 : GLX_DEPTH_SIZE,0,/// no depth buffer
356 : GLX_RENDER_TYPE, GLX_RGBA_BIT,
357 : GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
358 : None
359 : };
360 : static int winAttrList0[] =
361 : {
362 : GLX_RGBA,//only TrueColor or DirectColor
363 : GLX_DOUBLEBUFFER,// only double buffer
364 : GLX_RED_SIZE,4,// use the maximum red bits, with a minimum of 4 bits
365 : GLX_GREEN_SIZE,4,// use the maximum green bits, with a minimum of 4 bits
366 : GLX_BLUE_SIZE,4,// use the maximum blue bits, with a minimum of 4 bits
367 : GLX_DEPTH_SIZE,1,// use the maximum depth bits, making sure there is a depth buffer
368 : None
369 : };
370 : static int pBufAttrList0[] =
371 : {
372 : GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
373 : GLX_RED_SIZE,4,// use the maximum red bits, with a minimum of 4 bits
374 : GLX_GREEN_SIZE,4,// use the maximum green bits, with a minimum of 4 bits
375 : GLX_BLUE_SIZE,4,// use the maximum blue bits, with a minimum of 4 bits
376 : GLX_ALPHA_SIZE,4,
377 : GLX_DEPTH_SIZE,1,// use the maximum depth bits, making sure there is a depth buffer
378 : GLX_RENDER_TYPE, GLX_RGBA_BIT,
379 : GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
380 : None
381 : };
382 : static int* winAttrTable[] =
383 : {
384 : winAttrList0,
385 : winAttrList1,
386 : winAttrList2,
387 : winAttrList3,
388 : NULL
389 : };
390 : static int* pBufAttrTable[] =
391 : {
392 : pBufAttrList0,
393 : pBufAttrList1,
394 : pBufAttrList2,
395 : pBufAttrList3,
396 : NULL
397 : };
398 0 : int** pWinAttributeTable = winAttrTable;
399 0 : int** pBufAttributeTable = pBufAttrTable;
400 :
401 0 : boost::shared_ptr<SystemChildWindow> pResult;
402 0 : unx::GLXFBConfig* fbConfigs=NULL;
403 : int nConfigs, nVal;
404 0 : while( *pWinAttributeTable && *pBufAttributeTable )
405 : {
406 : // try to find a window visual for the current set of
407 : // attributes
408 : viWin = unx::glXChooseVisual( pDisplay,
409 : nScreen,
410 0 : *pWinAttributeTable );
411 0 : if( viWin )
412 : {
413 : // try to find a framebuffer config for the current set of
414 : // attributes
415 : fbConfigs = glXChooseFBConfig( pDisplay,
416 : nScreen,
417 : *pBufAttributeTable,
418 0 : &nConfigs );
419 : // don't use glXGetFBConfigs, that does not list alpha-configs
420 : // fbConfigs = unx::glXGetFBConfigs(pDisplay, nScreen, &nConfigs);
421 0 : for(int i=0; i<nConfigs; i++)
422 : {
423 0 : viPB = glXGetVisualFromFBConfig(pDisplay, fbConfigs[i]);
424 0 : if( viPB && viPB->visualid != viWin->visualid )
425 : {
426 : glXGetFBConfigAttrib(pDisplay,
427 0 : fbConfigs[i],
428 : GLX_DRAWABLE_TYPE,
429 0 : &nVal);
430 :
431 0 : if( (GLX_PBUFFER_BIT|GLX_WINDOW_BIT|GLX_PIXMAP_BIT)
432 0 : == (nVal & (GLX_PBUFFER_BIT|GLX_WINDOW_BIT|GLX_PIXMAP_BIT)) )
433 : {
434 : SystemWindowData winData;
435 0 : winData.nSize = sizeof(winData);
436 : SAL_INFO("canvas.ogl", "using VisualID " << viWin->visualid << " for OpenGL canvas");
437 0 : winData.pVisual = (void*)(viWin->visual);
438 0 : pResult.reset( new SystemChildWindow(&rWindow, 0, &winData, false) );
439 :
440 0 : if( pResult->GetSystemData() )
441 : {
442 0 : fbConfig = &fbConfigs[i];
443 0 : return pResult;
444 : }
445 :
446 0 : pResult.reset();
447 : }
448 :
449 0 : XFree(viPB);
450 : }
451 : }
452 :
453 0 : XFree(viWin);
454 : }
455 :
456 0 : ++pWinAttributeTable;
457 0 : ++pBufAttributeTable;
458 : }
459 :
460 0 : return pResult;
461 : }
462 :
463 :
464 : namespace oglcanvas
465 : {
466 : /** Compile shader program
467 :
468 : Code courtesy rodo
469 : */
470 0 : void SpriteDeviceHelper::compileShader(unsigned int& o_rShaderHandle,
471 : unsigned int eShaderType,
472 : const char* pShaderSourceCode)
473 : {
474 : GLint nCompileStatus;
475 : char log[1024];
476 :
477 0 : o_rShaderHandle = glCreateShader( eShaderType );
478 0 : glShaderSource( o_rShaderHandle, 1, &pShaderSourceCode, NULL );
479 0 : glCompileShader( o_rShaderHandle );
480 0 : glGetShaderInfoLog( o_rShaderHandle, sizeof(log), NULL, log );
481 : SAL_INFO("canvas.ogl", "shader compile log: " << log);
482 :
483 0 : glGetShaderiv( o_rShaderHandle, GL_COMPILE_STATUS, &nCompileStatus );
484 0 : if( !nCompileStatus )
485 : {
486 0 : glDeleteShader(o_rShaderHandle);
487 0 : o_rShaderHandle=0;
488 : }
489 0 : }
490 :
491 : /** Link vertex & fragment shaders
492 :
493 : Code courtesy rodo
494 : */
495 0 : void SpriteDeviceHelper::linkShaders(unsigned int& o_rProgramHandle,
496 : unsigned int nVertexProgramId,
497 : unsigned int nFragmentProgramId)
498 : {
499 0 : if( !nVertexProgramId || !nFragmentProgramId )
500 0 : return;
501 :
502 0 : o_rProgramHandle = glCreateProgram();
503 0 : glAttachShader( o_rProgramHandle, nVertexProgramId );
504 0 : glAttachShader( o_rProgramHandle, nFragmentProgramId );
505 :
506 : char log[1024];
507 : GLint nProgramLinked;
508 :
509 0 : glLinkProgram( o_rProgramHandle );
510 0 : glGetProgramInfoLog( o_rProgramHandle, sizeof(log), NULL, log );
511 : SAL_INFO("canvas.ogl", "shader program link log: " << log);
512 0 : glGetProgramiv( o_rProgramHandle, GL_LINK_STATUS, &nProgramLinked );
513 :
514 0 : if( !nProgramLinked )
515 : {
516 0 : glDeleteProgram(o_rProgramHandle);
517 0 : o_rProgramHandle=0;
518 : }
519 : }
520 :
521 0 : SpriteDeviceHelper::SpriteDeviceHelper() :
522 : mpDevice(NULL),
523 : mpSpriteCanvas(NULL),
524 : maActiveSprites(),
525 : maLastUpdate(),
526 : mpChildWindow(),
527 : mpDisplay(NULL),
528 : mpGLContext(NULL),
529 : mpGLPBufContext(NULL),
530 : mpFBConfig(NULL),
531 0 : mpTextureCache(new TextureCache()),
532 : mnDummyVertexProgram(0),
533 : mnLinearTwoColorGradientFragmentProgram(0),
534 : mnLinearMultiColorGradientFragmentProgram(0),
535 : mnRadialTwoColorGradientFragmentProgram(0),
536 : mnRadialMultiColorGradientFragmentProgram(0),
537 : mnRectangularTwoColorGradientFragmentProgram(0),
538 : mnRectangularMultiColorGradientFragmentProgram(0),
539 : mnLinearTwoColorGradientProgram(0),
540 : mnLinearMultiColorGradientProgram(0),
541 : mnRadialTwoColorGradientProgram(0),
542 : mnRadialMultiColorGradientProgram(0),
543 : mnRectangularTwoColorGradientProgram(0),
544 0 : mnRectangularMultiColorGradientProgram(0)
545 0 : {}
546 :
547 0 : void SpriteDeviceHelper::init( Window& rWindow,
548 : SpriteCanvas& rSpriteCanvas,
549 : const awt::Rectangle& rViewArea )
550 : {
551 0 : mpSpriteCanvas = &rSpriteCanvas;
552 :
553 : rSpriteCanvas.setWindow(
554 : uno::Reference<awt::XWindow2>(
555 : VCLUnoHelper::GetInterface(&rWindow),
556 0 : uno::UNO_QUERY_THROW) );
557 :
558 : // init OpenGL
559 0 : const SystemEnvData* sysData(rWindow.GetSystemData());
560 0 : unx::Display* pDisplay=reinterpret_cast<unx::Display*>(sysData->pDisplay);
561 0 : mpDisplay=pDisplay;
562 0 : if( !unx::glXQueryExtension(pDisplay, NULL, NULL) )
563 0 : return;
564 :
565 0 : unx::Window xWindow = sysData->aWindow;
566 : unx::XWindowAttributes xAttr;
567 0 : unx::XGetWindowAttributes( pDisplay, xWindow, &xAttr );
568 0 : int nScreen = XScreenNumberOfScreen( xAttr.screen );
569 :
570 0 : unx::Window childXWindow=0;
571 0 : unx::XVisualInfo* viWin=NULL;
572 0 : unx::XVisualInfo* viPB=NULL;
573 0 : mpChildWindow=createChildWindow(viWin,viPB,mpFBConfig,
574 0 : rWindow,pDisplay,nScreen);
575 :
576 : // tweak SysChild window to act as an input-transparent
577 : // overlay
578 0 : if( mpChildWindow )
579 : {
580 0 : childXWindow=mpChildWindow->GetSystemData()->aWindow;
581 0 : mpChildWindow->SetMouseTransparent(true);
582 0 : mpChildWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
583 0 : mpChildWindow->EnableEraseBackground(false);
584 0 : mpChildWindow->SetControlForeground();
585 0 : mpChildWindow->SetControlBackground();
586 0 : mpChildWindow->EnablePaint(false);
587 :
588 : unx::GLXContext pContext1 =
589 : glXCreateContext(pDisplay,
590 : viWin,
591 : 0,
592 0 : GL_TRUE);
593 0 : mpGLContext = pContext1;
594 :
595 : unx::GLXContext pContext2 =
596 : glXCreateContext( pDisplay,
597 : viPB,
598 : pContext1,
599 0 : GL_TRUE );
600 0 : mpGLPBufContext = pContext2;
601 :
602 0 : XFree(viWin);
603 0 : XFree(viPB);
604 :
605 0 : if( !glXMakeCurrent( pDisplay,
606 : childXWindow,
607 0 : pContext1) )
608 : {
609 0 : glXDestroyContext(pDisplay, pContext1);
610 0 : glXDestroyContext(pDisplay, pContext2);
611 0 : throw lang::NoSupportException("Could not select OpenGL context!", NULL);
612 : }
613 :
614 0 : const GLubyte* extensions=glGetString( GL_EXTENSIONS );
615 0 : if( gluCheckExtension((const GLubyte*)"GLX_SGI_swap_control", extensions) )
616 : {
617 : // try to enable vsync
618 : typedef GLint (*glXSwapIntervalProc)(GLint);
619 : glXSwapIntervalProc glXSwapInterval =
620 0 : (glXSwapIntervalProc) unx::glXGetProcAddress((const GLubyte*)"glXSwapIntervalSGI");
621 0 : if( glXSwapInterval )
622 : {
623 : int (*oldHandler)(unx::Display*, unx::XErrorEvent*);
624 :
625 : // synchronize on global mutex - no other ogl
626 : // canvas instance permitted to enter here
627 : {
628 0 : ::osl::MutexGuard aGuard( *::osl::Mutex::getGlobalMutex() );
629 :
630 : // replace error handler temporarily
631 0 : oldHandler = unx::XSetErrorHandler( lcl_XErrorHandler );
632 :
633 0 : lcl_bErrorTriggered = false;
634 :
635 : // Note: if this fails, so be it. Buggy
636 : // drivers will then not have vsync.
637 0 : glXSwapInterval(1);
638 :
639 : // sync so that we possibly get an XError
640 0 : unx::glXWaitGL();
641 0 : XSync(pDisplay, false);
642 :
643 0 : unx::XSetErrorHandler( oldHandler );
644 : }
645 : }
646 : }
647 :
648 : // init window context
649 0 : initContext();
650 :
651 : // compile & link shaders - code courtesy rodo
652 : compileShader(mnDummyVertexProgram,
653 : GL_VERTEX_SHADER,
654 0 : dummyVertexShader);
655 : compileShader(mnLinearTwoColorGradientFragmentProgram,
656 : GL_FRAGMENT_SHADER,
657 0 : linearTwoColorGradientFragmentShader);
658 : compileShader(mnLinearMultiColorGradientFragmentProgram,
659 : GL_FRAGMENT_SHADER,
660 0 : linearMultiColorGradientFragmentShader);
661 : compileShader(mnRadialTwoColorGradientFragmentProgram,
662 : GL_FRAGMENT_SHADER,
663 0 : radialTwoColorGradientFragmentShader);
664 : compileShader(mnRadialMultiColorGradientFragmentProgram,
665 : GL_FRAGMENT_SHADER,
666 0 : radialMultiColorGradientFragmentShader);
667 : compileShader(mnRectangularTwoColorGradientFragmentProgram,
668 : GL_FRAGMENT_SHADER,
669 0 : rectangularTwoColorGradientFragmentShader);
670 : compileShader(mnRectangularMultiColorGradientFragmentProgram,
671 : GL_FRAGMENT_SHADER,
672 0 : rectangularMultiColorGradientFragmentShader);
673 : linkShaders(mnLinearTwoColorGradientProgram,
674 : mnDummyVertexProgram,
675 0 : mnLinearTwoColorGradientFragmentProgram);
676 : linkShaders(mnLinearMultiColorGradientProgram,
677 : mnDummyVertexProgram,
678 0 : mnLinearMultiColorGradientFragmentProgram);
679 : linkShaders(mnRadialTwoColorGradientProgram,
680 : mnDummyVertexProgram,
681 0 : mnRadialTwoColorGradientFragmentProgram);
682 : linkShaders(mnRadialMultiColorGradientProgram,
683 : mnDummyVertexProgram,
684 0 : mnRadialMultiColorGradientFragmentProgram);
685 : linkShaders(mnRectangularTwoColorGradientProgram,
686 : mnDummyVertexProgram,
687 0 : mnRectangularTwoColorGradientFragmentProgram);
688 : linkShaders(mnRectangularMultiColorGradientProgram,
689 : mnDummyVertexProgram,
690 0 : mnRectangularMultiColorGradientFragmentProgram);
691 :
692 0 : glXMakeCurrent(pDisplay, None, NULL);
693 : }
694 :
695 0 : if( !mpGLContext || glGetError() != GL_NO_ERROR )
696 : throw lang::NoSupportException(
697 0 : "Could not create OpenGL context, or an error occurred doing so!", NULL);
698 :
699 0 : notifySizeUpdate(rViewArea);
700 0 : mpChildWindow->Show();
701 : // TODO(E3): check for GL_ARB_imaging extension
702 : }
703 :
704 0 : void SpriteDeviceHelper::disposing()
705 : {
706 : // release all references
707 0 : mpSpriteCanvas = NULL;
708 0 : mpDevice = NULL;
709 0 : mpTextureCache.reset();
710 :
711 0 : if( mpGLContext )
712 : {
713 0 : glDeleteProgram( mnRectangularTwoColorGradientProgram );
714 0 : glDeleteProgram( mnRectangularMultiColorGradientProgram );
715 0 : glDeleteProgram( mnRadialTwoColorGradientProgram );
716 0 : glDeleteProgram( mnRadialMultiColorGradientProgram );
717 0 : glDeleteProgram( mnLinearTwoColorGradientProgram );
718 0 : glDeleteProgram( mnLinearMultiColorGradientProgram );
719 0 : glDeleteShader( mnRectangularTwoColorGradientFragmentProgram );
720 0 : glDeleteShader( mnRectangularMultiColorGradientFragmentProgram );
721 0 : glDeleteShader( mnRadialTwoColorGradientFragmentProgram );
722 0 : glDeleteShader( mnRadialMultiColorGradientFragmentProgram );
723 0 : glDeleteShader( mnLinearTwoColorGradientFragmentProgram );
724 0 : glDeleteShader( mnLinearMultiColorGradientFragmentProgram );
725 0 : glDeleteShader( mnDummyVertexProgram );
726 :
727 : glXDestroyContext(reinterpret_cast<unx::Display*>(mpDisplay),
728 0 : reinterpret_cast<unx::GLXContext>(mpGLContext));
729 : }
730 :
731 0 : mpDisplay = NULL;
732 0 : mpGLContext = NULL;
733 0 : mpChildWindow.reset();
734 0 : }
735 :
736 0 : geometry::RealSize2D SpriteDeviceHelper::getPhysicalResolution()
737 : {
738 0 : if( !mpChildWindow )
739 0 : return ::canvas::tools::createInfiniteSize2D(); // we're disposed
740 :
741 : // Map a one-by-one millimeter box to pixel
742 0 : const MapMode aOldMapMode( mpChildWindow->GetMapMode() );
743 0 : mpChildWindow->SetMapMode( MapMode(MAP_MM) );
744 0 : const Size aPixelSize( mpChildWindow->LogicToPixel(Size(1,1)) );
745 0 : mpChildWindow->SetMapMode( aOldMapMode );
746 :
747 0 : return ::vcl::unotools::size2DFromSize( aPixelSize );
748 : }
749 :
750 0 : geometry::RealSize2D SpriteDeviceHelper::getPhysicalSize()
751 : {
752 0 : if( !mpChildWindow )
753 0 : return ::canvas::tools::createInfiniteSize2D(); // we're disposed
754 :
755 : // Map the pixel dimensions of the output window to millimeter
756 0 : const MapMode aOldMapMode( mpChildWindow->GetMapMode() );
757 0 : mpChildWindow->SetMapMode( MapMode(MAP_MM) );
758 0 : const Size aLogSize( mpChildWindow->PixelToLogic(mpChildWindow->GetOutputSizePixel()) );
759 0 : mpChildWindow->SetMapMode( aOldMapMode );
760 :
761 0 : return ::vcl::unotools::size2DFromSize( aLogSize );
762 : }
763 :
764 0 : uno::Reference< rendering::XLinePolyPolygon2D > SpriteDeviceHelper::createCompatibleLinePolyPolygon(
765 : const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
766 : const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points )
767 : {
768 : // disposed?
769 0 : if( !mpSpriteCanvas )
770 0 : return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed
771 :
772 : return uno::Reference< rendering::XLinePolyPolygon2D >(
773 : new ::basegfx::unotools::UnoPolyPolygon(
774 0 : ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points )));
775 : }
776 :
777 0 : uno::Reference< rendering::XBezierPolyPolygon2D > SpriteDeviceHelper::createCompatibleBezierPolyPolygon(
778 : const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
779 : const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points )
780 : {
781 : // disposed?
782 0 : if( !mpSpriteCanvas )
783 0 : return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed
784 :
785 : return uno::Reference< rendering::XBezierPolyPolygon2D >(
786 : new ::basegfx::unotools::UnoPolyPolygon(
787 0 : ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) );
788 : }
789 :
790 0 : uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleBitmap(
791 : const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
792 : const geometry::IntegerSize2D& size )
793 : {
794 : // disposed?
795 0 : if( !mpSpriteCanvas )
796 0 : return uno::Reference< rendering::XBitmap >(); // we're disposed
797 :
798 : return uno::Reference< rendering::XBitmap >(
799 : new CanvasBitmap( size,
800 : mpSpriteCanvas,
801 : *this,
802 0 : false ) );
803 : }
804 :
805 0 : uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileBitmap(
806 : const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
807 : const geometry::IntegerSize2D& /*size*/ )
808 : {
809 0 : return uno::Reference< rendering::XVolatileBitmap >();
810 : }
811 :
812 0 : uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleAlphaBitmap(
813 : const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
814 : const geometry::IntegerSize2D& size )
815 : {
816 : // disposed?
817 0 : if( !mpSpriteCanvas )
818 0 : return uno::Reference< rendering::XBitmap >(); // we're disposed
819 :
820 : return uno::Reference< rendering::XBitmap >(
821 : new CanvasBitmap( size,
822 : mpSpriteCanvas,
823 : *this,
824 0 : true ) );
825 : }
826 :
827 0 : uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap(
828 : const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
829 : const geometry::IntegerSize2D& /*size*/ )
830 : {
831 0 : return uno::Reference< rendering::XVolatileBitmap >();
832 : }
833 :
834 0 : sal_Bool SpriteDeviceHelper::hasFullScreenMode()
835 : {
836 : // TODO(F3): offer fullscreen mode the XCanvas way
837 0 : return false;
838 : }
839 :
840 0 : sal_Bool SpriteDeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ )
841 : {
842 : // TODO(F3): offer fullscreen mode the XCanvas way
843 0 : return false;
844 : }
845 :
846 0 : ::sal_Int32 SpriteDeviceHelper::createBuffers( ::sal_Int32 /*nBuffers*/ )
847 : {
848 : // TODO(F3): implement XBufferStrategy interface. For now, we
849 : // _always_ will have exactly one backbuffer
850 0 : return 1;
851 : }
852 :
853 0 : void SpriteDeviceHelper::destroyBuffers()
854 : {
855 : // TODO(F3): implement XBufferStrategy interface. For now, we
856 : // _always_ will have exactly one backbuffer
857 0 : }
858 :
859 : namespace
860 : {
861 : /** Functor providing a StrictWeakOrdering for XSprites (over
862 : priority)
863 : */
864 : struct SpriteComparator
865 : {
866 0 : bool operator()( const ::rtl::Reference<CanvasCustomSprite>& rLHS,
867 : const ::rtl::Reference<CanvasCustomSprite>& rRHS ) const
868 : {
869 0 : const double nPrioL( rLHS->getPriority() );
870 0 : const double nPrioR( rRHS->getPriority() );
871 :
872 : // if prios are equal, tie-break on ptr value
873 0 : return nPrioL == nPrioR ? rLHS.get() < rRHS.get() : nPrioL < nPrioR;
874 : }
875 : };
876 : }
877 :
878 0 : sal_Bool SpriteDeviceHelper::showBuffer( bool bIsVisible, sal_Bool /*bUpdateAll*/ )
879 : {
880 : // hidden or disposed?
881 0 : if( !bIsVisible || !mpChildWindow || !mpSpriteCanvas )
882 0 : return false;
883 :
884 0 : if( !activateWindowContext() )
885 0 : return false;
886 :
887 0 : const ::Size& rOutputSize=mpChildWindow->GetSizePixel();
888 0 : initTransformation(rOutputSize);
889 :
890 : // render the actual spritecanvas content
891 0 : mpSpriteCanvas->renderRecordedActions();
892 :
893 : // render all sprites (in order of priority) on top of that
894 0 : std::vector< ::rtl::Reference<CanvasCustomSprite> > aSprites;
895 : std::copy(maActiveSprites.begin(),
896 : maActiveSprites.end(),
897 : std::back_insert_iterator<
898 0 : std::vector< ::rtl::Reference< CanvasCustomSprite > > >(aSprites));
899 : std::sort(aSprites.begin(),
900 : aSprites.end(),
901 0 : SpriteComparator());
902 : std::for_each(aSprites.begin(),
903 : aSprites.end(),
904 0 : boost::mem_fn(&CanvasCustomSprite::renderSprite));
905 :
906 :
907 : // frame counter, other info
908 0 : glMatrixMode(GL_MODELVIEW);
909 0 : glLoadIdentity();
910 0 : glTranslated(-1.0, 1.0, 0.0);
911 0 : glScaled( 2.0 / rOutputSize.Width(),
912 0 : -2.0 / rOutputSize.Height(),
913 0 : 1.0 );
914 :
915 0 : const double denominator( maLastUpdate.getElapsedTime() );
916 0 : maLastUpdate.reset();
917 :
918 0 : const double fps(denominator == 0.0 ? 100.0 : 1.0/denominator);
919 0 : std::vector<double> aVec; aVec.push_back(fps);
920 0 : aVec.push_back(maActiveSprites.size());
921 0 : aVec.push_back(mpTextureCache->getCacheSize());
922 0 : aVec.push_back(mpTextureCache->getCacheMissCount());
923 0 : aVec.push_back(mpTextureCache->getCacheHitCount());
924 0 : renderOSD( aVec, 20 );
925 :
926 : // switch buffer, sync etc.
927 0 : const unx::Window aXWindow=mpChildWindow->GetSystemData()->aWindow;
928 : unx::glXSwapBuffers(reinterpret_cast<unx::Display*>(mpDisplay),
929 0 : aXWindow);
930 0 : mpChildWindow->Show();
931 0 : unx::glXWaitGL();
932 0 : XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
933 :
934 : // flush texture cache, such that it does not build up
935 : // indefinitely.
936 : // TODO: have max cache size/LRU time in config, prune only on
937 : // demand
938 0 : mpTextureCache->prune();
939 :
940 0 : return true;
941 : }
942 :
943 0 : sal_Bool SpriteDeviceHelper::switchBuffer( bool bIsVisible, sal_Bool bUpdateAll )
944 : {
945 : // no difference for VCL canvas
946 0 : return showBuffer( bIsVisible, bUpdateAll );
947 : }
948 :
949 0 : uno::Any SpriteDeviceHelper::isAccelerated() const
950 : {
951 0 : return ::com::sun::star::uno::makeAny(false);
952 : }
953 :
954 0 : uno::Any SpriteDeviceHelper::getDeviceHandle() const
955 : {
956 0 : return uno::makeAny( reinterpret_cast< sal_Int64 >(mpChildWindow.get()) );
957 : }
958 :
959 0 : uno::Any SpriteDeviceHelper::getSurfaceHandle() const
960 : {
961 0 : return uno::Any();
962 : }
963 :
964 0 : uno::Reference<rendering::XColorSpace> SpriteDeviceHelper::getColorSpace() const
965 : {
966 : // always the same
967 : return uno::Reference<rendering::XColorSpace>(
968 : ::canvas::tools::getStdColorSpace(),
969 0 : uno::UNO_QUERY);
970 : }
971 :
972 0 : void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds )
973 : {
974 0 : if( mpChildWindow )
975 0 : mpChildWindow->setPosSizePixel(
976 0 : 0,0,rBounds.Width,rBounds.Height);
977 0 : }
978 :
979 0 : void SpriteDeviceHelper::dumpScreenContent() const
980 : {
981 : SAL_INFO("canvas.ogl", BOOST_CURRENT_FUNCTION );
982 0 : }
983 :
984 0 : void SpriteDeviceHelper::show( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
985 : {
986 0 : maActiveSprites.insert(xSprite);
987 0 : }
988 :
989 0 : void SpriteDeviceHelper::hide( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
990 : {
991 0 : maActiveSprites.erase(xSprite);
992 0 : }
993 :
994 0 : static void setupUniforms( unsigned int nProgramId,
995 : const ::basegfx::B2DHomMatrix& rTexTransform )
996 : {
997 : const GLint nTransformLocation = glGetUniformLocation(nProgramId,
998 0 : "m_transform" );
999 : // OGL is column-major
1000 : float aTexTransform[] =
1001 : {
1002 0 : float(rTexTransform.get(0,0)), float(rTexTransform.get(1,0)),
1003 0 : float(rTexTransform.get(0,1)), float(rTexTransform.get(1,1)),
1004 0 : float(rTexTransform.get(0,2)), float(rTexTransform.get(1,2))
1005 0 : };
1006 0 : glUniformMatrix3x2fv(nTransformLocation,1,false,aTexTransform);
1007 0 : }
1008 :
1009 0 : static void setupUniforms( unsigned int nProgramId,
1010 : const rendering::ARGBColor* pColors,
1011 : const uno::Sequence< double >& rStops,
1012 : const ::basegfx::B2DHomMatrix& rTexTransform )
1013 : {
1014 0 : glUseProgram(nProgramId);
1015 :
1016 : GLuint nColorsTexture;
1017 0 : glActiveTexture(GL_TEXTURE0);
1018 0 : glGenTextures(1, &nColorsTexture);
1019 0 : glBindTexture(GL_TEXTURE_1D, nColorsTexture);
1020 :
1021 0 : const sal_Int32 nColors=rStops.getLength();
1022 0 : glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, nColors, 0, GL_RGBA, GL_DOUBLE, pColors );
1023 0 : glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1024 0 : glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1025 :
1026 : GLuint nStopsTexture;
1027 0 : glActiveTexture(GL_TEXTURE1);
1028 0 : glGenTextures(1, &nStopsTexture);
1029 0 : glBindTexture(GL_TEXTURE_1D, nStopsTexture);
1030 :
1031 0 : glTexImage1D( GL_TEXTURE_1D, 0, GL_ALPHA, nColors, 0, GL_ALPHA, GL_DOUBLE, rStops.getConstArray() );
1032 0 : glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1033 0 : glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1034 :
1035 : const GLint nColorArrayLocation = glGetUniformLocation(nProgramId,
1036 0 : "t_colorArray4d" );
1037 0 : glUniform1i( nColorArrayLocation, 0 ); // unit 0
1038 :
1039 : const GLint nStopArrayLocation = glGetUniformLocation(nProgramId,
1040 0 : "t_stopArray1d" );
1041 0 : glUniform1i( nStopArrayLocation, 1 ); // unit 1
1042 :
1043 : const GLint nNumColorLocation = glGetUniformLocation(nProgramId,
1044 0 : "i_nColors" );
1045 0 : glUniform1i( nNumColorLocation, nColors-1 );
1046 :
1047 0 : setupUniforms(nProgramId,rTexTransform);
1048 0 : }
1049 :
1050 0 : static void setupUniforms( unsigned int nProgramId,
1051 : const rendering::ARGBColor& rStartColor,
1052 : const rendering::ARGBColor& rEndColor,
1053 : const ::basegfx::B2DHomMatrix& rTexTransform )
1054 : {
1055 0 : glUseProgram(nProgramId);
1056 :
1057 : const GLint nStartColorLocation = glGetUniformLocation(nProgramId,
1058 0 : "v_startColor4d" );
1059 : glUniform4f(nStartColorLocation,
1060 : rStartColor.Red,
1061 : rStartColor.Green,
1062 : rStartColor.Blue,
1063 0 : rStartColor.Alpha);
1064 :
1065 : const GLint nEndColorLocation = glGetUniformLocation(nProgramId,
1066 0 : "v_endColor4d" );
1067 : glUniform4f(nEndColorLocation,
1068 : rEndColor.Red,
1069 : rEndColor.Green,
1070 : rEndColor.Blue,
1071 0 : rEndColor.Alpha);
1072 :
1073 0 : setupUniforms(nProgramId,rTexTransform);
1074 0 : }
1075 :
1076 0 : void SpriteDeviceHelper::useLinearGradientShader( const rendering::ARGBColor* pColors,
1077 : const uno::Sequence< double >& rStops,
1078 : const ::basegfx::B2DHomMatrix& rTexTransform )
1079 : {
1080 0 : if( rStops.getLength() > 2 )
1081 0 : setupUniforms(mnLinearMultiColorGradientProgram, pColors, rStops, rTexTransform);
1082 : else
1083 0 : setupUniforms(mnLinearTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
1084 0 : }
1085 :
1086 0 : void SpriteDeviceHelper::useRadialGradientShader( const rendering::ARGBColor* pColors,
1087 : const uno::Sequence< double >& rStops,
1088 : const ::basegfx::B2DHomMatrix& rTexTransform )
1089 : {
1090 0 : if( rStops.getLength() > 2 )
1091 0 : setupUniforms(mnRadialMultiColorGradientProgram, pColors, rStops, rTexTransform);
1092 : else
1093 0 : setupUniforms(mnRadialTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
1094 0 : }
1095 :
1096 0 : void SpriteDeviceHelper::useRectangularGradientShader( const rendering::ARGBColor* pColors,
1097 : const uno::Sequence< double >& rStops,
1098 : const ::basegfx::B2DHomMatrix& rTexTransform )
1099 : {
1100 0 : if( rStops.getLength() > 2 )
1101 0 : setupUniforms(mnRectangularMultiColorGradientProgram, pColors, rStops, rTexTransform);
1102 : else
1103 0 : setupUniforms(mnRectangularTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
1104 0 : }
1105 :
1106 0 : bool SpriteDeviceHelper::activatePBufferContext(const ::basegfx::B2IVector& rSize,
1107 : unsigned int PBuffer) const
1108 : {
1109 0 : if( !glXMakeCurrent( reinterpret_cast<unx::Display*>(mpDisplay),
1110 : PBuffer,
1111 0 : reinterpret_cast<unx::GLXContext>(mpGLPBufContext)) )
1112 : {
1113 : SAL_INFO("canvas.ogl", "SpriteDeviceHelper::activatePBufferContext(): cannot activate GL context");
1114 0 : return false;
1115 : }
1116 :
1117 0 : initContext();
1118 : initTransformation(
1119 : ::Size(
1120 : rSize.getX(),
1121 : rSize.getY()),
1122 0 : true);
1123 :
1124 0 : return true;
1125 : }
1126 :
1127 0 : bool SpriteDeviceHelper::activateWindowContext() const
1128 : {
1129 0 : const unx::Window aXWindow=mpChildWindow->GetSystemData()->aWindow;
1130 0 : if( !glXMakeCurrent( reinterpret_cast<unx::Display*>(mpDisplay),
1131 : aXWindow,
1132 0 : reinterpret_cast<unx::GLXContext>(mpGLContext)) )
1133 : {
1134 : SAL_INFO("canvas.ogl", "SpriteDeviceHelper::activateWindowContext(): cannot activate GL context");
1135 0 : return false;
1136 : }
1137 :
1138 0 : return true;
1139 : }
1140 :
1141 0 : bool SpriteDeviceHelper::updatePBufferTexture( const ::basegfx::B2IVector& rSize,
1142 : unsigned int nTextId ) const
1143 : {
1144 0 : glBindTexture( GL_TEXTURE_2D, nTextId );
1145 0 : glEnable(GL_TEXTURE_2D);
1146 : glCopyTexSubImage2D( GL_TEXTURE_2D,
1147 : 0, 0, 0, 0, 0,
1148 0 : rSize.getX(),
1149 0 : rSize.getY() );
1150 0 : glBindTexture(GL_TEXTURE_2D, 0);
1151 :
1152 0 : return true;
1153 : }
1154 :
1155 : namespace
1156 : {
1157 : class BufferContextImpl : public IBufferContext
1158 : {
1159 : ::basegfx::B2IVector maSize;
1160 : const SpriteDeviceHelper& mrDeviceHelper;
1161 : unx::GLXPbuffer mpPBuffer;
1162 : #if 0
1163 : unx::Display* mpDisplay;
1164 : #endif
1165 : unsigned int mnTexture;
1166 :
1167 0 : virtual bool startBufferRendering() SAL_OVERRIDE
1168 : {
1169 0 : return mrDeviceHelper.activatePBufferContext(maSize,mpPBuffer);
1170 : }
1171 :
1172 0 : virtual bool endBufferRendering() SAL_OVERRIDE
1173 : {
1174 0 : mrDeviceHelper.updatePBufferTexture(maSize,mnTexture);
1175 0 : if( !mrDeviceHelper.activateWindowContext() )
1176 0 : return false;
1177 :
1178 0 : glBindTexture( GL_TEXTURE_2D, mnTexture );
1179 :
1180 0 : return true;
1181 : }
1182 :
1183 : public:
1184 0 : BufferContextImpl(const SpriteDeviceHelper& rDeviceHelper,
1185 : unx::GLXPbuffer pBuffer,
1186 : unx::Display*
1187 : #if 0
1188 : pDisplay
1189 : #endif
1190 : ,
1191 : const ::basegfx::B2IVector& rSize) :
1192 : maSize(rSize),
1193 : mrDeviceHelper(rDeviceHelper),
1194 : mpPBuffer(pBuffer),
1195 : #if 0
1196 : mpDisplay(pDisplay),
1197 : #endif
1198 0 : mnTexture(0)
1199 : {
1200 0 : glGenTextures( 1, &mnTexture );
1201 : #if 1
1202 0 : glBindTexture( GL_TEXTURE_2D, mnTexture );
1203 0 : glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1204 0 : glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1205 : glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
1206 0 : maSize.getX(), maSize.getY(),
1207 0 : 0, GL_RGBA, GL_UNSIGNED_BYTE, new int[maSize.getX()*maSize.getY()] );
1208 : #endif
1209 0 : }
1210 :
1211 0 : virtual ~BufferContextImpl()
1212 0 : {
1213 : #if 0
1214 : glBindTexture(GL_TEXTURE_2D, 0);
1215 : glDeleteTextures( 1, &mnTexture );
1216 : glXDestroyPbuffer( mpDisplay, mpPBuffer );
1217 : #endif
1218 0 : }
1219 : };
1220 : }
1221 :
1222 0 : IBufferContextSharedPtr SpriteDeviceHelper::createBufferContext(const ::basegfx::B2IVector& rSize) const
1223 : {
1224 : int pBufAttribs[] =
1225 : {
1226 0 : GLX_PBUFFER_WIDTH, rSize.getX(),
1227 0 : GLX_PBUFFER_HEIGHT, rSize.getY(),
1228 : GLX_LARGEST_PBUFFER, False,
1229 : None
1230 0 : };
1231 :
1232 : unx::GLXPbuffer pBuffer;
1233 : pBuffer = unx::glXCreatePbuffer( reinterpret_cast<unx::Display*>(mpDisplay),
1234 : *reinterpret_cast<unx::GLXFBConfig*>(mpFBConfig),
1235 0 : pBufAttribs );
1236 :
1237 0 : IBufferContextSharedPtr pRet;
1238 0 : if( pBuffer )
1239 : pRet.reset(new BufferContextImpl(
1240 : *this,
1241 : pBuffer,
1242 : reinterpret_cast<unx::Display*>(mpDisplay),
1243 0 : rSize));
1244 :
1245 0 : return pRet;
1246 : }
1247 :
1248 0 : TextureCache& SpriteDeviceHelper::getTextureCache() const
1249 : {
1250 0 : return *mpTextureCache;
1251 : }
1252 0 : }
1253 :
1254 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|