98ee3c2d26ef60c86561301a0d7466c35f8a2a15
[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   if (!myVboAttribs->init (theCtx, 0, myAttribs->NbElements, myAttribs->Data(), GL_NONE, myAttribs->Stride))
228   {
229     TCollection_ExtendedString aMsg;
230     aMsg += "VBO creation for Primitive Array has failed for ";
231     aMsg += myAttribs->NbElements;
232     aMsg += " vertices. Out of memory?";
233     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
234
235     clearMemoryGL (theCtx);
236     return Standard_False;
237   }
238   else if (myIndices.IsNull())
239   {
240     return Standard_True;
241   }
242
243   myVboIndices = new OpenGl_IndexBuffer();
244   bool isOk = false;
245   switch (myIndices->Stride)
246   {
247     case 2:
248     {
249       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLushort*> (myIndices->Data()));
250       break;
251     }
252     case 4:
253     {
254       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLuint*> (myIndices->Data()));
255       break;
256     }
257     default:
258     {
259       clearMemoryGL (theCtx);
260       return Standard_False;
261     }
262   }
263   if (!isOk)
264   {
265     TCollection_ExtendedString aMsg;
266     aMsg += "VBO creation for Primitive Array has failed for ";
267     aMsg += myIndices->NbElements;
268     aMsg += " indices. Out of memory?";
269     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
270     clearMemoryGL (theCtx);
271     return Standard_False;
272   }
273   return Standard_True;
274 }
275
276 // =======================================================================
277 // function : buildVBO
278 // purpose  :
279 // =======================================================================
280 Standard_Boolean OpenGl_PrimitiveArray::buildVBO (const Handle(OpenGl_Context)& theCtx,
281                                                   const Standard_Boolean        theToKeepData) const
282 {
283   bool isNormalMode = theCtx->ToUseVbo();
284   clearMemoryGL (theCtx);
285   if (myAttribs.IsNull()
286    || myAttribs->IsEmpty()
287    || myAttribs->NbElements < 1
288    || myAttribs->NbAttributes < 1
289    || myAttribs->NbAttributes > 10)
290   {
291     // vertices should be always defined - others are optional
292     return Standard_False;
293   }
294
295   if (isNormalMode
296    && initNormalVbo (theCtx))
297   {
298     if (!theCtx->caps->keepArrayData
299      && !theToKeepData)
300     {
301       myIndices.Nullify();
302       myAttribs.Nullify();
303     }
304     return Standard_True;
305   }
306
307   Handle(OpenGl_VertexBufferCompat) aVboAttribs;
308   switch (myAttribs->NbAttributes)
309   {
310     case 1:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 1> (*myAttribs); break;
311     case 2:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 2> (*myAttribs); break;
312     case 3:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 3> (*myAttribs); break;
313     case 4:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 4> (*myAttribs); break;
314     case 5:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 5> (*myAttribs); break;
315     case 6:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 6> (*myAttribs); break;
316     case 7:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 7> (*myAttribs); break;
317     case 8:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 8> (*myAttribs); break;
318     case 9:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 9> (*myAttribs); break;
319     case 10: aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 10>(*myAttribs); break;
320   }
321   aVboAttribs->initLink (myAttribs, 0, myAttribs->NbElements, GL_NONE);
322   if (!myIndices.IsNull())
323   {
324     Handle(OpenGl_VertexBufferCompat) aVboIndices = new OpenGl_VertexBufferCompat();
325     switch (myIndices->Stride)
326     {
327       case 2:
328       {
329         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_SHORT);
330         break;
331       }
332       case 4:
333       {
334         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_INT);
335         break;
336       }
337       default:
338       {
339         return Standard_False;
340       }
341     }
342     myVboIndices = aVboIndices;
343   }
344   myVboAttribs = aVboAttribs;
345   if (!theCtx->caps->keepArrayData
346    && !theToKeepData)
347   {
348     // does not make sense for compatibility mode
349     //myIndices.Nullify();
350     //myAttribs.Nullify();
351   }
352
353   return Standard_True;
354 }
355
356 // =======================================================================
357 // function : drawArray
358 // purpose  :
359 // =======================================================================
360 void OpenGl_PrimitiveArray::drawArray (const Handle(OpenGl_Workspace)& theWorkspace,
361                                        const Graphic3d_Vec4*           theFaceColors,
362                                        const Standard_Boolean          theHasVertColor) const
363 {
364   if (myVboAttribs.IsNull())
365   {
366   #if !defined(GL_ES_VERSION_2_0)
367     if (myDrawMode == GL_POINTS)
368     {
369       // extreme compatibility mode - without sprites but with markers
370       drawMarkers (theWorkspace);
371     }
372   #endif
373     return;
374   }
375
376   const Handle(OpenGl_Context)& aGlContext  = theWorkspace->GetGlContext();
377   const bool                    toHilight   = theWorkspace->ToHighlight();
378   myVboAttribs->BindAllAttributes (aGlContext);
379   if (theHasVertColor && toHilight)
380   {
381     // disable per-vertex color
382     OpenGl_VertexBuffer::unbindAttribute (aGlContext, Graphic3d_TOA_COLOR);
383   }
384   if (!myVboIndices.IsNull())
385   {
386     myVboIndices->Bind (aGlContext);
387     GLubyte* anOffset = myVboIndices->GetDataOffset();
388     if (!myBounds.IsNull())
389     {
390       // draw primitives by vertex count with the indices
391       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
392       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
393       {
394         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
395         if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
396         glDrawElements (myDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
397         anOffset += aStride * aNbElemsInGroup;
398       }
399     }
400     else
401     {
402       // draw one (or sequential) primitive by the indices
403       glDrawElements (myDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
404     }
405     myVboIndices->Unbind (aGlContext);
406   }
407   else if (!myBounds.IsNull())
408   {
409     GLint aFirstElem = 0;
410     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
411     {
412       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
413       if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
414       glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
415       aFirstElem += aNbElemsInGroup;
416     }
417   }
418   else
419   {
420     if (myDrawMode == GL_POINTS)
421     {
422       drawMarkers (theWorkspace);
423     }
424     else
425     {
426       glDrawArrays (myDrawMode, 0, myVboAttribs->GetElemsNb());
427     }
428   }
429
430   // bind with 0
431   myVboAttribs->UnbindAllAttributes (aGlContext);
432 }
433
434 // =======================================================================
435 // function : drawEdges
436 // purpose  :
437 // =======================================================================
438 void OpenGl_PrimitiveArray::drawEdges (const OpenGl_Vec4&              theEdgeColour,
439                                        const Handle(OpenGl_Workspace)& theWorkspace) const
440 {
441   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
442   if (myVboAttribs.IsNull())
443   {
444     return;
445   }
446
447 #if !defined(GL_ES_VERSION_2_0)
448   if (aGlContext->core11 != NULL)
449   {
450     glDisable (GL_LIGHTING);
451   }
452 #endif
453
454   const OpenGl_AspectLine* anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace()->AspectEdge());
455   const OpenGl_AspectLine* anAspect = theWorkspace->ApplyAspectLine();
456
457 #if !defined(GL_ES_VERSION_2_0)
458   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
459 #endif
460
461   if (aGlContext->core20fwd != NULL)
462   {
463     aGlContext->ShaderManager()->BindLineProgram (NULL,
464                                                   anAspect->Aspect()->Type() != Aspect_TOL_SOLID,
465                                                   Standard_False,
466                                                   Standard_False,
467                                                   anAspect->ShaderProgramRes (aGlContext));
468   }
469
470   /// OCC22236 NOTE: draw edges for all situations:
471   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indices array
472   /// 2) draw elements from vertex array, when bounds defines count of primitive's vertices.
473   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
474   myVboAttribs->BindPositionAttribute (aGlContext);
475
476   aGlContext->SetColor4fv   (theEdgeColour);
477   aGlContext->SetTypeOfLine (anAspect->Aspect()->Type());
478   aGlContext->SetLineWidth  (anAspect->Aspect()->Width());
479
480   if (!myVboIndices.IsNull())
481   {
482     myVboIndices->Bind (aGlContext);
483     GLubyte* anOffset = myVboIndices->GetDataOffset();
484
485     // draw primitives by vertex count with the indices
486     if (!myBounds.IsNull())
487     {
488       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
489       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
490       {
491         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
492         glDrawElements (myDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
493         anOffset += aStride * aNbElemsInGroup;
494       }
495     }
496     // draw one (or sequential) primitive by the indices
497     else
498     {
499       glDrawElements (myDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
500     }
501     myVboIndices->Unbind (aGlContext);
502   }
503   else if (!myBounds.IsNull())
504   {
505     GLint aFirstElem = 0;
506     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
507     {
508       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
509       glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
510       aFirstElem += aNbElemsInGroup;
511     }
512   }
513   else
514   {
515     glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
516   }
517
518   // unbind buffers
519   myVboAttribs->UnbindAttribute (aGlContext, Graphic3d_TOA_POS);
520
521   // restore line context
522   theWorkspace->SetAspectLine (anAspectLineOld);
523 }
524
525 // =======================================================================
526 // function : drawMarkers
527 // purpose  :
528 // =======================================================================
529 void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
530 {
531   const OpenGl_AspectMarker* anAspectMarker     = theWorkspace->ApplyAspectMarker();
532   const Handle(OpenGl_Context)&     aCtx        = theWorkspace->GetGlContext();
533   const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
534   const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
535   if (aSpriteNorm != NULL
536   && !aSpriteNorm->IsDisplayList())
537   {
538     // Textured markers will be drawn with the point sprites
539     aCtx->SetPointSize (anAspectMarker->MarkerSize());
540     aCtx->SetPointSpriteOrigin();
541   #if !defined(GL_ES_VERSION_2_0)
542     if (aCtx->core11 != NULL)
543     {
544       aCtx->core11fwd->glEnable (GL_ALPHA_TEST);
545       aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, 0.1f);
546     }
547   #endif
548
549     aCtx->core11fwd->glEnable (GL_BLEND);
550     aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
551
552     aCtx->core11fwd->glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
553
554     aCtx->core11fwd->glDisable (GL_BLEND);
555   #if !defined(GL_ES_VERSION_2_0)
556     if (aCtx->core11 != NULL)
557     {
558       aCtx->core11fwd->glDisable (GL_ALPHA_TEST);
559     }
560   #endif
561     aCtx->SetPointSize (1.0f);
562     return;
563   }
564   else if (anAspectMarker->Aspect()->Type() == Aspect_TOM_POINT)
565   {
566     aCtx->SetPointSize (anAspectMarker->MarkerSize());
567     aCtx->core11fwd->glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
568     aCtx->SetPointSize (1.0f);
569   }
570 #if !defined(GL_ES_VERSION_2_0)
571   // Textured markers will be drawn with the glBitmap
572   else if (anAspectMarker->Aspect()->Type() != Aspect_TOM_POINT
573         && aSpriteNorm != NULL)
574   {
575     /**if (!isHilight && (myPArray->vcolours != NULL))
576     {
577       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
578       {
579         glColor4ubv    (myPArray->vcolours[anIter].GetData());
580         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
581         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
582       }
583     }
584     else*/
585     {
586       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
587       {
588         aCtx->core11->glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
589         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
590       }
591     }
592   }
593 #endif
594 }
595
596 // =======================================================================
597 // function : OpenGl_PrimitiveArray
598 // purpose  :
599 // =======================================================================
600 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver* theDriver)
601
602 : myDrawMode  (DRAW_MODE_NONE),
603   myIsVboInit (Standard_False)
604 {
605   if (theDriver != NULL)
606   {
607     myUID = theDriver->GetNextPrimitiveArrayUID();
608   }
609 }
610
611 // =======================================================================
612 // function : OpenGl_PrimitiveArray
613 // purpose  :
614 // =======================================================================
615 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver*          theDriver,
616                                               const Graphic3d_TypeOfPrimitiveArray theType,
617                                               const Handle(Graphic3d_IndexBuffer)& theIndices,
618                                               const Handle(Graphic3d_Buffer)&      theAttribs,
619                                               const Handle(Graphic3d_BoundBuffer)& theBounds)
620
621 : myIndices   (theIndices),
622   myAttribs   (theAttribs),
623   myBounds    (theBounds),
624   myDrawMode  (DRAW_MODE_NONE),
625   myIsVboInit (Standard_False)
626 {
627   if (!myIndices.IsNull()
628     && myIndices->NbElements < 1)
629   {
630     // dummy index buffer?
631     myIndices.Nullify();
632   }
633
634   if (theDriver != NULL)
635   {
636     myUID = theDriver->GetNextPrimitiveArrayUID();
637   #if defined (GL_ES_VERSION_2_0)
638     const Handle(OpenGl_Context)& aCtx = theDriver->GetSharedContext();
639     if (!aCtx.IsNull())
640     {
641       processIndices (aCtx);
642     }
643   #endif
644   }
645
646   setDrawMode (theType);
647 }
648
649 // =======================================================================
650 // function : ~OpenGl_PrimitiveArray
651 // purpose  :
652 // =======================================================================
653 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
654 {
655   //
656 }
657
658 // =======================================================================
659 // function : Release
660 // purpose  :
661 // =======================================================================
662 void OpenGl_PrimitiveArray::Release (OpenGl_Context* theContext)
663 {
664   myIsVboInit = Standard_False;
665   if (!myVboIndices.IsNull())
666   {
667     if (theContext)
668     {
669       theContext->DelayedRelease (myVboIndices);
670     }
671     myVboIndices.Nullify();
672   }
673   if (!myVboAttribs.IsNull())
674   {
675     if (theContext)
676     {
677       theContext->DelayedRelease (myVboAttribs);
678     }
679     myVboAttribs.Nullify();
680   }
681 }
682
683 // =======================================================================
684 // function : Render
685 // purpose  :
686 // =======================================================================
687 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
688 {
689   if (myDrawMode == DRAW_MODE_NONE)
690   {
691     return;
692   }
693
694   const OpenGl_AspectFace*   anAspectFace   = theWorkspace->ApplyAspectFace();
695   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->ApplyAspectLine();
696   const OpenGl_AspectMarker* anAspectMarker = myDrawMode == GL_POINTS
697                                             ? theWorkspace->ApplyAspectMarker()
698                                             : theWorkspace->AspectMarker();
699
700   // create VBOs on first render call
701   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
702   if (!myIsVboInit)
703   {
704     // compatibility - keep data to draw markers using display lists
705     Standard_Boolean toKeepData = Standard_False;
706     if (myDrawMode == GL_POINTS)
707     {
708       const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
709       const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
710       toKeepData = aSpriteNorm != NULL
711                &&  aSpriteNorm->IsDisplayList();
712     }
713   #if defined (GL_ES_VERSION_2_0)
714     processIndices (aCtx);
715   #endif
716     buildVBO (aCtx, toKeepData);
717     myIsVboInit = Standard_True;
718   }
719
720   const Standard_Boolean hasColorAttrib = !myVboAttribs.IsNull()
721                                         && myVboAttribs->HasColorAttribute();
722   const Standard_Boolean isLightOn = !anAspectFace->IsNoLighting()
723                                   && !myVboAttribs.IsNull()
724                                   &&  myVboAttribs->HasNormalAttribute();
725
726   // Temporarily disable environment mapping
727   Handle(OpenGl_TextureSet) aTextureBack;
728   bool toDrawArray = true;
729   if (myDrawMode > GL_LINE_STRIP)
730   {
731     toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY;
732   }
733   else if (myDrawMode <= GL_LINE_STRIP)
734   {
735     aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
736     if (myDrawMode == GL_POINTS)
737     {
738       toDrawArray = anAspectMarker->Aspect()->Type() != Aspect_TOM_EMPTY;
739     }
740     else
741     {
742       toDrawArray = anAspectLine->Aspect()->Type() != Aspect_TOL_EMPTY;
743     }
744   }
745
746   if (toDrawArray)
747   {
748     const bool             toHilight    = theWorkspace->ToHighlight();
749     const Standard_Boolean hasVertColor = hasColorAttrib && !toHilight;
750     switch (myDrawMode)
751     {
752       case GL_POINTS:
753       {
754         const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
755         const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
756         if (aSpriteNorm != NULL
757         && !aSpriteNorm->IsDisplayList())
758         {
759           const Handle(OpenGl_TextureSet)& aSprite = toHilight && anAspectMarker->SpriteHighlightRes (aCtx)->First()->IsValid()
760                                                    ? anAspectMarker->SpriteHighlightRes (aCtx)
761                                                    : aSpriteNormRes;
762           aCtx->BindTextures (aSprite);
763           aCtx->ShaderManager()->BindMarkerProgram (aSprite, isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
764         }
765         else
766         {
767           aCtx->ShaderManager()->BindMarkerProgram (Handle(OpenGl_TextureSet)(), isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
768         }
769         break;
770       }
771       case GL_LINES:
772       case GL_LINE_STRIP:
773       {
774         aCtx->ShaderManager()->BindLineProgram (NULL,
775                                                 anAspectLine->Aspect()->Type() != Aspect_TOL_SOLID,
776                                                 isLightOn,
777                                                 hasVertColor,
778                                                 anAspectLine->ShaderProgramRes (aCtx));
779         break;
780       }
781       default:
782       {
783         const Handle(OpenGl_TextureSet)& aTextures = aCtx->ActiveTextures();
784         const Standard_Boolean isLightOnFace = isLightOn
785                                             && (aTextures.IsNull()
786                                              || aTextures->IsEmpty()
787                                              || aTextures->First().IsNull()
788                                              || aTextures->First()->Sampler()->Parameters()->IsModulate());
789         const Standard_Boolean toEnableEnvMap = (!aTextures.IsNull() && (aTextures == theWorkspace->EnvironmentTexture()));
790         aCtx->ShaderManager()->BindFaceProgram (aTextures,
791                                                 isLightOnFace,
792                                                 hasVertColor,
793                                                 toEnableEnvMap,
794                                                 anAspectFace->ShaderProgramRes (aCtx));
795         break;
796       }
797     }
798
799   #if !defined(GL_ES_VERSION_2_0)
800     // manage FFP lighting
801     if (aCtx->ActiveProgram().IsNull()
802      && aCtx->core11 != NULL)
803     {
804       if (!isLightOn)
805       {
806         glDisable (GL_LIGHTING);
807       }
808       else
809       {
810         glEnable (GL_LIGHTING);
811       }
812     }
813   #endif
814
815     if (!aCtx->ActiveTextures().IsNull()
816      && !aCtx->ActiveTextures()->IsEmpty()
817      && !aCtx->ActiveTextures()->First().IsNull()
818      && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
819     {
820       aCtx->SetTextureMatrix (aCtx->ActiveTextures()->First()->Sampler()->Parameters());
821     }
822
823     if (myDrawMode <= GL_LINE_STRIP)
824     {
825       const OpenGl_Vec4& aLineColor = myDrawMode == GL_POINTS ? theWorkspace->MarkerColor() : theWorkspace->LineColor();
826       aCtx->SetColor4fv (aLineColor);
827     }
828     else
829     {
830       const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
831       aCtx->SetColor4fv (anInteriorColor);
832     }
833     if (myDrawMode == GL_LINES
834      || myDrawMode == GL_LINE_STRIP)
835     {
836       aCtx->SetTypeOfLine (anAspectLine->Aspect()->Type());
837       aCtx->SetLineWidth  (anAspectLine->Aspect()->Width());
838     }
839
840     const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
841                                       ?  myBounds->Colors
842                                       :  NULL;
843
844     const Standard_Boolean isHighlightWithTransparency = toHilight &&
845       myDrawMode > GL_LINE_STRIP &&
846       theWorkspace->InteriorColor().a() > 0.05f;
847     GLint  aPrevBlendSrc = GL_SRC_ALPHA, aPrevBlendDst = GL_ONE_MINUS_SRC_ALPHA;
848     GLboolean wasBlendEnabled = GL_FALSE;
849     if (isHighlightWithTransparency)
850     {
851       wasBlendEnabled = glIsEnabled (GL_BLEND);
852       #if !defined(GL_ES_VERSION_2_0)
853         glGetIntegerv (GL_BLEND_SRC, &aPrevBlendSrc);
854         glGetIntegerv (GL_BLEND_DST, &aPrevBlendDst);
855       #endif
856       if (!wasBlendEnabled)
857       {
858         glEnable (GL_BLEND);
859       }
860       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
861     }
862
863     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
864
865     if (isHighlightWithTransparency)
866     {
867       glBlendFunc (aPrevBlendSrc, aPrevBlendDst);
868       if (!wasBlendEnabled)
869       {
870         glDisable (GL_BLEND);
871       }
872     }
873   }
874
875   if (myDrawMode <= GL_LINE_STRIP)
876   {
877     aCtx->BindTextures (aTextureBack);
878   }
879   else
880   {
881     if (anAspectFace->Aspect()->ToDrawEdges()
882      || anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_HIDDENLINE)
883     {
884       const OpenGl_Vec4& anEdgeColor = theWorkspace->EdgeColor();
885       drawEdges (anEdgeColor, theWorkspace);
886
887       // restore OpenGL polygon mode if needed
888     #if !defined(GL_ES_VERSION_2_0)
889       if (anAspectFace->Aspect()->InteriorStyle() >= Aspect_IS_HATCH)
890       {
891         glPolygonMode (GL_FRONT_AND_BACK,
892           anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_POINT ? GL_POINT : GL_FILL);
893       }
894     #endif
895     }
896   }
897 }
898
899 // =======================================================================
900 // function : setDrawMode
901 // purpose  :
902 // =======================================================================
903 void OpenGl_PrimitiveArray::setDrawMode (const Graphic3d_TypeOfPrimitiveArray theType)
904 {
905   if (myAttribs.IsNull())
906   {
907     myDrawMode = DRAW_MODE_NONE;
908     return;
909   }
910
911   switch (theType)
912   {
913     case Graphic3d_TOPA_POINTS:
914       myDrawMode = GL_POINTS;
915       break;
916     case Graphic3d_TOPA_POLYLINES:
917       myDrawMode = GL_LINE_STRIP;
918       break;
919     case Graphic3d_TOPA_SEGMENTS:
920       myDrawMode = GL_LINES;
921       break;
922     case Graphic3d_TOPA_TRIANGLES:
923       myDrawMode = GL_TRIANGLES;
924       break;
925     case Graphic3d_TOPA_TRIANGLESTRIPS:
926       myDrawMode = GL_TRIANGLE_STRIP;
927       break;
928     case Graphic3d_TOPA_TRIANGLEFANS:
929       myDrawMode = GL_TRIANGLE_FAN;
930       break;
931   #if !defined(GL_ES_VERSION_2_0)
932     case Graphic3d_TOPA_POLYGONS:
933       myDrawMode = GL_POLYGON;
934       break;
935     case Graphic3d_TOPA_QUADRANGLES:
936       myDrawMode = GL_QUADS;
937       break;
938     case Graphic3d_TOPA_QUADRANGLESTRIPS:
939       myDrawMode = GL_QUAD_STRIP;
940       break;
941   #else
942     case Graphic3d_TOPA_POLYGONS:
943     case Graphic3d_TOPA_QUADRANGLES:
944     case Graphic3d_TOPA_QUADRANGLESTRIPS:
945   #endif
946     case Graphic3d_TOPA_UNDEFINED:
947       break;
948   }
949 }
950
951 // =======================================================================
952 // function : processIndices
953 // purpose  :
954 // =======================================================================
955 Standard_Boolean OpenGl_PrimitiveArray::processIndices (const Handle(OpenGl_Context)& theContext) const
956 {
957   if (myIndices.IsNull()
958    || myAttribs.IsNull()
959    || theContext->hasUintIndex)
960   {
961     return Standard_True;
962   }
963
964   if (myAttribs->NbElements > std::numeric_limits<GLushort>::max())
965   {
966     Handle(Graphic3d_Buffer) anAttribs = new Graphic3d_Buffer (new NCollection_AlignedAllocator (16));
967     if (!anAttribs->Init (myIndices->NbElements, myAttribs->AttributesArray(), myAttribs->NbAttributes))
968     {
969       return Standard_False; // failed to initialize attribute array
970     }
971
972     for (Standard_Integer anIdxIdx = 0; anIdxIdx < myIndices->NbElements; ++anIdxIdx)
973     {
974       const Standard_Integer anIndex = myIndices->Index (anIdxIdx);
975       memcpy (anAttribs->ChangeData() + myAttribs->Stride * anIdxIdx,
976               myAttribs->Data()       + myAttribs->Stride * anIndex,
977               myAttribs->Stride);
978     }
979
980     myIndices.Nullify();
981     myAttribs = anAttribs;
982   }
983
984   return Standard_True;
985 }
986
987 // =======================================================================
988 // function : InitBuffers
989 // purpose  :
990 // =======================================================================
991 void OpenGl_PrimitiveArray::InitBuffers (const Handle(OpenGl_Context)&        theContext,
992                                          const Graphic3d_TypeOfPrimitiveArray theType,
993                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
994                                          const Handle(Graphic3d_Buffer)&      theAttribs,
995                                          const Handle(Graphic3d_BoundBuffer)& theBounds)
996 {
997   // Release old graphic resources
998   Release (theContext.operator->());
999
1000   myIndices = theIndices;
1001   myAttribs = theAttribs;
1002   myBounds = theBounds;
1003 #if defined(GL_ES_VERSION_2_0)
1004   processIndices (theContext);
1005 #endif
1006
1007   setDrawMode (theType);
1008 }