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