0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[occt.git] / src / OpenGl / OpenGl_BackgroundArray.cxx
1 // Created on: 2015-01-16
2 // Created by: Anastasia BORISOVA
3 // Copyright (c) 2015 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_BackgroundArray.hxx>
17
18 #include <Aspect_FillMethod.hxx>
19 #include <NCollection_AlignedAllocator.hxx>
20 #include <OpenGl_Texture.hxx>
21 #include <OpenGl_View.hxx>
22 #include <Graphic3d_TextureParams.hxx>
23
24 // =======================================================================
25 // method  : Constructor
26 // purpose :
27 // =======================================================================
28 OpenGl_BackgroundArray::OpenGl_BackgroundArray (const Graphic3d_TypeOfBackground theType)
29 : OpenGl_PrimitiveArray (NULL, Graphic3d_TOPA_TRIANGLESTRIPS, NULL, NULL, NULL),
30   myTrsfPers (Graphic3d_TMF_2d, theType == Graphic3d_TOB_TEXTURE ? Aspect_TOTP_CENTER : Aspect_TOTP_LEFT_LOWER),
31   myType (theType),
32   myFillMethod (Aspect_FM_NONE),
33   myViewWidth (0),
34   myViewHeight (0),
35   myToUpdate (Standard_False)
36 {
37   myDrawMode = GL_TRIANGLE_STRIP;
38   myIsFillType = true;
39
40   myGradientParams.color1 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
41   myGradientParams.color2 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
42   myGradientParams.type   = Aspect_GFM_NONE;
43 }
44
45 // =======================================================================
46 // method  : SetTextureParameters
47 // purpose :
48 // =======================================================================
49 void OpenGl_BackgroundArray::SetTextureParameters (const Aspect_FillMethod theFillMethod)
50 {
51   if (myType != Graphic3d_TOB_TEXTURE)
52   {
53     return;
54   }
55
56   myFillMethod = theFillMethod;
57   invalidateData();
58 }
59
60 // =======================================================================
61 // method  : SetTextureFillMethod
62 // purpose :
63 // =======================================================================
64 void OpenGl_BackgroundArray::SetTextureFillMethod (const Aspect_FillMethod theFillMethod)
65 {
66   myFillMethod = theFillMethod;
67   invalidateData();
68 }
69
70 // =======================================================================
71 // method  : SetGradientParameters
72 // purpose :
73 // =======================================================================
74 void OpenGl_BackgroundArray::SetGradientParameters (const Quantity_Color&           theColor1,
75                                                     const Quantity_Color&           theColor2,
76                                                     const Aspect_GradientFillMethod theType)
77 {
78   if (myType != Graphic3d_TOB_GRADIENT)
79   {
80     return;
81   }
82
83   Standard_Real anR, aG, aB;
84   theColor1.Values (anR, aG, aB, Quantity_TOC_RGB);
85   myGradientParams.color1 = OpenGl_Vec4 ((float)anR, (float)aG, (float)aB, 0.0f);
86
87   theColor2.Values (anR, aG, aB, Quantity_TOC_RGB);
88   myGradientParams.color2 = OpenGl_Vec4 ((float)anR, (float)aG, (float)aB, 0.0f);
89
90   myGradientParams.type = theType;
91   invalidateData();
92 }
93
94 // =======================================================================
95 // method  : SetGradientFillMethod
96 // purpose :
97 // =======================================================================
98 void OpenGl_BackgroundArray::SetGradientFillMethod (const Aspect_GradientFillMethod theType)
99 {
100   if (myType != Graphic3d_TOB_GRADIENT)
101   {
102     return;
103   }
104
105   myGradientParams.type = theType;
106   invalidateData();
107 }
108
109 // =======================================================================
110 // method  : IsDefined
111 // purpose :
112 // =======================================================================
113 bool OpenGl_BackgroundArray::IsDefined() const
114 {
115   switch (myType)
116   {
117     case Graphic3d_TOB_GRADIENT: return myGradientParams.type != Aspect_GFM_NONE;
118     case Graphic3d_TOB_TEXTURE:  return myFillMethod          != Aspect_FM_NONE;
119     case Graphic3d_TOB_CUBEMAP:  return Standard_True;
120     case Graphic3d_TOB_NONE:     return Standard_False;
121   }
122   return Standard_False;
123 }
124
125 // =======================================================================
126 // method  : invalidateData
127 // purpose :
128 // =======================================================================
129 void OpenGl_BackgroundArray::invalidateData()
130 {
131   myToUpdate = Standard_True;
132 }
133
134 // =======================================================================
135 // method  : init
136 // purpose :
137 // =======================================================================
138 Standard_Boolean OpenGl_BackgroundArray::init (const Handle(OpenGl_Workspace)& theWorkspace) const
139 {
140   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
141   switch (myType)
142   {
143     case Graphic3d_TOB_GRADIENT:
144     {
145       if (!createGradientArray (aCtx))
146       {
147         return Standard_False;
148       }
149       break;
150     }
151     case Graphic3d_TOB_TEXTURE:
152     {
153       if (!createTextureArray (theWorkspace))
154       {
155         return Standard_False;
156       }
157       break;
158     }
159     case Graphic3d_TOB_CUBEMAP:
160     {
161       if (!createCubeMapArray())
162       {
163         return Standard_False;
164       }
165       break;
166     }
167     case Graphic3d_TOB_NONE:
168     default:
169     {
170       return Standard_False;
171     }
172   }
173
174   // Init VBO
175   if (myIsVboInit)
176   {
177     clearMemoryGL (aCtx);
178   }
179   buildVBO (aCtx, Standard_True);
180   myIsVboInit = Standard_True;
181
182   // Data is up-to-date
183   myToUpdate = Standard_False;
184   return Standard_True;
185 }
186
187 // =======================================================================
188 // method  : createGradientArray
189 // purpose :
190 // =======================================================================
191 Standard_Boolean OpenGl_BackgroundArray::createGradientArray (const Handle(OpenGl_Context)& theCtx) const
192 {
193   // Initialize data for primitive array
194   Graphic3d_Attribute aGragientAttribInfo[] =
195   {
196     { Graphic3d_TOA_POS,   Graphic3d_TOD_VEC2 },
197     { Graphic3d_TOA_COLOR, Graphic3d_TOD_VEC3 }
198   };
199
200   if (myAttribs.IsNull())
201   {
202     Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
203     myAttribs = new Graphic3d_Buffer (anAlloc);
204   }
205   if (!myAttribs->Init (4, aGragientAttribInfo, 2))
206   {
207     return Standard_False;
208   }
209
210   OpenGl_Vec2 aVertices[4] =
211   {
212     OpenGl_Vec2(float(myViewWidth), 0.0f),
213     OpenGl_Vec2(float(myViewWidth), float(myViewHeight)),
214     OpenGl_Vec2(0.0f,               0.0f),
215     OpenGl_Vec2(0.0f,               float(myViewHeight))
216   };
217
218   float* aCorners[4]     = {};
219   float  aDiagCorner1[3] = {};
220   float  aDiagCorner2[3] = {};
221
222   switch (myGradientParams.type)
223   {
224     case Aspect_GFM_HOR:
225     {
226       aCorners[0] = myGradientParams.color2.ChangeData();
227       aCorners[1] = myGradientParams.color2.ChangeData();
228       aCorners[2] = myGradientParams.color1.ChangeData();
229       aCorners[3] = myGradientParams.color1.ChangeData();
230       break;
231     }
232     case Aspect_GFM_VER:
233     {
234       aCorners[0] = myGradientParams.color2.ChangeData();
235       aCorners[1] = myGradientParams.color1.ChangeData();
236       aCorners[2] = myGradientParams.color2.ChangeData();
237       aCorners[3] = myGradientParams.color1.ChangeData();
238       break;
239     }
240     case Aspect_GFM_DIAG1:
241     {
242       aCorners[0] = myGradientParams.color2.ChangeData();
243       aCorners[3] = myGradientParams.color1.ChangeData();
244       aDiagCorner1[0] = aDiagCorner2[0] = 0.5f * (aCorners[0][0] + aCorners[3][0]);
245       aDiagCorner1[1] = aDiagCorner2[1] = 0.5f * (aCorners[0][1] + aCorners[3][1]);
246       aDiagCorner1[2] = aDiagCorner2[2] = 0.5f * (aCorners[0][2] + aCorners[3][2]);
247       aCorners[1] = aDiagCorner1;
248       aCorners[2] = aDiagCorner2;
249       break;
250     }
251     case Aspect_GFM_DIAG2:
252     {
253       aCorners[1] = myGradientParams.color1.ChangeData();
254       aCorners[2] = myGradientParams.color2.ChangeData();
255       aDiagCorner1[0] = aDiagCorner2[0] = 0.5f * (aCorners[1][0] + aCorners[2][0]);
256       aDiagCorner1[1] = aDiagCorner2[1] = 0.5f * (aCorners[1][1] + aCorners[2][1]);
257       aDiagCorner1[2] = aDiagCorner2[2] = 0.5f * (aCorners[1][2] + aCorners[2][2]);
258       aCorners[0] = aDiagCorner1;
259       aCorners[3] = aDiagCorner2;
260       break;
261     }
262     case Aspect_GFM_CORNER1:
263     {
264       aVertices[0] = OpenGl_Vec2(float(myViewWidth), float(myViewHeight));
265       aVertices[1] = OpenGl_Vec2(0.0f,               float(myViewHeight));
266       aVertices[2] = OpenGl_Vec2(float(myViewWidth), 0.0f);
267       aVertices[3] = OpenGl_Vec2(0.0f,               0.0f);
268
269       aCorners[0] = myGradientParams.color2.ChangeData();
270       aCorners[1] = myGradientParams.color1.ChangeData();
271       aCorners[2] = myGradientParams.color2.ChangeData();
272       aCorners[3] = myGradientParams.color2.ChangeData();
273       break;
274     }
275     case Aspect_GFM_CORNER2:
276     {
277       aCorners[0] = myGradientParams.color2.ChangeData();
278       aCorners[1] = myGradientParams.color1.ChangeData();
279       aCorners[2] = myGradientParams.color2.ChangeData();
280       aCorners[3] = myGradientParams.color2.ChangeData();
281       break;
282     }
283     case Aspect_GFM_CORNER3:
284     {
285       aVertices[0] = OpenGl_Vec2(float(myViewWidth), float(myViewHeight));
286       aVertices[1] = OpenGl_Vec2(0.0f,               float(myViewHeight));
287       aVertices[2] = OpenGl_Vec2(float(myViewWidth), 0.0f);
288       aVertices[3] = OpenGl_Vec2(0.0f,               0.0f);
289
290       aCorners[0] = myGradientParams.color2.ChangeData();
291       aCorners[1] = myGradientParams.color2.ChangeData();
292       aCorners[2] = myGradientParams.color1.ChangeData();
293       aCorners[3] = myGradientParams.color2.ChangeData();
294       break;
295     }
296     case Aspect_GFM_CORNER4:
297     {
298       aCorners[0] = myGradientParams.color2.ChangeData();
299       aCorners[1] = myGradientParams.color2.ChangeData();
300       aCorners[2] = myGradientParams.color1.ChangeData();
301       aCorners[3] = myGradientParams.color2.ChangeData();
302       break;
303     }
304     case Aspect_GFM_NONE:
305     {
306       break;
307     }
308   }
309
310   for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
311   {
312     OpenGl_Vec2* aVertData  = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (anIt));
313     *aVertData = aVertices[anIt];
314
315     OpenGl_Vec3* aColorData = reinterpret_cast<OpenGl_Vec3* >(myAttribs->changeValue (anIt) + myAttribs->AttributeOffset (1));
316     *aColorData = theCtx->Vec4FromQuantityColor (OpenGl_Vec4(aCorners[anIt][0], aCorners[anIt][1], aCorners[anIt][2], 1.0f)).rgb();
317   }
318
319   return Standard_True;
320 }
321
322 // =======================================================================
323 // method  : createTextureArray
324 // purpose :
325 // =======================================================================
326 Standard_Boolean OpenGl_BackgroundArray::createTextureArray (const Handle(OpenGl_Workspace)& theWorkspace) const
327 {
328   Graphic3d_Attribute aTextureAttribInfo[] =
329   {
330     { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2 },
331     { Graphic3d_TOA_UV,  Graphic3d_TOD_VEC2 }
332   };
333
334   if (myAttribs.IsNull())
335   {
336     Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
337     myAttribs = new Graphic3d_Buffer (anAlloc);
338   }
339   if (!myAttribs->Init (4, aTextureAttribInfo, 2))
340   {
341     return Standard_False;
342   }
343
344   GLfloat aTexRangeX = 1.0f; // texture <s> coordinate
345   GLfloat aTexRangeY = 1.0f; // texture <t> coordinate
346
347   // Set up for stretching or tiling
348   GLfloat anOffsetX = 0.5f * (float )myViewWidth;
349   GLfloat anOffsetY = 0.5f * (float )myViewHeight;
350
351   // Setting this coefficient to -1.0f allows to tile textures relatively to the top-left corner of the view
352   // (value 1.0f corresponds to the initial behavior - tiling from the bottom-left corner)
353   GLfloat aCoef = -1.0f;
354
355   // Get texture parameters
356   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
357   const OpenGl_Aspects* anAspectFace = theWorkspace->Aspects();
358   GLfloat aTextureWidth  = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeX();
359   GLfloat aTextureHeight = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeY();
360
361   if (myFillMethod == Aspect_FM_CENTERED)
362   {
363     anOffsetX = 0.5f * aTextureWidth;
364     anOffsetY = 0.5f * aTextureHeight;
365   }
366   else if (myFillMethod == Aspect_FM_TILED)
367   {
368     aTexRangeX = (GLfloat )myViewWidth  / aTextureWidth;
369     aTexRangeY = (GLfloat )myViewHeight / aTextureHeight;
370   }
371
372   // NOTE: texture is mapped using GL_REPEAT wrapping mode so integer part
373   // is simply ignored, and negative multiplier is here for convenience only
374   // and does not result e.g. in texture mirroring
375
376
377   OpenGl_Vec2* aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (0));
378   aData[0] = OpenGl_Vec2 (anOffsetX, -aCoef * anOffsetY);
379   aData[1] = OpenGl_Vec2 (aTexRangeX, 0.0f);
380
381   aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (1));
382   aData[0] = OpenGl_Vec2 (anOffsetX,  aCoef * anOffsetY);
383   aData[1] = OpenGl_Vec2 (aTexRangeX, aCoef * aTexRangeY);
384
385   aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (2));
386   aData[0] = OpenGl_Vec2 (-anOffsetX, -aCoef * anOffsetY);
387   aData[1] = OpenGl_Vec2 (0.0f, 0.0f);
388
389   aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (3));
390   aData[0] = OpenGl_Vec2 (-anOffsetX, aCoef * anOffsetY);
391   aData[1] = OpenGl_Vec2 (0.0f, aCoef * aTexRangeY);
392
393   return Standard_True;
394 }
395
396 // =======================================================================
397 // method  : createCubeMapArray
398 // purpose :
399 // =======================================================================
400 Standard_Boolean OpenGl_BackgroundArray::createCubeMapArray() const
401 {
402   Graphic3d_Attribute aCubeMapAttribInfo[] =
403   {
404     { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2}
405   };
406
407   if (myAttribs.IsNull())
408   {
409     Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
410     myAttribs = new Graphic3d_Buffer (anAlloc);
411   }
412   if (!myAttribs->Init(4, aCubeMapAttribInfo, 1))
413   {
414     return Standard_False;
415   }
416
417   OpenGl_Vec2* aData = reinterpret_cast<OpenGl_Vec2*>(myAttribs->changeValue(0));
418
419   for (unsigned int i = 0; i < 4; ++i)
420   {
421     aData[i] = (OpenGl_Vec2(Standard_ShortReal(i / 2), Standard_ShortReal(i % 2)) - OpenGl_Vec2(0.5f)) * 2.f;
422   }
423
424   return Standard_True;
425 }
426
427 // =======================================================================
428 // method  : Render
429 // purpose :
430 // =======================================================================
431 void OpenGl_BackgroundArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
432 {
433   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
434   Standard_Integer aViewSizeX = aCtx->Viewport()[2];
435   Standard_Integer aViewSizeY = aCtx->Viewport()[3];
436   Graphic3d_Vec2i aTileOffset, aTileSize;
437
438   if (theWorkspace->View()->Camera()->Tile().IsValid())
439   {
440     aViewSizeX = theWorkspace->View()->Camera()->Tile().TotalSize.x();
441     aViewSizeY = theWorkspace->View()->Camera()->Tile().TotalSize.y();
442
443     aTileOffset = theWorkspace->View()->Camera()->Tile().OffsetLowerLeft();
444     aTileSize   = theWorkspace->View()->Camera()->Tile().TileSize;
445   }
446   if (myToUpdate
447    || myViewWidth  != aViewSizeX
448    || myViewHeight != aViewSizeY
449    || myAttribs.IsNull()
450    || myVboAttribs.IsNull())
451   {
452     myViewWidth  = aViewSizeX;
453     myViewHeight = aViewSizeY;
454     init (theWorkspace);
455   }
456
457   OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
458   OpenGl_Mat4 aWorldView  = aCtx->WorldViewState.Current();
459
460   if (myType != Graphic3d_TOB_CUBEMAP)
461   {
462     aProjection.InitIdentity();
463     aWorldView.InitIdentity();
464     if (theWorkspace->View()->Camera()->Tile().IsValid())
465     {
466       aWorldView.SetDiagonal (OpenGl_Vec4 (2.0f / aTileSize.x(), 2.0f / aTileSize.y(), 1.0f, 1.0f));
467       if (myType == Graphic3d_TOB_GRADIENT)
468       {
469         aWorldView.SetColumn (3, OpenGl_Vec4 (-1.0f - 2.0f * aTileOffset.x() / aTileSize.x(),
470                                               -1.0f - 2.0f * aTileOffset.y() / aTileSize.y(), 0.0f, 1.0f));
471       }
472       else
473       {
474         aWorldView.SetColumn (3, OpenGl_Vec4 (-1.0f + (float) aViewSizeX / aTileSize.x() - 2.0f * aTileOffset.x() / aTileSize.x(),
475                                               -1.0f + (float) aViewSizeY / aTileSize.y() - 2.0f * aTileOffset.y() / aTileSize.y(), 0.0f, 1.0f));
476       }
477     }
478     else
479     {
480       aWorldView.SetDiagonal (OpenGl_Vec4 (2.0f / myViewWidth, 2.0f / myViewHeight, 1.0f, 1.0f));
481       if (myType == Graphic3d_TOB_GRADIENT)
482       {
483         aWorldView.SetColumn (3, OpenGl_Vec4 (-1.0f, -1.0f, 0.0f, 1.0f));
484       }
485     }
486   }
487
488   aCtx->ProjectionState.Push();
489   aCtx->WorldViewState.Push();
490   aCtx->ProjectionState.SetCurrent (aProjection);
491   aCtx->WorldViewState.SetCurrent (aWorldView);
492   aCtx->ApplyProjectionMatrix();
493   aCtx->ApplyModelViewMatrix();
494
495   OpenGl_PrimitiveArray::Render (theWorkspace);
496
497   aCtx->ProjectionState.Pop();
498   aCtx->WorldViewState.Pop();
499   aCtx->ApplyProjectionMatrix();
500 }