0031082: Visualization - crash on display if there are no lights in the view
[occt.git] / src / OpenGl / OpenGl_BackgroundArray.cxx
CommitLineData
0b0320e7 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>
3bffef55 21#include <OpenGl_View.hxx>
c04c30b3 22#include <Graphic3d_TextureParams.hxx>
0b0320e7 23
24// =======================================================================
25// method : Constructor
26// purpose :
27// =======================================================================
28OpenGl_BackgroundArray::OpenGl_BackgroundArray (const Graphic3d_TypeOfBackground theType)
29: OpenGl_PrimitiveArray (NULL, Graphic3d_TOPA_TRIANGLESTRIPS, NULL, NULL, NULL),
778cd667 30 myTrsfPers (Graphic3d_TMF_2d, theType == Graphic3d_TOB_TEXTURE ? Aspect_TOTP_CENTER : Aspect_TOTP_LEFT_LOWER),
0b0320e7 31 myType (theType),
3bffef55 32 myFillMethod (Aspect_FM_NONE),
0b0320e7 33 myViewWidth (0),
34 myViewHeight (0),
3bffef55 35 myToUpdate (Standard_False)
0b0320e7 36{
d5846489 37 myDrawMode = GL_TRIANGLE_STRIP;
6ef0d6f1 38 myIsFillType = true;
0b0320e7 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// =======================================================================
49void 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// =======================================================================
64void OpenGl_BackgroundArray::SetTextureFillMethod (const Aspect_FillMethod theFillMethod)
65{
66 myFillMethod = theFillMethod;
67 invalidateData();
68}
69
70// =======================================================================
71// method : SetGradientParameters
72// purpose :
73// =======================================================================
74void 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// =======================================================================
98void 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// =======================================================================
113bool 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;
077a220c 119 case Graphic3d_TOB_CUBEMAP: return Standard_True;
0b0320e7 120 case Graphic3d_TOB_NONE: return Standard_False;
121 }
122 return Standard_False;
123}
124
125// =======================================================================
126// method : invalidateData
127// purpose :
128// =======================================================================
129void OpenGl_BackgroundArray::invalidateData()
130{
131 myToUpdate = Standard_True;
132}
133
134// =======================================================================
3bffef55 135// method : init
0b0320e7 136// purpose :
137// =======================================================================
3bffef55 138Standard_Boolean OpenGl_BackgroundArray::init (const Handle(OpenGl_Workspace)& theWorkspace) const
0b0320e7 139{
ba00aab7 140 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
0b0320e7 141 switch (myType)
142 {
143 case Graphic3d_TOB_GRADIENT:
144 {
ba00aab7 145 if (!createGradientArray (aCtx))
0b0320e7 146 {
147 return Standard_False;
148 }
149 break;
150 }
151 case Graphic3d_TOB_TEXTURE:
152 {
0b0320e7 153 if (!createTextureArray (theWorkspace))
154 {
155 return Standard_False;
156 }
157 break;
158 }
077a220c 159 case Graphic3d_TOB_CUBEMAP:
160 {
161 if (!createCubeMapArray())
162 {
163 return Standard_False;
164 }
165 break;
166 }
0b0320e7 167 case Graphic3d_TOB_NONE:
168 default:
169 {
170 return Standard_False;
171 }
172 }
173
174 // Init VBO
0b0320e7 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// =======================================================================
ba00aab7 191Standard_Boolean OpenGl_BackgroundArray::createGradientArray (const Handle(OpenGl_Context)& theCtx) const
0b0320e7 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
ba00aab7 200 if (myAttribs.IsNull())
201 {
202 Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
203 myAttribs = new Graphic3d_Buffer (anAlloc);
204 }
0b0320e7 205 if (!myAttribs->Init (4, aGragientAttribInfo, 2))
206 {
207 return Standard_False;
208 }
209
210 OpenGl_Vec2 aVertices[4] =
211 {
3bffef55 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))
0b0320e7 216 };
217
b6472664 218 float* aCorners[4] = {};
219 float aDiagCorner1[3] = {};
220 float aDiagCorner2[3] = {};
0b0320e7 221
222 switch (myGradientParams.type)
223 {
224 case Aspect_GFM_HOR:
225 {
bc379358 226 aCorners[0] = myGradientParams.color2.ChangeData();
227 aCorners[1] = myGradientParams.color2.ChangeData();
228 aCorners[2] = myGradientParams.color1.ChangeData();
229 aCorners[3] = myGradientParams.color1.ChangeData();
0b0320e7 230 break;
231 }
232 case Aspect_GFM_VER:
233 {
bc379358 234 aCorners[0] = myGradientParams.color2.ChangeData();
235 aCorners[1] = myGradientParams.color1.ChangeData();
236 aCorners[2] = myGradientParams.color2.ChangeData();
237 aCorners[3] = myGradientParams.color1.ChangeData();
0b0320e7 238 break;
239 }
240 case Aspect_GFM_DIAG1:
241 {
bc379358 242 aCorners[0] = myGradientParams.color2.ChangeData();
243 aCorners[3] = myGradientParams.color1.ChangeData();
d5846489 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;
0b0320e7 248 aCorners[2] = aDiagCorner2;
249 break;
250 }
251 case Aspect_GFM_DIAG2:
252 {
bc379358 253 aCorners[1] = myGradientParams.color1.ChangeData();
254 aCorners[2] = myGradientParams.color2.ChangeData();
d5846489 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;
0b0320e7 259 aCorners[3] = aDiagCorner2;
260 break;
261 }
262 case Aspect_GFM_CORNER1:
263 {
3bffef55 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);
d5846489 268
bc379358 269 aCorners[0] = myGradientParams.color2.ChangeData();
270 aCorners[1] = myGradientParams.color1.ChangeData();
271 aCorners[2] = myGradientParams.color2.ChangeData();
272 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 273 break;
274 }
275 case Aspect_GFM_CORNER2:
276 {
bc379358 277 aCorners[0] = myGradientParams.color2.ChangeData();
278 aCorners[1] = myGradientParams.color1.ChangeData();
279 aCorners[2] = myGradientParams.color2.ChangeData();
280 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 281 break;
282 }
283 case Aspect_GFM_CORNER3:
284 {
3bffef55 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);
d5846489 289
bc379358 290 aCorners[0] = myGradientParams.color2.ChangeData();
291 aCorners[1] = myGradientParams.color2.ChangeData();
292 aCorners[2] = myGradientParams.color1.ChangeData();
293 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 294 break;
295 }
296 case Aspect_GFM_CORNER4:
297 {
bc379358 298 aCorners[0] = myGradientParams.color2.ChangeData();
299 aCorners[1] = myGradientParams.color2.ChangeData();
300 aCorners[2] = myGradientParams.color1.ChangeData();
301 aCorners[3] = myGradientParams.color2.ChangeData();
0b0320e7 302 break;
303 }
304 case Aspect_GFM_NONE:
305 {
306 break;
307 }
308 }
309
d5846489 310 for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
0b0320e7 311 {
d5846489 312 OpenGl_Vec2* aVertData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (anIt));
313 *aVertData = aVertices[anIt];
0b0320e7 314
d5846489 315 OpenGl_Vec3* aColorData = reinterpret_cast<OpenGl_Vec3* >(myAttribs->changeValue (anIt) + myAttribs->AttributeOffset (1));
ba00aab7 316 *aColorData = theCtx->Vec4FromQuantityColor (OpenGl_Vec4(aCorners[anIt][0], aCorners[anIt][1], aCorners[anIt][2], 1.0f)).rgb();
0b0320e7 317 }
318
319 return Standard_True;
320}
321
322// =======================================================================
323// method : createTextureArray
324// purpose :
325// =======================================================================
3bffef55 326Standard_Boolean OpenGl_BackgroundArray::createTextureArray (const Handle(OpenGl_Workspace)& theWorkspace) const
0b0320e7 327{
328 Graphic3d_Attribute aTextureAttribInfo[] =
329 {
330 { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2 },
331 { Graphic3d_TOA_UV, Graphic3d_TOD_VEC2 }
332 };
333
ba00aab7 334 if (myAttribs.IsNull())
335 {
336 Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
337 myAttribs = new Graphic3d_Buffer (anAlloc);
338 }
0b0320e7 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
3bffef55 348 GLfloat anOffsetX = 0.5f * (float )myViewWidth;
349 GLfloat anOffsetY = 0.5f * (float )myViewHeight;
0b0320e7 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();
bf5f0ca2 357 const OpenGl_Aspects* anAspectFace = theWorkspace->Aspects();
cc8cbabe 358 GLfloat aTextureWidth = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeX();
359 GLfloat aTextureHeight = (GLfloat )anAspectFace->TextureSet (aCtx)->First()->SizeY();
0b0320e7 360
361 if (myFillMethod == Aspect_FM_CENTERED)
362 {
3bffef55 363 anOffsetX = 0.5f * aTextureWidth;
364 anOffsetY = 0.5f * aTextureHeight;
0b0320e7 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
0b0320e7 376
d5846489 377 OpenGl_Vec2* aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (0));
0b0320e7 378 aData[0] = OpenGl_Vec2 (anOffsetX, -aCoef * anOffsetY);
379 aData[1] = OpenGl_Vec2 (aTexRangeX, 0.0f);
380
d5846489 381 aData = reinterpret_cast<OpenGl_Vec2* >(myAttribs->changeValue (1));
0b0320e7 382 aData[0] = OpenGl_Vec2 (anOffsetX, aCoef * anOffsetY);
383 aData[1] = OpenGl_Vec2 (aTexRangeX, aCoef * aTexRangeY);
384
d5846489 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
0b0320e7 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}
3bffef55 395
396// =======================================================================
077a220c 397// method : createCubeMapArray
398// purpose :
399// =======================================================================
400Standard_Boolean OpenGl_BackgroundArray::createCubeMapArray() const
401{
402 Graphic3d_Attribute aCubeMapAttribInfo[] =
403 {
404 { Graphic3d_TOA_POS, Graphic3d_TOD_VEC2}
405 };
406
ba00aab7 407 if (myAttribs.IsNull())
408 {
409 Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
410 myAttribs = new Graphic3d_Buffer (anAlloc);
411 }
077a220c 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
3bffef55 429// purpose :
430// =======================================================================
431void 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 if (theWorkspace->View()->Camera()->Tile().IsValid())
437 {
438 aViewSizeX = theWorkspace->View()->Camera()->Tile().TotalSize.x();
439 aViewSizeY = theWorkspace->View()->Camera()->Tile().TotalSize.y();
440 }
441 if (myToUpdate
442 || myViewWidth != aViewSizeX
ba00aab7 443 || myViewHeight != aViewSizeY
444 || myAttribs.IsNull()
445 || myVboAttribs.IsNull())
3bffef55 446 {
447 myViewWidth = aViewSizeX;
448 myViewHeight = aViewSizeY;
449 init (theWorkspace);
450 }
451
452 OpenGl_Mat4 aProjection = aCtx->ProjectionState.Current();
453 OpenGl_Mat4 aWorldView = aCtx->WorldViewState.Current();
077a220c 454
455 if (myType != Graphic3d_TOB_CUBEMAP)
456 {
457 myTrsfPers.Apply(theWorkspace->View()->Camera(), aProjection, aWorldView,
458 aCtx->Viewport()[2], aCtx->Viewport()[3]);
459 }
3bffef55 460
461 aCtx->ProjectionState.Push();
462 aCtx->WorldViewState.Push();
463 aCtx->ProjectionState.SetCurrent (aProjection);
464 aCtx->WorldViewState.SetCurrent (aWorldView);
465 aCtx->ApplyProjectionMatrix();
466 aCtx->ApplyModelViewMatrix();
467
468 OpenGl_PrimitiveArray::Render (theWorkspace);
469
470 aCtx->ProjectionState.Pop();
471 aCtx->WorldViewState.Pop();
472 aCtx->ApplyProjectionMatrix();
473}