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