f760dcfc9820b102d204d6118db1cb7c11e2d609
[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   Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
38   myAttribs = new Graphic3d_Buffer (anAlloc);
39
40   myDrawMode = GL_TRIANGLE_STRIP;
41
42   myGradientParams.color1 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
43   myGradientParams.color2 = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
44   myGradientParams.type   = Aspect_GFM_NONE;
45 }
46
47 // =======================================================================
48 // method  : SetTextureParameters
49 // purpose :
50 // =======================================================================
51 void OpenGl_BackgroundArray::SetTextureParameters (const Aspect_FillMethod theFillMethod)
52 {
53   if (myType != Graphic3d_TOB_TEXTURE)
54   {
55     return;
56   }
57
58   myFillMethod = theFillMethod;
59   invalidateData();
60 }
61
62 // =======================================================================
63 // method  : SetTextureFillMethod
64 // purpose :
65 // =======================================================================
66 void OpenGl_BackgroundArray::SetTextureFillMethod (const Aspect_FillMethod theFillMethod)
67 {
68   myFillMethod = theFillMethod;
69   invalidateData();
70 }
71
72 // =======================================================================
73 // method  : SetGradientParameters
74 // purpose :
75 // =======================================================================
76 void OpenGl_BackgroundArray::SetGradientParameters (const Quantity_Color&           theColor1,
77                                                     const Quantity_Color&           theColor2,
78                                                     const Aspect_GradientFillMethod theType)
79 {
80   if (myType != Graphic3d_TOB_GRADIENT)
81   {
82     return;
83   }
84
85   Standard_Real anR, aG, aB;
86   theColor1.Values (anR, aG, aB, Quantity_TOC_RGB);
87   myGradientParams.color1 = OpenGl_Vec4 ((float)anR, (float)aG, (float)aB, 0.0f);
88
89   theColor2.Values (anR, aG, aB, Quantity_TOC_RGB);
90   myGradientParams.color2 = OpenGl_Vec4 ((float)anR, (float)aG, (float)aB, 0.0f);
91
92   myGradientParams.type = theType;
93   invalidateData();
94 }
95
96 // =======================================================================
97 // method  : SetGradientFillMethod
98 // purpose :
99 // =======================================================================
100 void OpenGl_BackgroundArray::SetGradientFillMethod (const Aspect_GradientFillMethod theType)
101 {
102   if (myType != Graphic3d_TOB_GRADIENT)
103   {
104     return;
105   }
106
107   myGradientParams.type = theType;
108   invalidateData();
109 }
110
111 // =======================================================================
112 // method  : IsDefined
113 // purpose :
114 // =======================================================================
115 bool OpenGl_BackgroundArray::IsDefined() const
116 {
117   switch (myType)
118   {
119     case Graphic3d_TOB_GRADIENT: return myGradientParams.type != Aspect_GFM_NONE;
120     case Graphic3d_TOB_TEXTURE:  return myFillMethod          != Aspect_FM_NONE;
121     case Graphic3d_TOB_NONE:     return Standard_False;
122   }
123   return Standard_False;
124 }
125
126 // =======================================================================
127 // method  : invalidateData
128 // purpose :
129 // =======================================================================
130 void OpenGl_BackgroundArray::invalidateData()
131 {
132   myToUpdate = Standard_True;
133 }
134
135 // =======================================================================
136 // method  : init
137 // purpose :
138 // =======================================================================
139 Standard_Boolean OpenGl_BackgroundArray::init (const Handle(OpenGl_Workspace)& theWorkspace) const
140 {
141   switch (myType)
142   {
143     case Graphic3d_TOB_GRADIENT:
144     {
145       if (!createGradientArray())
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_NONE:
160     default:
161     {
162       return Standard_False;
163     }
164   }
165
166   // Init VBO
167   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
168   if (myIsVboInit)
169   {
170     clearMemoryGL (aCtx);
171   }
172   buildVBO (aCtx, Standard_True);
173   myIsVboInit = Standard_True;
174
175   // Data is up-to-date
176   myToUpdate = Standard_False;
177   return Standard_True;
178 }
179
180 // =======================================================================
181 // method  : createGradientArray
182 // purpose :
183 // =======================================================================
184 Standard_Boolean OpenGl_BackgroundArray::createGradientArray() const
185 {
186   // Initialize data for primitive array
187   Graphic3d_Attribute aGragientAttribInfo[] =
188   {
189     { Graphic3d_TOA_POS,   Graphic3d_TOD_VEC2 },
190     { Graphic3d_TOA_COLOR, Graphic3d_TOD_VEC3 }
191   };
192
193   if (!myAttribs->Init (4, aGragientAttribInfo, 2))
194   {
195     return Standard_False;
196   }
197
198   OpenGl_Vec2 aVertices[4] =
199   {
200     OpenGl_Vec2(float(myViewWidth), 0.0f),
201     OpenGl_Vec2(float(myViewWidth), float(myViewHeight)),
202     OpenGl_Vec2(0.0f,               0.0f),
203     OpenGl_Vec2(0.0f,               float(myViewHeight))
204   };
205
206   float* aCorners[4]     = {};
207   float  aDiagCorner1[3] = {};
208   float  aDiagCorner2[3] = {};
209
210   switch (myGradientParams.type)
211   {
212     case Aspect_GFM_HOR:
213     {
214       aCorners[0] = myGradientParams.color2.ChangeData();
215       aCorners[1] = myGradientParams.color2.ChangeData();
216       aCorners[2] = myGradientParams.color1.ChangeData();
217       aCorners[3] = myGradientParams.color1.ChangeData();
218       break;
219     }
220     case Aspect_GFM_VER:
221     {
222       aCorners[0] = myGradientParams.color2.ChangeData();
223       aCorners[1] = myGradientParams.color1.ChangeData();
224       aCorners[2] = myGradientParams.color2.ChangeData();
225       aCorners[3] = myGradientParams.color1.ChangeData();
226       break;
227     }
228     case Aspect_GFM_DIAG1:
229     {
230       aCorners[0] = myGradientParams.color2.ChangeData();
231       aCorners[3] = myGradientParams.color1.ChangeData();
232       aDiagCorner1[0] = aDiagCorner2[0] = 0.5f * (aCorners[0][0] + aCorners[3][0]);
233       aDiagCorner1[1] = aDiagCorner2[1] = 0.5f * (aCorners[0][1] + aCorners[3][1]);
234       aDiagCorner1[2] = aDiagCorner2[2] = 0.5f * (aCorners[0][2] + aCorners[3][2]);
235       aCorners[1] = aDiagCorner1;
236       aCorners[2] = aDiagCorner2;
237       break;
238     }
239     case Aspect_GFM_DIAG2:
240     {
241       aCorners[1] = myGradientParams.color1.ChangeData();
242       aCorners[2] = myGradientParams.color2.ChangeData();
243       aDiagCorner1[0] = aDiagCorner2[0] = 0.5f * (aCorners[1][0] + aCorners[2][0]);
244       aDiagCorner1[1] = aDiagCorner2[1] = 0.5f * (aCorners[1][1] + aCorners[2][1]);
245       aDiagCorner1[2] = aDiagCorner2[2] = 0.5f * (aCorners[1][2] + aCorners[2][2]);
246       aCorners[0] = aDiagCorner1;
247       aCorners[3] = aDiagCorner2;
248       break;
249     }
250     case Aspect_GFM_CORNER1:
251     {
252       aVertices[0] = OpenGl_Vec2(float(myViewWidth), float(myViewHeight));
253       aVertices[1] = OpenGl_Vec2(0.0f,               float(myViewHeight));
254       aVertices[2] = OpenGl_Vec2(float(myViewWidth), 0.0f);
255       aVertices[3] = OpenGl_Vec2(0.0f,               0.0f);
256
257       aCorners[0] = myGradientParams.color2.ChangeData();
258       aCorners[1] = myGradientParams.color1.ChangeData();
259       aCorners[2] = myGradientParams.color2.ChangeData();
260       aCorners[3] = myGradientParams.color2.ChangeData();
261       break;
262     }
263     case Aspect_GFM_CORNER2:
264     {
265       aCorners[0] = myGradientParams.color2.ChangeData();
266       aCorners[1] = myGradientParams.color1.ChangeData();
267       aCorners[2] = myGradientParams.color2.ChangeData();
268       aCorners[3] = myGradientParams.color2.ChangeData();
269       break;
270     }
271     case Aspect_GFM_CORNER3:
272     {
273       aVertices[0] = OpenGl_Vec2(float(myViewWidth), float(myViewHeight));
274       aVertices[1] = OpenGl_Vec2(0.0f,               float(myViewHeight));
275       aVertices[2] = OpenGl_Vec2(float(myViewWidth), 0.0f);
276       aVertices[3] = OpenGl_Vec2(0.0f,               0.0f);
277
278       aCorners[0] = myGradientParams.color2.ChangeData();
279       aCorners[1] = myGradientParams.color2.ChangeData();
280       aCorners[2] = myGradientParams.color1.ChangeData();
281       aCorners[3] = myGradientParams.color2.ChangeData();
282       break;
283     }
284     case Aspect_GFM_CORNER4:
285     {
286       aCorners[0] = myGradientParams.color2.ChangeData();
287       aCorners[1] = myGradientParams.color2.ChangeData();
288       aCorners[2] = myGradientParams.color1.ChangeData();
289       aCorners[3] = myGradientParams.color2.ChangeData();
290       break;
291     }
292     case Aspect_GFM_NONE:
293     {
294       break;
295     }
296   }
297
298   for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
299   {
300     OpenGl_Vec2* aVertData  = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (anIt));
301     *aVertData = aVertices[anIt];
302
303     OpenGl_Vec3* aColorData = reinterpret_cast<OpenGl_Vec3* >(myAttribs->changeValue (anIt) + myAttribs->AttributeOffset (1));
304     *aColorData = OpenGl_Vec3(aCorners[anIt][0], aCorners[anIt][1], aCorners[anIt][2]);
305   }
306
307   return Standard_True;
308 }
309
310 // =======================================================================
311 // method  : createTextureArray
312 // purpose :
313 // =======================================================================
314 Standard_Boolean OpenGl_BackgroundArray::createTextureArray (const Handle(OpenGl_Workspace)& theWorkspace) const
315 {
316   Graphic3d_Attribute aTextureAttribInfo[] =
317   {
318     { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2 },
319     { Graphic3d_TOA_UV,  Graphic3d_TOD_VEC2 }
320   };
321
322   if (!myAttribs->Init (4, aTextureAttribInfo, 2))
323   {
324     return Standard_False;
325   }
326
327   GLfloat aTexRangeX = 1.0f; // texture <s> coordinate
328   GLfloat aTexRangeY = 1.0f; // texture <t> coordinate
329
330   // Set up for stretching or tiling
331   GLfloat anOffsetX = 0.5f * (float )myViewWidth;
332   GLfloat anOffsetY = 0.5f * (float )myViewHeight;
333
334   // Setting this coefficient to -1.0f allows to tile textures relatively to the top-left corner of the view
335   // (value 1.0f corresponds to the initial behavior - tiling from the bottom-left corner)
336   GLfloat aCoef = -1.0f;
337
338   // Get texture parameters
339   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
340   const OpenGl_AspectFace* anAspectFace = theWorkspace->AspectFace();
341   GLfloat aTextureWidth  = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeX();
342   GLfloat aTextureHeight = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeY();
343
344   if (myFillMethod == Aspect_FM_CENTERED)
345   {
346     anOffsetX = 0.5f * aTextureWidth;
347     anOffsetY = 0.5f * aTextureHeight;
348   }
349   else if (myFillMethod == Aspect_FM_TILED)
350   {
351     aTexRangeX = (GLfloat )myViewWidth  / aTextureWidth;
352     aTexRangeY = (GLfloat )myViewHeight / aTextureHeight;
353   }
354
355   // NOTE: texture is mapped using GL_REPEAT wrapping mode so integer part
356   // is simply ignored, and negative multiplier is here for convenience only
357   // and does not result e.g. in texture mirroring
358
359
360   OpenGl_Vec2* aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (0));
361   aData[0] = OpenGl_Vec2 (anOffsetX, -aCoef * anOffsetY);
362   aData[1] = OpenGl_Vec2 (aTexRangeX, 0.0f);
363
364   aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (1));
365   aData[0] = OpenGl_Vec2 (anOffsetX,  aCoef * anOffsetY);
366   aData[1] = OpenGl_Vec2 (aTexRangeX, aCoef * aTexRangeY);
367
368   aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (2));
369   aData[0] = OpenGl_Vec2 (-anOffsetX, -aCoef * anOffsetY);
370   aData[1] = OpenGl_Vec2 (0.0f, 0.0f);
371
372   aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (3));
373   aData[0] = OpenGl_Vec2 (-anOffsetX, aCoef * anOffsetY);
374   aData[1] = OpenGl_Vec2 (0.0f, aCoef * aTexRangeY);
375
376   return Standard_True;
377 }
378
379 // =======================================================================
380 // method  : createTextureArray
381 // purpose :
382 // =======================================================================
383 void OpenGl_BackgroundArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
384 {
385   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
386   Standard_Integer aViewSizeX = aCtx->Viewport()[2];
387   Standard_Integer aViewSizeY = aCtx->Viewport()[3];
388   if (theWorkspace->View()->Camera()->Tile().IsValid())
389   {
390     aViewSizeX = theWorkspace->View()->Camera()->Tile().TotalSize.x();
391     aViewSizeY = theWorkspace->View()->Camera()->Tile().TotalSize.y();
392   }
393   if (myToUpdate
394    || myViewWidth  != aViewSizeX
395    || myViewHeight != aViewSizeY)
396   {
397     myViewWidth  = aViewSizeX;
398     myViewHeight = aViewSizeY;
399     init (theWorkspace);
400   }
401
402   OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
403   OpenGl_Mat4 aWorldView  = aCtx->WorldViewState.Current();
404   myTrsfPers.Apply (theWorkspace->View()->Camera(), aProjection, aWorldView,
405                     aCtx->Viewport()[2], aCtx->Viewport()[3]);
406
407   aCtx->ProjectionState.Push();
408   aCtx->WorldViewState.Push();
409   aCtx->ProjectionState.SetCurrent (aProjection);
410   aCtx->WorldViewState.SetCurrent (aWorldView);
411   aCtx->ApplyProjectionMatrix();
412   aCtx->ApplyModelViewMatrix();
413
414   OpenGl_PrimitiveArray::Render (theWorkspace);
415
416   aCtx->ProjectionState.Pop();
417   aCtx->WorldViewState.Pop();
418   aCtx->ApplyProjectionMatrix();
419 }