1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "OGLTrans_TransitionImpl.hxx"
29 #include "OGLTrans_Shaders.hxx"
30 #include <GL/gl.h>
31 #include <math.h>
32 
33 
34 void OGLTransitionImpl::clear()
35 {
36     for(unsigned int i( 0 ); i < OverallOperations.size(); ++i)
37         delete OverallOperations[i];
38     OverallOperations.clear();
39     maLeavingSlidePrimitives.clear();
40     maEnteringSlidePrimitives.clear();
41     for(unsigned int i(0); i < maSceneObjects.size(); ++i)
42         delete maSceneObjects[i];
43     maSceneObjects.clear();
44 
45     mbReflectSlides = false;
46 
47 #ifdef GL_VERSION_2_0
48     if( mProgramObject ) {
49         OGLShaders::glDeleteProgram( mProgramObject );
50         mProgramObject = 0;
51     }
52 
53     if( mVertexObject ) {
54         OGLShaders::glDeleteShader( mVertexObject );
55         mVertexObject = 0;
56     }
57 
58     if( mFragmentObject ) {
59         OGLShaders::glDeleteShader( mFragmentObject );
60         mFragmentObject = 0;
61     }
62 #endif
63 
64     if( maHelperTexture ) {
65         glDeleteTextures( 1, &maHelperTexture );
66         maHelperTexture = 0;
67     }
68 
69     if( mmClearTransition )
70         (this->*mmClearTransition)();
71 }
72 
73 OGLTransitionImpl::~OGLTransitionImpl()
74 {
75     clear();
76 }
77 
78 void OGLTransitionImpl::prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex )
79 {
80     for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
81         maSceneObjects[i]->prepare();
82     }
83 
84     if( mmPrepareTransition )
85         (this->*mmPrepareTransition)( glLeavingSlideTex, glEnteringSlideTex );
86 }
87 
88 void OGLTransitionImpl::finish()
89 {
90     for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
91         maSceneObjects[i]->finish();
92     }
93 }
94 
95 static void blendSlide( double depth )
96 {
97     double showHeight = -1 + depth*2;
98     GLfloat reflectionColor[] = {0, 0, 0, 0.25};
99 
100     glDisable( GL_DEPTH_TEST );
101     glBegin( GL_QUADS );
102     glColor4fv( reflectionColor );
103     glVertex3f( -1, -1, 0 );
104     glColor4f( 0, 0, 0, 1 );
105     glVertex3f(-1,  showHeight, 0 );
106     glVertex3f( 1,  showHeight, 0 );
107     glColor4fv( reflectionColor );
108     glVertex3f( 1, -1, 0 );
109     glEnd();
110 
111     glBegin( GL_QUADS );
112     glColor4f( 0, 0, 0, 1 );
113     glVertex3f( -1, showHeight, 0 );
114     glVertex3f( -1,  1, 0 );
115     glVertex3f(  1,  1, 0 );
116     glVertex3f(  1, showHeight, 0 );
117     glEnd();
118     glEnable( GL_DEPTH_TEST );
119 }
120 
121 static void slideShadow( double nTime, Primitive& primitive, double sw, double sh )
122 {
123     double reflectionDepth = 0.3;
124 
125     glEnable(GL_BLEND);
126     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
127     glDisable(GL_LIGHTING);
128 
129     glPushMatrix();
130     primitive.applyOperations( nTime, sw, sh );
131     blendSlide( reflectionDepth );
132     glPopMatrix();
133 
134     glDisable(GL_BLEND);
135     glEnable(GL_LIGHTING);
136 }
137 
138 void OGLTransitionImpl::display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
139                                  double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
140 {
141     double SlideWidthScale, SlideHeightScale;
142 
143     SlideWidthScale = SlideWidth/DispWidth;
144     SlideHeightScale = SlideHeight/DispHeight;
145 
146     if( mmPrepare ) {
147         clear();
148         (this->*mmPrepare)( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
149     }
150 
151     glPushMatrix();
152     displaySlides( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
153     displayScene( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
154     glPopMatrix();
155 }
156 
157 void OGLTransitionImpl::applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale )
158 {
159     for(unsigned int i(0); i < OverallOperations.size(); ++i)
160         OverallOperations[i]->interpolate(nTime,SlideWidthScale,SlideHeightScale);
161 }
162 
163 void OGLTransitionImpl::displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives,
164                                       double SlideWidthScale, double SlideHeightScale )
165 {
166    //TODO change to foreach
167     glBindTexture(GL_TEXTURE_2D, glSlideTex);
168 
169     // display slide reflection
170     // note that depth test is turned off while blending the shadow
171     // so the slides has to be rendered in right order, see rochade as example
172     if( mbReflectSlides ) {
173         double surfaceLevel = -0.04;
174 
175         /* reflected slides */
176         glPushMatrix();
177 
178         glScaled( 1, -1, 1 );
179         glTranslated( 0, 2 - surfaceLevel, 0 );
180 
181         glCullFace(GL_FRONT);
182 	for(unsigned int i(0); i < primitives.size(); ++i)
183 	    primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
184         glCullFace(GL_BACK);
185 
186 	slideShadow( nTime, primitives[0], SlideWidthScale, SlideHeightScale );
187 
188         glPopMatrix();
189     }
190 
191     for(unsigned int i(0); i < primitives.size(); ++i)
192         primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
193 }
194 
195 void OGLTransitionImpl::displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
196                                        double SlideWidthScale, double SlideHeightScale )
197 {
198     if( mmDisplaySlides )
199         (this->*mmDisplaySlides)( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
200     else {
201         applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
202 
203         glEnable(GL_TEXTURE_2D);
204         displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
205         displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
206     }
207 }
208 
209 void OGLTransitionImpl::displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
210 {
211     glEnable(GL_TEXTURE_2D);
212     for(unsigned int i(0); i < maSceneObjects.size(); ++i)
213         maSceneObjects[i]->display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
214 }
215 
216 void Primitive::display(double nTime, double WidthScale, double HeightScale)
217 {
218     glPushMatrix();
219 
220     applyOperations( nTime, WidthScale, HeightScale );
221 
222     glEnableClientState( GL_VERTEX_ARRAY );
223     if(!Normals.empty())
224     {
225         glNormalPointer( GL_DOUBLE , 0 , &Normals[0] );
226         glEnableClientState( GL_NORMAL_ARRAY );
227     }
228     glEnableClientState( GL_TEXTURE_COORD_ARRAY );
229     glTexCoordPointer( 2, GL_DOUBLE, 0, &TexCoords[0] );
230     glVertexPointer( 3, GL_DOUBLE, 0, &Vertices[0] );
231     glDrawArrays( GL_TRIANGLES, 0, Vertices.size() );
232     glPopMatrix();
233 }
234 
235 void Primitive::applyOperations(double nTime, double WidthScale, double HeightScale)
236 {
237     for(unsigned int i(0); i < Operations.size(); ++i)
238         Operations[i]->interpolate( nTime ,WidthScale,HeightScale);
239     glScaled(WidthScale,HeightScale,1);
240 }
241 
242 Primitive::~Primitive()
243 {
244     for(unsigned int i( 0 ); i < Operations.size(); ++i)
245         delete Operations[i];
246 }
247 
248 
249 void SceneObject::display(double nTime, double /* SlideWidth */, double /* SlideHeight */, double DispWidth, double DispHeight )
250 {
251     for(unsigned int i(0); i < maPrimitives.size(); ++i) {
252         // fixme: allow various model spaces, now we make it so that
253         // it is regular -1,-1 to 1,1, where the whole display fits in
254         glPushMatrix();
255         if (DispHeight > DispWidth)
256             glScaled(DispHeight/DispWidth, 1, 1);
257         else
258             glScaled(1, DispWidth/DispHeight, 1);
259         maPrimitives[i].display(nTime, 1, 1);
260         glPopMatrix();
261     }
262 }
263 
264 void SceneObject::pushPrimitive(const Primitive &p)
265 {
266     maPrimitives.push_back(p);
267 }
268 
269 SceneObject::SceneObject()
270     : maPrimitives()
271 {
272 }
273 
274 Iris::Iris()
275     : SceneObject ()
276 {
277 }
278 
279 void Iris::display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
280 {
281     glBindTexture(GL_TEXTURE_2D, maTexture);
282     SceneObject::display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
283 }
284 
285 void Iris::prepare()
286 {
287     static GLubyte img[3] = { 80, 80, 80 };
288 
289     glGenTextures(1, &maTexture);
290     glBindTexture(GL_TEXTURE_2D, maTexture);
291     glTexImage2D(GL_TEXTURE_2D, 0, 3, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
292     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
293     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
294     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
295     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
296 }
297 
298 void Iris::finish()
299 {
300     glDeleteTextures(1, &maTexture);
301 }
302 
303 void OGLTransitionImpl::makeOutsideCubeFaceToLeft()
304 {
305     clear();
306     Primitive Slide;
307 
308     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
309     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
310 
311     maLeavingSlidePrimitives.push_back(Slide);
312 
313     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),90,false,0.0,1.0));
314 
315     maEnteringSlidePrimitives.push_back(Slide);
316 
317     OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),-90,true,0.0,1.0));
318 }
319 
320 void OGLTransitionImpl::makeInsideCubeFaceToLeft()
321 {
322     clear();
323     Primitive Slide;
324 
325     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
326     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
327 
328     maLeavingSlidePrimitives.push_back(Slide);
329 
330     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),-90,false,0.0,1.0));
331 
332     maEnteringSlidePrimitives.push_back(Slide);
333 
334     OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),90,true,0.0,1.0));
335 }
336 
337 void OGLTransitionImpl::makeFallLeaving()
338 {
339     clear();
340     Primitive Slide;
341 
342     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
343     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
344     maEnteringSlidePrimitives.push_back(Slide);
345 
346     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(1,0,0),basegfx::B3DVector(0,-1,0), 90,true,0.0,1.0));
347     maLeavingSlidePrimitives.push_back(Slide);
348 
349     mbUseMipMapEntering = false;
350 }
351 
352 void OGLTransitionImpl::makeTurnAround()
353 {
354     clear();
355     Primitive Slide;
356 
357     mbReflectSlides = true;
358 
359     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
360     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
361     maLeavingSlidePrimitives.push_back(Slide);
362 
363     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0),-180,false,0.0,1.0));
364     maEnteringSlidePrimitives.push_back(Slide);
365 
366     OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, -1.5),true, 0, 0.5));
367     OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1.5), true, 0.5, 1));
368     OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0),basegfx::B3DVector(0, 0, 0), -180, true, 0.0, 1.0));
369 }
370 
371 void OGLTransitionImpl::makeTurnDown()
372 {
373     clear();
374     Primitive Slide;
375 
376     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
377     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
378     maLeavingSlidePrimitives.push_back(Slide);
379 
380     Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 0.0001), false, -1.0, 0.0));
381     Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), -90, true, 0.0, 1.0));
382     Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), 90, false, -1.0, 0.0));
383     maEnteringSlidePrimitives.push_back(Slide);
384 
385     mbUseMipMapLeaving = false;
386 }
387 
388 void OGLTransitionImpl::makeIris()
389 {
390     clear();
391     Primitive Slide;
392 
393     Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
394     Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
395     maEnteringSlidePrimitives.push_back (Slide);
396 
397     Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0,  0.000001), false, -1, 0));
398     Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, -0.000002), false, 0.5, 1));
399     maLeavingSlidePrimitives.push_back (Slide);
400 
401 
402     Primitive irisPart, part;
403     int i, nSteps = 24, nParts = 7;
404     double lt = 0, t = 1.0/nSteps, cx, cy, lcx, lcy, lx = 1, ly = 0, x, y, cxo, cyo, lcxo, lcyo, of=2.2, f=1.42;
405 
406     for (i=1; i<=nSteps; i++) {
407         x = cos ((3*2*M_PI*t)/nParts);
408         y = -sin ((3*2*M_PI*t)/nParts);
409         cx = (f*x + 1)/2;
410         cy = (f*y + 1)/2;
411         lcx = (f*lx + 1)/2;
412         lcy = (f*ly + 1)/2;
413         cxo = (of*x + 1)/2;
414         cyo = (of*y + 1)/2;
415         lcxo = (of*lx + 1)/2;
416         lcyo = (of*ly + 1)/2;
417         irisPart.pushTriangle (basegfx::B2DVector (lcx, lcy),
418                                basegfx::B2DVector (lcxo, lcyo),
419                                basegfx::B2DVector (cx, cy));
420         irisPart.pushTriangle (basegfx::B2DVector (cx, cy),
421                                basegfx::B2DVector (lcxo, lcyo),
422                                basegfx::B2DVector (cxo, cyo));
423         lx = x;
424         ly = y;
425         lt = t;
426         t += 1.0/nSteps;
427     }
428 
429     Iris* pIris = new Iris();
430     double angle = 87;
431 
432     for (i = 0; i < nParts; i++) {
433         irisPart.Operations.clear ();
434         double rx, ry;
435 
436         rx = cos ((2*M_PI*i)/nParts);
437         ry = sin ((2*M_PI*i)/nParts);
438         irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0),  angle, true, 0.0, 0.5));
439         irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), -angle, true, 0.5, 1));
440         if (i > 0) {
441             irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(rx, ry, 0),  false, -1, 0));
442             irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(0, 0, 0), i*360.0/nParts, false, -1, 0));
443             irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(-1, 0, 0),  false, -1, 0));
444         }
445         irisPart.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1), false, -2, 0.0));
446         irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(1, .5, 0), basegfx::B3DVector(1, 0, 0), -30, false, -1, 0));
447         pIris->pushPrimitive (irisPart);
448     }
449 
450     maSceneObjects.push_back (pIris);
451 
452     mbUseMipMapLeaving = mbUseMipMapEntering = false;
453 }
454 
455 void OGLTransitionImpl::displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
456 					      double SlideWidthScale, double SlideHeightScale )
457 {
458     applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
459 
460     glEnable(GL_TEXTURE_2D);
461 
462     if( nTime > .5) {
463 	displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
464 	displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
465     } else {
466 	displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
467 	displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
468     }
469 }
470 
471 void OGLTransitionImpl::makeRochade()
472 {
473     clear();
474     Primitive Slide;
475 
476     mbReflectSlides = true;
477     mmDisplaySlides = &OGLTransitionImpl::displaySlidesRochade;
478 
479     double w, h;
480 
481     w = 2.2;
482     h = 10;
483 
484     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
485     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
486 
487     Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.25, -0.25, true, 0, 1));
488     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
489     maLeavingSlidePrimitives.push_back(Slide);
490 
491     Slide.Operations.clear();
492     Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.75, 0.25, true, 0, 1));
493     Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, -h), false, -1, 0));
494     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
495     Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), 45, false, -1, 0));
496     maEnteringSlidePrimitives.push_back(Slide);
497 
498     //     OverallOperations.push_back(new SEllipseTranslate(0.5, 2, 0, 1, true, 0, 1));
499 //      push_back(new STranslate(basegfx::B3DVector(0, 0, -2), true, 0, 0.5));
500 //      OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, 2), true, 0.5, 1));
501 }
502 
503 // TODO(Q3): extract to basegfx
504 inline basegfx::B2DVector clamp(const basegfx::B2DVector& v)
505 {
506     return basegfx::B2DVector(min(max(v.getX(),-1.0),1.0),
507                               min(max(v.getY(),-1.0),1.0));
508 }
509 
510 // TODO(Q3): extract to basegfx
511 inline basegfx::B3DVector clamp(const basegfx::B3DVector& v)
512 {
513     return basegfx::B3DVector(min(max(v.getX(),-1.0),1.0),
514                               min(max(v.getY(),-1.0),1.0),
515                               min(max(v.getZ(),-1.0),1.0));
516 }
517 
518 inline double randFromNeg1to1()
519 {
520     return ( ( static_cast<double>( rand() ) / static_cast<double>( RAND_MAX ) ) * 2.0 ) - 1.0;
521 }
522 
523 // TODO(Q3): extract to basegfx
524 inline basegfx::B3DVector randNormVectorInXYPlane()
525 {
526     basegfx::B3DVector toReturn(randFromNeg1to1(),randFromNeg1to1(),0.0);
527     return toReturn/toReturn.getLength();
528 }
529 
530 void OGLTransitionImpl::makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles )
531 {
532     clear();
533     double dAngle(2*3.1415926/static_cast<double>( nPointsOnCircles ));
534     if(nCircles < 2 || nPointsOnCircles < 4)
535     {
536         makeNByMTileFlip(1,1);
537         return;
538     }
539     double Radius(1.0/static_cast<double>( nCircles ));
540     double dRadius(Radius);
541     double LastRadius(0.0);
542     double NextRadius(2*Radius);
543 
544     /// now we know there is at least two circles
545     /// the first will always be a full circle
546     /// the last will always be the outer shell of the slide with a circle hole
547 
548     //add the full circle
549     vector<basegfx::B2DVector> unScaledTexCoords;
550     double TempAngle(0.0);
551     for(unsigned int Point(0); Point < nPointsOnCircles; ++Point)
552     {
553         unScaledTexCoords.push_back( basegfx::B2DVector( cos(TempAngle - 3.1415926/2.0) , sin(TempAngle- 3.1415926/2.0) ) );
554 
555         TempAngle += dAngle;
556     }
557 
558     {
559         //double angle(0.0);
560         Primitive EnteringSlide;
561         Primitive LeavingSlide;
562         for(int Point(0); Point + 1 < nPointsOnCircles; ++Point)
563         {
564             EnteringSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
565             LeavingSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5, 0.5) );
566         }
567         EnteringSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius * unScaledTexCoords[ 0 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ nPointsOnCircles - 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
568         LeavingSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
569 
570         basegfx::B3DVector axis(randNormVectorInXYPlane());
571         EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
572         LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
573         EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
574 
575         maEnteringSlidePrimitives.push_back(EnteringSlide);
576         maLeavingSlidePrimitives.push_back(LeavingSlide);
577         LastRadius = Radius;
578         Radius = NextRadius;
579         NextRadius += dRadius;
580     }
581 
582     for(int i(1); i < nCircles - 1; ++i)
583     {
584         Primitive LeavingSlide;
585         Primitive EnteringSlide;
586         for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
587         {
588             EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
589             EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
590 
591             LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
592             LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
593         }
594 
595         EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
596         EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
597 
598         LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
599         LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
600 
601         basegfx::B3DVector axis(randNormVectorInXYPlane());
602         EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
603         LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
604         EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
605 
606         maEnteringSlidePrimitives.push_back(EnteringSlide);
607         maLeavingSlidePrimitives.push_back(LeavingSlide);
608 
609         LastRadius = Radius;
610         Radius = NextRadius;
611         NextRadius += dRadius;
612     }
613     {
614         Radius = sqrt(2.0);
615         Primitive LeavingSlide;
616         Primitive EnteringSlide;
617         for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
618         {
619 
620             EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
621             EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
622 
623             LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
624             LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
625         }
626 
627         EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
628         EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
629 
630         LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
631         LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
632 
633         basegfx::B3DVector axis(randNormVectorInXYPlane());
634         EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
635         LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
636         EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
637 
638         maEnteringSlidePrimitives.push_back(EnteringSlide);
639         maLeavingSlidePrimitives.push_back(LeavingSlide);
640     }
641 }
642 
643 void OGLTransitionImpl::makeHelix( ::sal_uInt16 nRows )
644 {
645     clear();
646     double invN(1.0/static_cast<double>(nRows));
647     double iDn = 0.0;
648     double iPDn = invN;
649     for(unsigned int i(0); i < nRows; ++i)
650     {
651         Primitive Tile;
652 
653         Tile.pushTriangle(basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
654 
655         Tile.pushTriangle(basegfx::B2DVector( 1.0 , iPDn ) , basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
656 
657         Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 ,
658                                                 true,min(max(static_cast<double>(i - nRows/2.0)*invN/2.0,0.0),1.0),
659                                                 min(max(static_cast<double>(i + nRows/2.0)*invN/2.0,0.0),1.0) ) );
660 
661         maLeavingSlidePrimitives.push_back(Tile);
662 
663         Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180 , false,0.0,1.0) );
664 
665         maEnteringSlidePrimitives.push_back(Tile);
666 
667         iDn += invN;
668         iPDn += invN;
669     }
670 }
671 
672 void OGLTransitionImpl::makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m )
673 {
674     clear();
675     double invN(1.0/static_cast<double>(n));
676     double invM(1.0/static_cast<double>(m));
677     double iDn = 0.0;
678     double iPDn = invN;
679     for(unsigned int i(0); i < n; ++i)
680     {
681         double jDm = 0.0;
682         double jPDm = invM;
683         for(unsigned int j(0); j < m; ++j)
684         {
685             Primitive Tile;
686 
687             Tile.pushTriangle(basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));
688 
689             Tile.pushTriangle(basegfx::B2DVector( iPDn , jPDm ) , basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));//bottom left corner of tile
690 
691             Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 , true, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
692             maLeavingSlidePrimitives.push_back(Tile);
693             Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180, false, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
694 
695             maEnteringSlidePrimitives.push_back(Tile);
696 
697             jDm += invM;
698             jPDm += invM;
699         }
700         iDn += invN;
701         iPDn += invN;
702     }
703 }
704 
705 SRotate::SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
706 {
707     nT0 = T0;
708     nT1 = T1;
709     bInterpolate = bInter;
710 }
711 
712 SScale::SScale(const basegfx::B3DVector& Scale,const basegfx::B3DVector& Origin, bool bInter, double T0, double T1):scale(Scale),origin(Origin)
713 {
714     nT0 = T0;
715     nT1 = T1;
716     bInterpolate = bInter;
717 }
718 
719 RotateAndScaleDepthByWidth::RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
720 {
721     nT0 = T0;
722     nT1 = T1;
723     bInterpolate = bInter;
724 }
725 
726 RotateAndScaleDepthByHeight::RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
727 {
728     nT0 = T0;
729     nT1 = T1;
730     bInterpolate = bInter;
731 }
732 
733 
734 STranslate::STranslate(const basegfx::B3DVector& Vector, bool bInter, double T0, double T1):vector(Vector)
735 {
736     nT0 = T0;
737     nT1 = T1;
738     bInterpolate = bInter;
739 }
740 
741 inline double intervalInter(double t, double T0, double T1)
742 {
743     return ( t - T0 ) / ( T1 - T0 );
744 }
745 
746 void STranslate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
747 {
748     if(t <= nT0)
749         return;
750     if(!bInterpolate || t > nT1)
751         t = nT1;
752     t = intervalInter(t,nT0,nT1);
753     glTranslated(SlideWidthScale*t*vector.getX(),SlideHeightScale*t*vector.getY(),t*vector.getZ());
754 }
755 
756 void SRotate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
757 {
758     if(t <= nT0)
759         return;
760     if(!bInterpolate || t > nT1)
761         t = nT1;
762     t = intervalInter(t,nT0,nT1);
763     glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
764     glScaled(SlideWidthScale,SlideHeightScale,1);
765     glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
766     glScaled(1/SlideWidthScale,1/SlideHeightScale,1);
767     glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
768 }
769 
770 void SScale::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
771 {
772     if(t <= nT0)
773         return;
774     if(!bInterpolate || t > nT1)
775         t = nT1;
776     t = intervalInter(t,nT0,nT1);
777     glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
778     glScaled((1-t) + t*scale.getX(),(1-t) + t*scale.getY(),(1-t) + t*scale.getZ());
779     glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
780 }
781 
782 void RotateAndScaleDepthByWidth::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
783 {
784     if(t <= nT0)
785         return;
786     if(!bInterpolate || t > nT1)
787         t = nT1;
788     t = intervalInter(t,nT0,nT1);
789     glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideWidthScale*origin.getZ());
790     glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
791     glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideWidthScale*origin.getZ());
792 }
793 
794 void RotateAndScaleDepthByHeight::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
795 {
796     if(t <= nT0)
797         return;
798     if(!bInterpolate || t > nT1)
799         t = nT1;
800     t = intervalInter(t,nT0,nT1);
801     glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideHeightScale*origin.getZ());
802     glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
803     glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideHeightScale*origin.getZ());
804 }
805 
806 SEllipseTranslate::SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1)
807 {
808     nT0 = T0;
809     nT1 = T1;
810     bInterpolate = bInter;
811     width = dWidth;
812     height = dHeight;
813     startPosition = dStartPosition;
814     endPosition = dEndPosition;
815 }
816 
817 void SEllipseTranslate::interpolate(double t,double /* SlideWidthScale */,double /* SlideHeightScale */)
818 {
819     if(t <= nT0)
820         return;
821     if(!bInterpolate || t > nT1)
822         t = nT1;
823     t = intervalInter(t,nT0,nT1);
824 
825     double a1, a2, x, y;
826     a1 = startPosition*2*M_PI;
827     a2 = (startPosition + t*(endPosition - startPosition))*2*M_PI;
828     x = width*(cos (a2) - cos (a1))/2;
829     y = height*(sin (a2) - sin (a1))/2;
830 
831     glTranslated(x, 0, y);
832 }
833 
834 STranslate* STranslate::clone()
835 {
836     return new STranslate(*this);
837 }
838 SRotate* SRotate::clone()
839 {
840     return new SRotate(*this);
841 }
842 
843 SScale* SScale::clone()
844 {
845     return new SScale(*this);
846 }
847 
848 SEllipseTranslate* SEllipseTranslate::clone()
849 {
850     return new SEllipseTranslate(*this);
851 }
852 
853 RotateAndScaleDepthByWidth* RotateAndScaleDepthByWidth::clone()
854 {
855     return new RotateAndScaleDepthByWidth(*this);
856 }
857 
858 RotateAndScaleDepthByHeight* RotateAndScaleDepthByHeight::clone()
859 {
860     return new RotateAndScaleDepthByHeight(*this);
861 }
862 
863 const Primitive& Primitive::operator=(const Primitive& rvalue)
864 {
865     for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
866         Operations.push_back(rvalue.Operations[i]->clone());
867     for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
868         Vertices.push_back(rvalue.Vertices[i]);
869     for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
870         TexCoords.push_back(rvalue.TexCoords[i]);
871     for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
872         Normals.push_back(rvalue.Normals[i]);
873     return *this;
874 }
875 
876 Primitive::Primitive(const Primitive& rvalue)
877 {
878     for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
879         Operations.push_back(rvalue.Operations[i]->clone());
880     for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
881         Vertices.push_back(rvalue.Vertices[i]);
882     for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
883         TexCoords.push_back(rvalue.TexCoords[i]);
884     for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
885         Normals.push_back(rvalue.Normals[i]);
886 }
887 
888 void Primitive::pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2)
889 {
890     vector<basegfx::B3DVector> Verts;
891     vector<basegfx::B2DVector> Texs;
892     Verts.reserve(3);
893     Texs.reserve(3);
894 
895     Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
896     Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
897     Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
898 
899     //figure out if they're facing the correct way, and make them face the correct way.
900     basegfx::B3DVector Normal( basegfx::cross( Verts[0] - Verts[1] , Verts[1] - Verts[2] ) );
901     if(Normal.getZ() >= 0.0)//if the normal is facing us
902     {
903         Texs.push_back(SlideLocation0);
904         Texs.push_back(SlideLocation1);
905         Texs.push_back(SlideLocation2);
906     }
907     else // if the normal is facing away from us, make it face us
908     {
909         Texs.push_back(SlideLocation0);
910         Texs.push_back(SlideLocation2);
911         Texs.push_back(SlideLocation1);
912         Verts.clear();
913         Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
914         Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
915         Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
916     }
917 
918     Vertices.push_back(Verts[0]);
919     Vertices.push_back(Verts[1]);
920     Vertices.push_back(Verts[2]);
921 
922     TexCoords.push_back(Texs[0]);
923     TexCoords.push_back(Texs[1]);
924     TexCoords.push_back(Texs[2]);
925 
926     Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
927     Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
928     Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
929 }
930 
931 void OGLTransitionImpl::makeDiamond()
932 {
933     mmPrepare = &OGLTransitionImpl::prepareDiamond;
934     mbUseMipMapLeaving = mbUseMipMapEntering = false;
935 }
936 
937 void OGLTransitionImpl::prepareDiamond( double nTime, double /* SlideWidth */, double /* SlideHeight */, double /* DispWidth */, double /* DispHeight */ )
938 {
939     Primitive Slide1, Slide2;
940 
941     Slide1.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
942     Slide1.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
943     maEnteringSlidePrimitives.push_back (Slide1);
944 
945 
946     if( nTime >= 0.5 ) {
947         double m = 1 - nTime;
948 
949         Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (m,0), basegfx::B2DVector (0,m));
950         Slide2.pushTriangle (basegfx::B2DVector (nTime,0), basegfx::B2DVector (1,0), basegfx::B2DVector (1,m));
951         Slide2.pushTriangle (basegfx::B2DVector (1,nTime), basegfx::B2DVector (1,1), basegfx::B2DVector (nTime,1));
952         Slide2.pushTriangle (basegfx::B2DVector (0,nTime), basegfx::B2DVector (m,1), basegfx::B2DVector (0,1));
953     } else {
954         double l = 0.5 - nTime;
955         double h = 0.5 + nTime;
956 
957         Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0.5,l));
958         Slide2.pushTriangle (basegfx::B2DVector (0.5,l), basegfx::B2DVector (1,0), basegfx::B2DVector (h,0.5));
959         Slide2.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (1,1), basegfx::B2DVector (h,0.5));
960         Slide2.pushTriangle (basegfx::B2DVector (h,0.5), basegfx::B2DVector (1,1), basegfx::B2DVector (0.5,h));
961         Slide2.pushTriangle (basegfx::B2DVector (0.5,h), basegfx::B2DVector (1,1), basegfx::B2DVector (0,1));
962         Slide2.pushTriangle (basegfx::B2DVector (l,0.5), basegfx::B2DVector (0.5,h), basegfx::B2DVector (0,1));
963         Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (l,0.5), basegfx::B2DVector (0,1));
964         Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (0.5,l), basegfx::B2DVector (l,0.5));
965     }
966     Slide2.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.00000001), false, -1, 0));
967     maLeavingSlidePrimitives.push_back (Slide2);
968 }
969 
970 void OGLTransitionImpl::makeVenetianBlinds( bool vertical, int parts )
971 {
972     static double t30 = tan( M_PI/6.0 );
973     double n, ln = 0;
974     double p = 1.0/parts;
975 
976     for( int i=0; i<parts; i++ ) {
977         Primitive Slide;
978         n = (i + 1)/(double)parts;
979         if( vertical ) {
980             Slide.pushTriangle (basegfx::B2DVector (ln,0), basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1));
981             Slide.pushTriangle (basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1), basegfx::B2DVector (n,1));
982             Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, -t30*p), -120, true, 0.0, 1.0));
983         } else {
984             Slide.pushTriangle (basegfx::B2DVector (0,ln), basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n));
985             Slide.pushTriangle (basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n), basegfx::B2DVector (1,n));
986             Slide.Operations.push_back(new RotateAndScaleDepthByHeight(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, -t30*p), -120, true, 0.0, 1.0));
987         }
988         maLeavingSlidePrimitives.push_back (Slide);
989 
990         if( vertical ) {
991             Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(2*n - 1, 0, 0), -60, false, -1, 0));
992             Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, 0), 180, false, -1, 0));
993         } else {
994             Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - 2*n, 0), -60, false, -1, 0));
995             Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, 0), 180, false, -1, 0));
996         }
997         maEnteringSlidePrimitives.push_back (Slide);
998         ln = n;
999     }
1000 }
1001 
1002 void OGLTransitionImpl::displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
1003 {
1004     applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
1005 
1006     glDisable(GL_DEPTH_TEST);
1007 
1008     displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
1009 
1010     glDisable(GL_LIGHTING);
1011     glEnable(GL_BLEND);
1012     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1013     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1014     glColor4f( 1, 1, 1, nTime );
1015     displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
1016     glDisable(GL_BLEND);
1017     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1018     glEnable(GL_LIGHTING);
1019 
1020     glEnable(GL_DEPTH_TEST);
1021 }
1022 
1023 void OGLTransitionImpl::makeFadeSmoothly()
1024 {
1025     Primitive Slide;
1026 
1027     Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
1028     Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
1029     maLeavingSlidePrimitives.push_back (Slide);
1030     maEnteringSlidePrimitives.push_back (Slide);
1031 
1032     mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeSmoothly;
1033     mbUseMipMapLeaving = mbUseMipMapEntering = false;
1034 }
1035 
1036 void OGLTransitionImpl::displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
1037 {
1038     applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
1039 
1040     glDisable(GL_DEPTH_TEST);
1041 
1042     glDisable(GL_LIGHTING);
1043     glEnable(GL_BLEND);
1044     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1045     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1046     if( nTime < 0.5 ) {
1047 	glColor4f( 1, 1, 1, 1 - nTime*2 );
1048 	displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
1049     } else {
1050 	glColor4f( 1, 1, 1, (nTime - 0.5)*2 );
1051 	displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
1052     }
1053     glDisable(GL_BLEND);
1054     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1055     glEnable(GL_LIGHTING);
1056 
1057     glEnable(GL_DEPTH_TEST);
1058 }
1059 
1060 void OGLTransitionImpl::makeFadeThroughBlack()
1061 {
1062     Primitive Slide;
1063 
1064     Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
1065     Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
1066     maLeavingSlidePrimitives.push_back (Slide);
1067     maEnteringSlidePrimitives.push_back (Slide);
1068 
1069     mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeThroughBlack;
1070     mbUseMipMapLeaving = mbUseMipMapEntering = false;
1071 }
1072 
1073 static const char* basicVertexShader = "\n\
1074 varying vec2 v_texturePosition;\n\
1075 \n\
1076 void main( void )\n\
1077 {\n\
1078 	gl_Position = ftransform();\n\
1079 	v_texturePosition = gl_MultiTexCoord0.xy;\n\
1080 }\n\
1081 ";
1082 
1083 static const char* staticFragmentShader = "\n\
1084 uniform sampler2D leavingSlideTexture;\n\
1085 uniform sampler2D enteringSlideTexture;\n\
1086 uniform sampler2D permTexture;\n\
1087 uniform float time;\n\
1088 varying vec2 v_texturePosition;\n\
1089 \n\
1090 float snoise(vec2 P) {\n\
1091 \n\
1092   return texture2D(permTexture, P).r;\n\
1093 }\n\
1094 \n\
1095 \n\
1096 #define PART 0.5\n\
1097 #define START 0.4\n\
1098 #define END 0.9\n\
1099 \n\
1100 void main() {\n\
1101     float sn = snoise(10.0*v_texturePosition+time*0.07);\n\
1102     if( time < PART ) {\n\
1103         float sn1 = snoise(vec2(time*15.0, 20.0*v_texturePosition.y));\n\
1104         float sn2 = snoise(v_texturePosition);\n\
1105         if (sn1 > 1.0 - time*time && sn2 < 2.0*time+0.1)\n\
1106 	        gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
1107         else if (time > START )\n\
1108             gl_FragColor = ((time-START)/(PART - START))*vec4(sn, sn, sn, 1.0) + (1.0 - (time - START)/(PART - START))*texture2D(leavingSlideTexture, v_texturePosition);\n\
1109         else\n\
1110             gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
1111     } else if ( time < PART ) {\n\
1112             gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
1113     } else if ( time > END ) {\n\
1114         gl_FragColor = ((1.0 - time)/(1.0 - END))*vec4(sn, sn, sn, 1.0) + ((time - END)/(1.0 - END))*texture2D(enteringSlideTexture, v_texturePosition);\n\
1115     } else \n\
1116 	    gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
1117 }\n\
1118 ";
1119 
1120 static const char* dissolveFragmentShader = "\n\
1121 uniform sampler2D leavingSlideTexture;\n\
1122 uniform sampler2D enteringSlideTexture;\n\
1123 uniform sampler2D permTexture;\n\
1124 uniform float time;\n\
1125 varying vec2 v_texturePosition;\n\
1126 \n\
1127 float snoise(vec2 P) {\n\
1128 \n\
1129   return texture2D(permTexture, P).r;\n\
1130 }\n\
1131 \n\
1132 void main() {\n\
1133      float sn = snoise(10.0*v_texturePosition);\n\
1134      if( sn < time)\n\
1135          gl_FragColor = texture2D(enteringSlideTexture, v_texturePosition);\n\
1136      else\n\
1137          gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
1138 }\n\
1139 ";
1140 
1141 int permutation256 [256]= {
1142 215, 100, 200, 204, 233,  50,  85, 196,
1143  71, 141, 122, 160,  93, 131, 243, 234,
1144 162, 183,  36, 155,   4,  62,  35, 205,
1145  40, 102,  33,  27, 255,  55, 214, 156,
1146  75, 163, 134, 126, 249,  74, 197, 228,
1147  72,  90, 206, 235,  17,  22,  49, 169,
1148 227,  89,  16,   5, 117,  60, 248, 230,
1149 217,  68, 138,  96, 194, 170, 136,  10,
1150 112, 238, 184, 189, 176,  42, 225, 212,
1151  84,  58, 175, 244, 150, 168, 219, 236,
1152 101, 208, 123,  37, 164, 110, 158, 201,
1153  78, 114,  57,  48,  70, 142, 106,  43,
1154 232,  26,  32, 252, 239,  98, 191,  94,
1155  59, 149,  39, 187, 203, 190,  19,  13,
1156 133,  45,  61, 247,  23,  34,  20,  52,
1157 118, 209, 146, 193, 222,  18,   1, 152,
1158  46,  41,  91, 148, 115,  25, 135,  77,
1159 254, 147, 224, 161,   9, 213, 223, 250,
1160 231, 251, 127, 166,  63, 179,  81, 130,
1161 139,  28, 120, 151, 241,  86, 111,   0,
1162  88, 153, 172, 182, 159, 105, 178,  47,
1163  51, 167,  65,  66,  92,  73, 198, 211,
1164 245, 195,  31, 220, 140,  76, 221, 186,
1165 154, 185,  56,  83,  38, 165, 109,  67,
1166 124, 226, 132,  53, 229,  29,  12, 181,
1167 121,  24, 207, 199, 177, 113,  30,  80,
1168   3,  97, 188,  79, 216, 173,   8, 145,
1169  87, 128, 180, 237, 240, 137, 125, 104,
1170  15, 242, 119, 246, 103, 143,  95, 144,
1171   2,  44,  69, 157, 192, 174,  14,  54,
1172 218,  82,  64, 210,  11,   6, 129,  21,
1173 116, 171,  99, 202,   7, 107, 253, 108
1174 };
1175 
1176 void initPermTexture(GLuint *texID)
1177 {
1178   glGenTextures(1, texID);
1179   glBindTexture(GL_TEXTURE_2D, *texID);
1180 
1181   static bool initialized = false;
1182   static unsigned char permutation2D[256*256*4];
1183   if( !initialized ) {
1184       int x, y;
1185 
1186       for( y=0; y < 256; y++ )
1187           for( x=0; x < 256; x++ )
1188               permutation2D[x*4 + y*1024] = permutation256[(y + permutation256[x]) & 0xff];
1189 
1190       initialized = true;
1191   }
1192 
1193   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, permutation2D );
1194   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1195   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1196 }
1197 
1198 void OGLTransitionImpl::preparePermShader()
1199 {
1200 #ifdef GL_VERSION_2_0
1201     if( mProgramObject ) {
1202         OGLShaders::glUseProgram( mProgramObject );
1203 
1204         GLint location = OGLShaders::glGetUniformLocation( mProgramObject, "leavingSlideTexture" );
1205         if( location != -1 ) {
1206             OGLShaders::glUniform1i( location, 0 );  // texture unit 0
1207         }
1208 
1209         glActiveTexture(GL_TEXTURE1);
1210         if( !maHelperTexture )
1211             initPermTexture( &maHelperTexture );
1212         glActiveTexture(GL_TEXTURE0);
1213 
1214         location = OGLShaders::glGetUniformLocation( mProgramObject, "permTexture" );
1215         if( location != -1 ) {
1216             OGLShaders::glUniform1i( location, 1 );  // texture unit 1
1217         }
1218 
1219         location = OGLShaders::glGetUniformLocation( mProgramObject, "enteringSlideTexture" );
1220         if( location != -1 ) {
1221             OGLShaders::glUniform1i( location, 2 );  // texture unit 2
1222         }
1223     }
1224 #endif
1225 }
1226 
1227 void OGLTransitionImpl::prepareStatic( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
1228 {
1229     mProgramObject = OGLShaders::LinkProgram( basicVertexShader, staticFragmentShader );
1230 
1231     preparePermShader();
1232 }
1233 
1234 void OGLTransitionImpl::displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
1235                                               double SlideWidthScale, double SlideHeightScale )
1236 {
1237     applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
1238 
1239 #ifdef GL_VERSION_2_0
1240     if( mProgramObject ) {
1241         GLint location = OGLShaders::glGetUniformLocation( mProgramObject, "time" );
1242         if( location != -1 ) {
1243             OGLShaders::glUniform1f( location, nTime );
1244         }
1245     }
1246 
1247     glActiveTexture( GL_TEXTURE2 );
1248     glBindTexture( GL_TEXTURE_2D, glEnteringSlideTex );
1249     glActiveTexture( GL_TEXTURE0 );
1250 #endif
1251 
1252     displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
1253 }
1254 
1255 void OGLTransitionImpl::makeStatic()
1256 {
1257     Primitive Slide;
1258 
1259     Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
1260     Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
1261     maLeavingSlidePrimitives.push_back (Slide);
1262     maEnteringSlidePrimitives.push_back (Slide);
1263 
1264     mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
1265     mmPrepareTransition = &OGLTransitionImpl::prepareStatic;
1266     mbUseMipMapLeaving = mbUseMipMapEntering = false;
1267 
1268     mnRequiredGLVersion = 2.0;
1269 }
1270 
1271 void OGLTransitionImpl::prepareDissolve( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
1272 {
1273     mProgramObject = OGLShaders::LinkProgram( basicVertexShader, dissolveFragmentShader );
1274 
1275     preparePermShader();
1276 }
1277 
1278 void OGLTransitionImpl::makeDissolve()
1279 {
1280     Primitive Slide;
1281 
1282     Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
1283     Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
1284     maLeavingSlidePrimitives.push_back (Slide);
1285     maEnteringSlidePrimitives.push_back (Slide);
1286 
1287     mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
1288     mmPrepareTransition = &OGLTransitionImpl::prepareDissolve;
1289     mbUseMipMapLeaving = mbUseMipMapEntering = false;
1290 
1291     mnRequiredGLVersion = 2.0;
1292 }
1293 
1294 void OGLTransitionImpl::makeNewsflash()
1295 {
1296     Primitive Slide;
1297 
1298     Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
1299     Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
1300     Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),3000,true,0,0.5));
1301     Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),true,0,0.5));
1302     Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-10000, 0, 0),false, 0.5, 2));
1303     maLeavingSlidePrimitives.push_back(Slide);
1304 
1305     Slide.Operations.clear();
1306     Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),-3000,true,0.5,1));
1307     Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-100, 0, 0),false, -1, 1));
1308     Slide.Operations.push_back(new STranslate(basegfx::B3DVector(100, 0, 0),false, 0.5, 1));
1309     Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),false,-1,1));
1310     Slide.Operations.push_back(new SScale(basegfx::B3DVector(100,100,100),basegfx::B3DVector(0,0,0),true,0.5,1));
1311     maEnteringSlidePrimitives.push_back(Slide);
1312 
1313     OverallOperations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0.2,0.2,0),1080,true,0,1));
1314 }
1315 
1316