0029517: Visualization - introduce AlphaMode property defining alpha value handling...
[occt.git] / src / OpenGl / OpenGl_PrimitiveArray.cxx
1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 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_AspectFace.hxx>
17 #include <OpenGl_Context.hxx>
18 #include <OpenGl_GraphicDriver.hxx>
19 #include <OpenGl_IndexBuffer.hxx>
20 #include <OpenGl_PointSprite.hxx>
21 #include <OpenGl_PrimitiveArray.hxx>
22 #include <OpenGl_Sampler.hxx>
23 #include <OpenGl_ShaderManager.hxx>
24 #include <OpenGl_ShaderProgram.hxx>
25 #include <OpenGl_Structure.hxx>
26 #include <OpenGl_VertexBufferCompat.hxx>
27 #include <OpenGl_Workspace.hxx>
28 #include <Graphic3d_TextureParams.hxx>
29 #include <NCollection_AlignedAllocator.hxx>
30
31 namespace
32 {
33   //! Convert data type to GL info
34   inline GLenum toGlDataType (const Graphic3d_TypeOfData theType,
35                               GLint&                     theNbComp)
36   {
37     switch (theType)
38     {
39       case Graphic3d_TOD_USHORT:
40         theNbComp = 1;
41         return GL_UNSIGNED_SHORT;
42       case Graphic3d_TOD_UINT:
43         theNbComp = 1;
44         return GL_UNSIGNED_INT;
45       case Graphic3d_TOD_VEC2:
46         theNbComp = 2;
47         return GL_FLOAT;
48       case Graphic3d_TOD_VEC3:
49         theNbComp = 3;
50         return GL_FLOAT;
51       case Graphic3d_TOD_VEC4:
52         theNbComp = 4;
53         return GL_FLOAT;
54       case Graphic3d_TOD_VEC4UB:
55         theNbComp = 4;
56         return GL_UNSIGNED_BYTE;
57       case Graphic3d_TOD_FLOAT:
58         theNbComp = 1;
59         return GL_FLOAT;
60     }
61     theNbComp = 0;
62     return GL_NONE;
63   }
64
65 }
66
67 //! Auxiliary template for VBO with interleaved attributes.
68 template<class TheBaseClass, int NbAttributes>
69 class OpenGl_VertexBufferT : public TheBaseClass
70 {
71
72 public:
73
74   //! Create uninitialized VBO.
75   OpenGl_VertexBufferT (const Graphic3d_Attribute* theAttribs,
76                         const Standard_Integer     theStride)
77   : Stride (theStride)
78   {
79     memcpy (Attribs, theAttribs, sizeof(Graphic3d_Attribute) * NbAttributes);
80   }
81
82   //! Create uninitialized VBO.
83   OpenGl_VertexBufferT (const Graphic3d_Buffer& theAttribs)
84   : Stride (theAttribs.Stride)
85   {
86     memcpy (Attribs, theAttribs.AttributesArray(), sizeof(Graphic3d_Attribute) * NbAttributes);
87   }
88
89   virtual bool HasColorAttribute() const
90   {
91     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
92     {
93       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
94       if (anAttrib.Id == Graphic3d_TOA_COLOR)
95       {
96         return true;
97       }
98     }
99     return false;
100   }
101
102   virtual bool HasNormalAttribute() const
103   {
104     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
105     {
106       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
107       if (anAttrib.Id == Graphic3d_TOA_NORM)
108       {
109         return true;
110       }
111     }
112     return false;
113   }
114
115   virtual void BindPositionAttribute (const Handle(OpenGl_Context)& theGlCtx) const
116   {
117     if (!TheBaseClass::IsValid())
118     {
119       return;
120     }
121
122     TheBaseClass::Bind (theGlCtx);
123     GLint aNbComp;
124     const GLubyte* anOffset = TheBaseClass::myOffset;
125     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
126     {
127       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
128       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
129       if (aDataType == GL_NONE)
130       {
131         continue;
132       }
133       else if (anAttrib.Id == Graphic3d_TOA_POS)
134       {
135         TheBaseClass::bindAttribute (theGlCtx, Graphic3d_TOA_POS, aNbComp, aDataType, Stride, anOffset);
136         break;
137       }
138
139       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
140     }
141   }
142
143   virtual void BindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
144   {
145     if (!TheBaseClass::IsValid())
146     {
147       return;
148     }
149
150     TheBaseClass::Bind (theGlCtx);
151     GLint aNbComp;
152     const GLubyte* anOffset = TheBaseClass::myOffset;
153     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
154     {
155       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
156       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
157       if (aDataType == GL_NONE)
158       {
159         continue;
160       }
161
162       TheBaseClass::bindAttribute (theGlCtx, anAttrib.Id, aNbComp, aDataType, Stride, anOffset);
163       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
164     }
165   }
166
167   virtual void UnbindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
168   {
169     if (!TheBaseClass::IsValid())
170     {
171       return;
172     }
173     TheBaseClass::Unbind (theGlCtx);
174
175     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
176     {
177       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
178       TheBaseClass::unbindAttribute (theGlCtx, anAttrib.Id);
179     }
180   }
181
182 public:
183
184   Graphic3d_Attribute Attribs[NbAttributes];
185   Standard_Integer    Stride;
186
187 };
188
189 // =======================================================================
190 // function : clearMemoryGL
191 // purpose  :
192 // =======================================================================
193 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
194 {
195   if (!myVboIndices.IsNull())
196   {
197     myVboIndices->Release (theGlCtx.operator->());
198     myVboIndices.Nullify();
199   }
200   if (!myVboAttribs.IsNull())
201   {
202     myVboAttribs->Release (theGlCtx.operator->());
203     myVboAttribs.Nullify();
204   }
205 }
206
207 // =======================================================================
208 // function : initNormalVbo
209 // purpose  :
210 // =======================================================================
211 Standard_Boolean OpenGl_PrimitiveArray::initNormalVbo (const Handle(OpenGl_Context)& theCtx) const
212 {
213   switch (myAttribs->NbAttributes)
214   {
215     case 1:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 1> (*myAttribs); break;
216     case 2:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 2> (*myAttribs); break;
217     case 3:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 3> (*myAttribs); break;
218     case 4:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 4> (*myAttribs); break;
219     case 5:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 5> (*myAttribs); break;
220     case 6:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 6> (*myAttribs); break;
221     case 7:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 7> (*myAttribs); break;
222     case 8:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 8> (*myAttribs); break;
223     case 9:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 9> (*myAttribs); break;
224     case 10: myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 10>(*myAttribs); break;
225   }
226
227   // specify data type as Byte and NbComponents as Stride, so that OpenGl_VertexBuffer::EstimatedDataSize() will return correct value
228   if (!myVboAttribs->init (theCtx, myAttribs->Stride, myAttribs->NbElements, myAttribs->Data(), GL_UNSIGNED_BYTE, myAttribs->Stride))
229   {
230     TCollection_ExtendedString aMsg;
231     aMsg += "VBO creation for Primitive Array has failed for ";
232     aMsg += myAttribs->NbElements;
233     aMsg += " vertices. Out of memory?";
234     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
235
236     clearMemoryGL (theCtx);
237     return Standard_False;
238   }
239   else if (myIndices.IsNull())
240   {
241     return Standard_True;
242   }
243
244   myVboIndices = new OpenGl_IndexBuffer();
245   bool isOk = false;
246   switch (myIndices->Stride)
247   {
248     case 2:
249     {
250       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLushort*> (myIndices->Data()));
251       break;
252     }
253     case 4:
254     {
255       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLuint*> (myIndices->Data()));
256       break;
257     }
258     default:
259     {
260       clearMemoryGL (theCtx);
261       return Standard_False;
262     }
263   }
264   if (!isOk)
265   {
266     TCollection_ExtendedString aMsg;
267     aMsg += "VBO creation for Primitive Array has failed for ";
268     aMsg += myIndices->NbElements;
269     aMsg += " indices. Out of memory?";
270     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
271     clearMemoryGL (theCtx);
272     return Standard_False;
273   }
274   return Standard_True;
275 }
276
277 // =======================================================================
278 // function : buildVBO
279 // purpose  :
280 // =======================================================================
281 Standard_Boolean OpenGl_PrimitiveArray::buildVBO (const Handle(OpenGl_Context)& theCtx,
282                                                   const Standard_Boolean        theToKeepData) const
283 {
284   bool isNormalMode = theCtx->ToUseVbo();
285   clearMemoryGL (theCtx);
286   if (myAttribs.IsNull()
287    || myAttribs->IsEmpty()
288    || myAttribs->NbElements < 1
289    || myAttribs->NbAttributes < 1
290    || myAttribs->NbAttributes > 10)
291   {
292     // vertices should be always defined - others are optional
293     return Standard_False;
294   }
295
296   if (isNormalMode
297    && initNormalVbo (theCtx))
298   {
299     if (!theCtx->caps->keepArrayData
300      && !theToKeepData)
301     {
302       myIndices.Nullify();
303       myAttribs.Nullify();
304     }
305     return Standard_True;
306   }
307
308   Handle(OpenGl_VertexBufferCompat) aVboAttribs;
309   switch (myAttribs->NbAttributes)
310   {
311     case 1:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 1> (*myAttribs); break;
312     case 2:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 2> (*myAttribs); break;
313     case 3:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 3> (*myAttribs); break;
314     case 4:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 4> (*myAttribs); break;
315     case 5:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 5> (*myAttribs); break;
316     case 6:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 6> (*myAttribs); break;
317     case 7:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 7> (*myAttribs); break;
318     case 8:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 8> (*myAttribs); break;
319     case 9:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 9> (*myAttribs); break;
320     case 10: aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 10>(*myAttribs); break;
321   }
322   aVboAttribs->initLink (myAttribs, 0, myAttribs->NbElements, GL_NONE);
323   if (!myIndices.IsNull())
324   {
325     Handle(OpenGl_VertexBufferCompat) aVboIndices = new OpenGl_VertexBufferCompat();
326     switch (myIndices->Stride)
327     {
328       case 2:
329       {
330         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_SHORT);
331         break;
332       }
333       case 4:
334       {
335         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_INT);
336         break;
337       }
338       default:
339       {
340         return Standard_False;
341       }
342     }
343     myVboIndices = aVboIndices;
344   }
345   myVboAttribs = aVboAttribs;
346   if (!theCtx->caps->keepArrayData
347    && !theToKeepData)
348   {
349     // does not make sense for compatibility mode
350     //myIndices.Nullify();
351     //myAttribs.Nullify();
352   }
353
354   return Standard_True;
355 }
356
357 // =======================================================================
358 // function : drawArray
359 // purpose  :
360 // =======================================================================
361 void OpenGl_PrimitiveArray::drawArray (const Handle(OpenGl_Workspace)& theWorkspace,
362                                        const Graphic3d_Vec4*           theFaceColors,
363                                        const Standard_Boolean          theHasVertColor) const
364 {
365   if (myVboAttribs.IsNull())
366   {
367   #if !defined(GL_ES_VERSION_2_0)
368     if (myDrawMode == GL_POINTS)
369     {
370       // extreme compatibility mode - without sprites but with markers
371       drawMarkers (theWorkspace);
372     }
373   #endif
374     return;
375   }
376
377   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
378   const bool                    toHilight  = theWorkspace->ToHighlight();
379   const GLenum aDrawMode = !aGlContext->ActiveProgram().IsNull()
380                          && aGlContext->ActiveProgram()->HasTessellationStage()
381                          ? GL_PATCHES
382                          : myDrawMode;
383   myVboAttribs->BindAllAttributes (aGlContext);
384   if (theHasVertColor && toHilight)
385   {
386     // disable per-vertex color
387     OpenGl_VertexBuffer::unbindAttribute (aGlContext, Graphic3d_TOA_COLOR);
388   }
389   if (!myVboIndices.IsNull())
390   {
391     myVboIndices->Bind (aGlContext);
392     GLubyte* anOffset = myVboIndices->GetDataOffset();
393     if (!myBounds.IsNull())
394     {
395       // draw primitives by vertex count with the indices
396       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
397       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
398       {
399         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
400         if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
401         glDrawElements (aDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
402         anOffset += aStride * aNbElemsInGroup;
403       }
404     }
405     else
406     {
407       // draw one (or sequential) primitive by the indices
408       glDrawElements (aDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
409     }
410     myVboIndices->Unbind (aGlContext);
411   }
412   else if (!myBounds.IsNull())
413   {
414     GLint aFirstElem = 0;
415     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
416     {
417       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
418       if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
419       glDrawArrays (aDrawMode, aFirstElem, aNbElemsInGroup);
420       aFirstElem += aNbElemsInGroup;
421     }
422   }
423   else
424   {
425     if (myDrawMode == GL_POINTS)
426     {
427       drawMarkers (theWorkspace);
428     }
429     else
430     {
431       glDrawArrays (aDrawMode, 0, myVboAttribs->GetElemsNb());
432     }
433   }
434
435   // bind with 0
436   myVboAttribs->UnbindAllAttributes (aGlContext);
437 }
438
439 // =======================================================================
440 // function : drawEdges
441 // purpose  :
442 // =======================================================================
443 void OpenGl_PrimitiveArray::drawEdges (const OpenGl_Vec4&              theEdgeColour,
444                                        const Handle(OpenGl_Workspace)& theWorkspace) const
445 {
446   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
447   if (myVboAttribs.IsNull())
448   {
449     return;
450   }
451
452   const OpenGl_AspectLine* anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace()->AspectEdge());
453   const OpenGl_AspectLine* anAspect = theWorkspace->ApplyAspectLine();
454
455 #if !defined(GL_ES_VERSION_2_0)
456   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
457 #endif
458
459   if (aGlContext->core20fwd != NULL)
460   {
461     aGlContext->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), anAspect->Aspect()->Type(),
462                                                   Graphic3d_TOSM_UNLIT, Graphic3d_AlphaMode_Opaque, Standard_False,
463                                                   anAspect->ShaderProgramRes (aGlContext));
464   }
465   const GLenum aDrawMode = !aGlContext->ActiveProgram().IsNull()
466                          && aGlContext->ActiveProgram()->HasTessellationStage()
467                          ? GL_PATCHES
468                          : myDrawMode;
469 #if !defined(GL_ES_VERSION_2_0)
470   if (aGlContext->ActiveProgram().IsNull()
471    && aGlContext->core11 != NULL)
472   {
473     glDisable (GL_LIGHTING);
474   }
475 #endif
476
477   /// OCC22236 NOTE: draw edges for all situations:
478   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indices array
479   /// 2) draw elements from vertex array, when bounds defines count of primitive's vertices.
480   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
481   myVboAttribs->BindPositionAttribute (aGlContext);
482
483   aGlContext->SetColor4fv   (theEdgeColour);
484   aGlContext->SetTypeOfLine (anAspect->Aspect()->Type());
485   aGlContext->SetLineWidth  (anAspect->Aspect()->Width());
486
487   if (!myVboIndices.IsNull())
488   {
489     myVboIndices->Bind (aGlContext);
490     GLubyte* anOffset = myVboIndices->GetDataOffset();
491
492     // draw primitives by vertex count with the indices
493     if (!myBounds.IsNull())
494     {
495       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
496       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
497       {
498         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
499         glDrawElements (aDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
500         anOffset += aStride * aNbElemsInGroup;
501       }
502     }
503     // draw one (or sequential) primitive by the indices
504     else
505     {
506       glDrawElements (aDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
507     }
508     myVboIndices->Unbind (aGlContext);
509   }
510   else if (!myBounds.IsNull())
511   {
512     GLint aFirstElem = 0;
513     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
514     {
515       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
516       glDrawArrays (aDrawMode, aFirstElem, aNbElemsInGroup);
517       aFirstElem += aNbElemsInGroup;
518     }
519   }
520   else
521   {
522     glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
523   }
524
525   // unbind buffers
526   myVboAttribs->UnbindAttribute (aGlContext, Graphic3d_TOA_POS);
527
528   // restore line context
529   theWorkspace->SetAspectLine (anAspectLineOld);
530 }
531
532 // =======================================================================
533 // function : drawMarkers
534 // purpose  :
535 // =======================================================================
536 void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
537 {
538   const OpenGl_AspectMarker* anAspectMarker = theWorkspace->ApplyAspectMarker();
539   const Handle(OpenGl_Context)&     aCtx    = theWorkspace->GetGlContext();
540   const GLenum aDrawMode = !aCtx->ActiveProgram().IsNull()
541                          && aCtx->ActiveProgram()->HasTessellationStage()
542                          ? GL_PATCHES
543                          : myDrawMode;
544
545   const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
546   const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
547   if (aSpriteNorm != NULL
548   && !aSpriteNorm->IsDisplayList())
549   {
550     // Textured markers will be drawn with the point sprites
551     aCtx->SetPointSize (anAspectMarker->MarkerSize());
552     aCtx->SetPointSpriteOrigin();
553   #if !defined(GL_ES_VERSION_2_0)
554     if (aCtx->core11 != NULL)
555     {
556       aCtx->core11fwd->glEnable (GL_ALPHA_TEST);
557       aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, 0.1f);
558     }
559   #endif
560
561     aCtx->core11fwd->glEnable (GL_BLEND);
562     aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
563
564     aCtx->core11fwd->glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
565
566     aCtx->core11fwd->glDisable (GL_BLEND);
567   #if !defined(GL_ES_VERSION_2_0)
568     if (aCtx->core11 != NULL)
569     {
570       if (aCtx->ShaderManager()->MaterialState().AlphaCutoff() >= ShortRealLast())
571       {
572         aCtx->core11fwd->glDisable (GL_ALPHA_TEST);
573       }
574       else
575       {
576         aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, aCtx->ShaderManager()->MaterialState().AlphaCutoff());
577       }
578     }
579   #endif
580     aCtx->SetPointSize (1.0f);
581     return;
582   }
583   else if (anAspectMarker->Aspect()->Type() == Aspect_TOM_POINT)
584   {
585     aCtx->SetPointSize (anAspectMarker->MarkerSize());
586     aCtx->core11fwd->glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
587     aCtx->SetPointSize (1.0f);
588   }
589 #if !defined(GL_ES_VERSION_2_0)
590   // Textured markers will be drawn with the glBitmap
591   else if (anAspectMarker->Aspect()->Type() != Aspect_TOM_POINT
592         && aSpriteNorm != NULL)
593   {
594     /**if (!isHilight && (myPArray->vcolours != NULL))
595     {
596       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
597       {
598         glColor4ubv    (myPArray->vcolours[anIter].GetData());
599         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
600         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
601       }
602     }
603     else*/
604     {
605       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
606       {
607         aCtx->core11->glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
608         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
609       }
610     }
611   }
612 #endif
613 }
614
615 // =======================================================================
616 // function : OpenGl_PrimitiveArray
617 // purpose  :
618 // =======================================================================
619 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver* theDriver)
620
621 : myDrawMode  (DRAW_MODE_NONE),
622   myIsFillType(Standard_False),
623   myIsVboInit (Standard_False)
624 {
625   if (theDriver != NULL)
626   {
627     myUID = theDriver->GetNextPrimitiveArrayUID();
628   }
629 }
630
631 // =======================================================================
632 // function : OpenGl_PrimitiveArray
633 // purpose  :
634 // =======================================================================
635 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver*          theDriver,
636                                               const Graphic3d_TypeOfPrimitiveArray theType,
637                                               const Handle(Graphic3d_IndexBuffer)& theIndices,
638                                               const Handle(Graphic3d_Buffer)&      theAttribs,
639                                               const Handle(Graphic3d_BoundBuffer)& theBounds)
640
641 : myIndices   (theIndices),
642   myAttribs   (theAttribs),
643   myBounds    (theBounds),
644   myDrawMode  (DRAW_MODE_NONE),
645   myIsFillType(Standard_False),
646   myIsVboInit (Standard_False)
647 {
648   if (!myIndices.IsNull()
649     && myIndices->NbElements < 1)
650   {
651     // dummy index buffer?
652     myIndices.Nullify();
653   }
654
655   if (theDriver != NULL)
656   {
657     myUID = theDriver->GetNextPrimitiveArrayUID();
658   #if defined (GL_ES_VERSION_2_0)
659     const Handle(OpenGl_Context)& aCtx = theDriver->GetSharedContext();
660     if (!aCtx.IsNull())
661     {
662       processIndices (aCtx);
663     }
664   #endif
665   }
666
667   setDrawMode (theType);
668 }
669
670 // =======================================================================
671 // function : ~OpenGl_PrimitiveArray
672 // purpose  :
673 // =======================================================================
674 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
675 {
676   //
677 }
678
679 // =======================================================================
680 // function : Release
681 // purpose  :
682 // =======================================================================
683 void OpenGl_PrimitiveArray::Release (OpenGl_Context* theContext)
684 {
685   myIsVboInit = Standard_False;
686   if (!myVboIndices.IsNull())
687   {
688     if (theContext)
689     {
690       theContext->DelayedRelease (myVboIndices);
691     }
692     myVboIndices.Nullify();
693   }
694   if (!myVboAttribs.IsNull())
695   {
696     if (theContext)
697     {
698       theContext->DelayedRelease (myVboAttribs);
699     }
700     myVboAttribs.Nullify();
701   }
702 }
703
704 // =======================================================================
705 // function : Render
706 // purpose  :
707 // =======================================================================
708 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
709 {
710   if (myDrawMode == DRAW_MODE_NONE)
711   {
712     return;
713   }
714
715   const OpenGl_AspectFace*   anAspectFace   = theWorkspace->ApplyAspectFace();
716   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->ApplyAspectLine();
717   const OpenGl_AspectMarker* anAspectMarker = myDrawMode == GL_POINTS
718                                             ? theWorkspace->ApplyAspectMarker()
719                                             : theWorkspace->AspectMarker();
720
721   // create VBOs on first render call
722   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
723   if (!myIsVboInit)
724   {
725     // compatibility - keep data to draw markers using display lists
726     Standard_Boolean toKeepData = Standard_False;
727     if (myDrawMode == GL_POINTS)
728     {
729       const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
730       const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
731       toKeepData = aSpriteNorm != NULL
732                &&  aSpriteNorm->IsDisplayList();
733     }
734   #if defined (GL_ES_VERSION_2_0)
735     processIndices (aCtx);
736   #endif
737     buildVBO (aCtx, toKeepData);
738     myIsVboInit = Standard_True;
739   }
740
741   // Temporarily disable environment mapping
742   Handle(OpenGl_TextureSet) aTextureBack;
743   bool toDrawArray = true;
744   if (myDrawMode > GL_LINE_STRIP)
745   {
746     toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY;
747   }
748   else if (myDrawMode <= GL_LINE_STRIP)
749   {
750     aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
751     if (myDrawMode == GL_POINTS)
752     {
753       toDrawArray = anAspectMarker->Aspect()->Type() != Aspect_TOM_EMPTY;
754     }
755     else
756     {
757       toDrawArray = anAspectLine->Aspect()->Type() != Aspect_TOL_EMPTY;
758     }
759   }
760
761   Graphic3d_TypeOfShadingModel aShadingModel = Graphic3d_TOSM_UNLIT;
762   if (toDrawArray)
763   {
764     const bool hasColorAttrib = !myVboAttribs.IsNull()
765                               && myVboAttribs->HasColorAttribute();
766     const bool toHilight    = theWorkspace->ToHighlight();
767     const bool hasVertColor = hasColorAttrib && !toHilight;
768     const bool hasVertNorm  = !myVboAttribs.IsNull() && myVboAttribs->HasNormalAttribute();
769     switch (myDrawMode)
770     {
771       case GL_POINTS:
772       {
773         aShadingModel = aCtx->ShaderManager()->ChooseMarkerShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
774         const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
775         const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
776         if (aSpriteNorm != NULL
777         && !aSpriteNorm->IsDisplayList())
778         {
779           const Handle(OpenGl_TextureSet)& aSprite = toHilight && anAspectMarker->SpriteHighlightRes (aCtx)->First()->IsValid()
780                                                    ? anAspectMarker->SpriteHighlightRes (aCtx)
781                                                    : aSpriteNormRes;
782           aCtx->BindTextures (aSprite);
783           aCtx->ShaderManager()->BindMarkerProgram (aSprite, aShadingModel, Graphic3d_AlphaMode_Opaque, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
784         }
785         else
786         {
787           aCtx->ShaderManager()->BindMarkerProgram (Handle(OpenGl_TextureSet)(), aShadingModel, Graphic3d_AlphaMode_Opaque, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
788         }
789         break;
790       }
791       case GL_LINES:
792       case GL_LINE_STRIP:
793       {
794         aShadingModel = aCtx->ShaderManager()->ChooseLineShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
795         aCtx->ShaderManager()->BindLineProgram (NULL,
796                                                 anAspectLine->Aspect()->Type(),
797                                                 aShadingModel,
798                                                 Graphic3d_AlphaMode_Opaque,
799                                                 hasVertColor,
800                                                 anAspectLine->ShaderProgramRes (aCtx));
801         break;
802       }
803       default:
804       {
805         aShadingModel = aCtx->ShaderManager()->ChooseFaceShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
806         const Handle(OpenGl_TextureSet)& aTextures = aCtx->ActiveTextures();
807         const Standard_Boolean toEnableEnvMap = (!aTextures.IsNull() && (aTextures == theWorkspace->EnvironmentTexture()));
808         aCtx->ShaderManager()->BindFaceProgram (aTextures,
809                                                 aShadingModel,
810                                                 anAspectFace->Aspect()->AlphaMode(),
811                                                 hasVertColor,
812                                                 toEnableEnvMap,
813                                                 anAspectFace->ShaderProgramRes (aCtx));
814         break;
815       }
816     }
817
818   #if !defined(GL_ES_VERSION_2_0)
819     // manage FFP lighting
820     if (aCtx->ActiveProgram().IsNull()
821      && aCtx->core11 != NULL)
822     {
823       if (aShadingModel == Graphic3d_TOSM_UNLIT)
824       {
825         glDisable (GL_LIGHTING);
826       }
827       else
828       {
829         glEnable (GL_LIGHTING);
830       }
831     }
832   #endif
833
834     if (!aCtx->ActiveTextures().IsNull()
835      && !aCtx->ActiveTextures()->IsEmpty()
836      && !aCtx->ActiveTextures()->First().IsNull()
837      && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
838     {
839       aCtx->SetTextureMatrix (aCtx->ActiveTextures()->First()->Sampler()->Parameters());
840     }
841
842     if (myDrawMode <= GL_LINE_STRIP)
843     {
844       const OpenGl_Vec4& aLineColor = myDrawMode == GL_POINTS ? theWorkspace->MarkerColor() : theWorkspace->LineColor();
845       aCtx->SetColor4fv (aLineColor);
846     }
847     else
848     {
849       const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
850       aCtx->SetColor4fv (anInteriorColor);
851     }
852     if (myDrawMode == GL_LINES
853      || myDrawMode == GL_LINE_STRIP)
854     {
855       aCtx->SetTypeOfLine (anAspectLine->Aspect()->Type());
856       aCtx->SetLineWidth  (anAspectLine->Aspect()->Width());
857     }
858
859     const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
860                                       ?  myBounds->Colors
861                                       :  NULL;
862     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
863   }
864
865   if (myDrawMode <= GL_LINE_STRIP)
866   {
867     aCtx->BindTextures (aTextureBack);
868   }
869   else
870   {
871     if (anAspectFace->Aspect()->ToDrawEdges()
872      || anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_HIDDENLINE)
873     {
874       const OpenGl_Vec4& anEdgeColor = theWorkspace->EdgeColor();
875       drawEdges (anEdgeColor, theWorkspace);
876
877       // restore OpenGL polygon mode if needed
878     #if !defined(GL_ES_VERSION_2_0)
879       if (anAspectFace->Aspect()->InteriorStyle() >= Aspect_IS_HATCH)
880       {
881         glPolygonMode (GL_FRONT_AND_BACK,
882           anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_POINT ? GL_POINT : GL_FILL);
883       }
884     #endif
885     }
886   }
887 }
888
889 // =======================================================================
890 // function : setDrawMode
891 // purpose  :
892 // =======================================================================
893 void OpenGl_PrimitiveArray::setDrawMode (const Graphic3d_TypeOfPrimitiveArray theType)
894 {
895   if (myAttribs.IsNull())
896   {
897     myDrawMode = DRAW_MODE_NONE;
898     myIsFillType = false;
899     return;
900   }
901
902   switch (theType)
903   {
904     case Graphic3d_TOPA_POINTS:
905       myDrawMode   = GL_POINTS;
906       myIsFillType = false;
907       break;
908     case Graphic3d_TOPA_SEGMENTS:
909       myDrawMode   = GL_LINES;
910       myIsFillType = false;
911       break;
912     case Graphic3d_TOPA_POLYLINES:
913       myDrawMode   = GL_LINE_STRIP;
914       myIsFillType = false;
915       break;
916     case Graphic3d_TOPA_TRIANGLES:
917       myDrawMode   = GL_TRIANGLES;
918       myIsFillType = true;
919       break;
920     case Graphic3d_TOPA_TRIANGLESTRIPS:
921       myDrawMode   = GL_TRIANGLE_STRIP;
922       myIsFillType = true;
923       break;
924     case Graphic3d_TOPA_TRIANGLEFANS:
925       myDrawMode   = GL_TRIANGLE_FAN;
926       myIsFillType = true;
927       break;
928     //
929     case Graphic3d_TOPA_LINES_ADJACENCY:
930       myDrawMode = GL_LINES_ADJACENCY;
931       myIsFillType = false;
932       break;
933     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:
934       myDrawMode   = GL_LINE_STRIP_ADJACENCY;
935       myIsFillType = false;
936       break;
937     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:
938       myDrawMode   = GL_TRIANGLES_ADJACENCY;
939       myIsFillType = true;
940       break;
941     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY:
942       myDrawMode   = GL_TRIANGLE_STRIP_ADJACENCY;
943       myIsFillType = true;
944       break;
945     //
946   #if !defined(GL_ES_VERSION_2_0)
947     case Graphic3d_TOPA_QUADRANGLES:
948       myDrawMode   = GL_QUADS;
949       myIsFillType = true;
950       break;
951     case Graphic3d_TOPA_QUADRANGLESTRIPS:
952       myDrawMode   = GL_QUAD_STRIP;
953       myIsFillType = true;
954       break;
955     case Graphic3d_TOPA_POLYGONS:
956       myDrawMode   = GL_POLYGON;
957       myIsFillType = true;
958       break;
959   #else
960     case Graphic3d_TOPA_QUADRANGLES:
961     case Graphic3d_TOPA_QUADRANGLESTRIPS:
962     case Graphic3d_TOPA_POLYGONS:
963   #endif
964     case Graphic3d_TOPA_UNDEFINED:
965       myDrawMode   = DRAW_MODE_NONE;
966       myIsFillType = false;
967       break;
968   }
969 }
970
971 // =======================================================================
972 // function : processIndices
973 // purpose  :
974 // =======================================================================
975 Standard_Boolean OpenGl_PrimitiveArray::processIndices (const Handle(OpenGl_Context)& theContext) const
976 {
977   if (myIndices.IsNull()
978    || myAttribs.IsNull()
979    || theContext->hasUintIndex)
980   {
981     return Standard_True;
982   }
983
984   if (myAttribs->NbElements > std::numeric_limits<GLushort>::max())
985   {
986     Handle(Graphic3d_Buffer) anAttribs = new Graphic3d_Buffer (new NCollection_AlignedAllocator (16));
987     if (!anAttribs->Init (myIndices->NbElements, myAttribs->AttributesArray(), myAttribs->NbAttributes))
988     {
989       return Standard_False; // failed to initialize attribute array
990     }
991
992     for (Standard_Integer anIdxIdx = 0; anIdxIdx < myIndices->NbElements; ++anIdxIdx)
993     {
994       const Standard_Integer anIndex = myIndices->Index (anIdxIdx);
995       memcpy (anAttribs->ChangeData() + myAttribs->Stride * anIdxIdx,
996               myAttribs->Data()       + myAttribs->Stride * anIndex,
997               myAttribs->Stride);
998     }
999
1000     myIndices.Nullify();
1001     myAttribs = anAttribs;
1002   }
1003
1004   return Standard_True;
1005 }
1006
1007 // =======================================================================
1008 // function : InitBuffers
1009 // purpose  :
1010 // =======================================================================
1011 void OpenGl_PrimitiveArray::InitBuffers (const Handle(OpenGl_Context)&        theContext,
1012                                          const Graphic3d_TypeOfPrimitiveArray theType,
1013                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
1014                                          const Handle(Graphic3d_Buffer)&      theAttribs,
1015                                          const Handle(Graphic3d_BoundBuffer)& theBounds)
1016 {
1017   // Release old graphic resources
1018   Release (theContext.operator->());
1019
1020   myIndices = theIndices;
1021   myAttribs = theAttribs;
1022   myBounds = theBounds;
1023 #if defined(GL_ES_VERSION_2_0)
1024   processIndices (theContext);
1025 #endif
1026
1027   setDrawMode (theType);
1028 }