0025133: TKOpenGl - Crash on closing a view containing presentations with capping
[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_ShaderManager.hxx>
23 #include <OpenGl_ShaderProgram.hxx>
24 #include <OpenGl_Structure.hxx>
25 #include <OpenGl_Workspace.hxx>
26
27 namespace
28 {
29   template<class T>
30   void BindProgramWithMaterial (const Handle(OpenGl_Workspace)& theWS,
31                                 const T*                      theAspect)
32   {
33     const Handle(OpenGl_Context)& aCtx = theWS->GetGlContext();
34     const Handle(OpenGl_ShaderProgram)& aProgram = theAspect->ShaderProgramRes (theWS);
35     if (aProgram.IsNull())
36     {
37       OpenGl_ShaderProgram::Unbind (aCtx);
38       return;
39     }
40     aProgram->BindWithVariables (aCtx);
41
42     const OpenGl_MaterialState* aMaterialState = aCtx->ShaderManager()->MaterialState (aProgram);
43     if (aMaterialState == NULL || aMaterialState->Aspect() != theAspect)
44     {
45       aCtx->ShaderManager()->UpdateMaterialStateTo (aProgram, theAspect);
46     }
47
48     aCtx->ShaderManager()->PushState (aProgram);
49   }
50
51   //! Convert index data type from size
52   inline GLenum toGlIndexType (const Standard_Integer theStride)
53   {
54     switch (theStride)
55     {
56       case 2:  return GL_UNSIGNED_SHORT;
57       case 4:  return GL_UNSIGNED_INT;
58       default: return GL_NONE;
59     }
60   }
61
62   //! Convert data type to GL info
63   inline GLenum toGlDataType (const Graphic3d_TypeOfData theType,
64                               GLint&                     theNbComp)
65   {
66     switch (theType)
67     {
68       case Graphic3d_TOD_USHORT:
69         theNbComp = 1;
70         return GL_UNSIGNED_SHORT;
71       case Graphic3d_TOD_UINT:
72         theNbComp = 1;
73         return GL_UNSIGNED_INT;
74       case Graphic3d_TOD_VEC2:
75         theNbComp = 2;
76         return GL_FLOAT;
77       case Graphic3d_TOD_VEC3:
78         theNbComp = 3;
79         return GL_FLOAT;
80       case Graphic3d_TOD_VEC4:
81         theNbComp = 4;
82         return GL_FLOAT;
83       case Graphic3d_TOD_VEC4UB:
84         theNbComp = 4;
85         return GL_UNSIGNED_BYTE;
86     }
87     theNbComp = 0;
88     return GL_NONE;
89   }
90
91 }
92
93 //! Auxiliary template for VBO with interleaved attributes.
94 template<int NbAttributes>
95 class OpenGl_VertexBufferT : public OpenGl_VertexBuffer
96 {
97
98 public:
99
100   //! Create uninitialized VBO.
101   OpenGl_VertexBufferT (const Graphic3d_Attribute* theAttribs,
102                         const Standard_Integer     theStride)
103   : Stride (theStride)
104   {
105     memcpy (Attribs, theAttribs, sizeof(Graphic3d_Attribute) * NbAttributes);
106   }
107
108   //! Create uninitialized VBO.
109   OpenGl_VertexBufferT (const Graphic3d_Buffer& theAttribs)
110   : Stride (theAttribs.Stride)
111   {
112     memcpy (Attribs, theAttribs.AttributesArray(), sizeof(Graphic3d_Attribute) * NbAttributes);
113   }
114
115   virtual bool HasColorAttribute() const
116   {
117     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
118     {
119       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
120       if (anAttrib.Id == Graphic3d_TOA_COLOR)
121       {
122         return true;
123       }
124     }
125     return false;
126   }
127
128   virtual void BindFixedPosition (const Handle(OpenGl_Context)& theGlCtx) const
129   {
130     if (!IsValid())
131     {
132       return;
133     }
134
135     Bind (theGlCtx);
136     GLint aNbComp;
137     const GLubyte* anOffset = NULL;
138     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
139     {
140       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
141       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
142       if (aDataType == GL_NONE)
143       {
144         continue;
145       }
146       else if (anAttrib.Id == Graphic3d_TOA_POS)
147       {
148         bindFixed (theGlCtx, Graphic3d_TOA_POS, aNbComp, aDataType, Stride, anOffset);
149         break;
150       }
151
152       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
153     }
154   }
155
156   virtual void BindFixed (const Handle(OpenGl_Context)& theGlCtx) const
157   {
158     if (!IsValid())
159     {
160       return;
161     }
162
163     Bind (theGlCtx);
164     GLint aNbComp;
165     const GLubyte* anOffset = NULL;
166     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
167     {
168       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
169       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
170       if (aDataType == GL_NONE)
171       {
172         continue;
173       }
174
175       bindFixed (theGlCtx, anAttrib.Id, aNbComp, aDataType, Stride, anOffset);
176       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
177     }
178   }
179
180   virtual void UnbindFixed (const Handle(OpenGl_Context)& theGlCtx) const
181   {
182     if (!IsValid())
183     {
184       return;
185     }
186     Unbind (theGlCtx);
187
188     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
189     {
190       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
191       unbindFixed (theGlCtx, anAttrib.Id);
192     }
193   }
194
195 public:
196
197   Graphic3d_Attribute Attribs[NbAttributes];
198   Standard_Integer    Stride;
199
200 };
201
202 // =======================================================================
203 // function : clearMemoryGL
204 // purpose  :
205 // =======================================================================
206 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
207 {
208   if (!myVboIndices.IsNull())
209   {
210     myVboIndices->Release (theGlCtx.operator->());
211     myVboIndices.Nullify();
212   }
213   if (!myVboAttribs.IsNull())
214   {
215     myVboAttribs->Release (theGlCtx.operator->());
216     myVboAttribs.Nullify();
217   }
218 }
219
220 // =======================================================================
221 // function : BuildVBO
222 // purpose  :
223 // =======================================================================
224 Standard_Boolean OpenGl_PrimitiveArray::BuildVBO (const Handle(OpenGl_Workspace)& theWorkspace) const
225 {
226   const Handle(OpenGl_Context)& aGlCtx = theWorkspace->GetGlContext();
227   if (myAttribs.IsNull()
228    || myAttribs->IsEmpty()
229    || myAttribs->NbElements < 1)
230   {
231     // vertices should be always defined - others are optional
232     return Standard_False;
233   }
234
235   switch (myAttribs->NbAttributes)
236   {
237     case 1:  myVboAttribs = new OpenGl_VertexBufferT<1> (*myAttribs); break;
238     case 2:  myVboAttribs = new OpenGl_VertexBufferT<2> (*myAttribs); break;
239     case 3:  myVboAttribs = new OpenGl_VertexBufferT<3> (*myAttribs); break;
240     case 4:  myVboAttribs = new OpenGl_VertexBufferT<4> (*myAttribs); break;
241     case 5:  myVboAttribs = new OpenGl_VertexBufferT<5> (*myAttribs); break;
242     case 6:  myVboAttribs = new OpenGl_VertexBufferT<6> (*myAttribs); break;
243     case 7:  myVboAttribs = new OpenGl_VertexBufferT<7> (*myAttribs); break;
244     case 8:  myVboAttribs = new OpenGl_VertexBufferT<8> (*myAttribs); break;
245     case 9:  myVboAttribs = new OpenGl_VertexBufferT<9> (*myAttribs); break;
246     case 10: myVboAttribs = new OpenGl_VertexBufferT<10>(*myAttribs); break;
247     default: return Standard_False;
248   }
249
250   if (!myVboAttribs->init (aGlCtx, 0, myAttribs->NbElements, myAttribs->Data(), GL_NONE, myAttribs->Stride))
251   {
252     clearMemoryGL (aGlCtx);
253     return Standard_False;
254   }
255
256   if (!myIndices.IsNull())
257   {
258     myVboIndices = new OpenGl_IndexBuffer();
259     bool isOk = Standard_False;
260     switch (myIndices->Stride)
261     {
262       case 2:
263       {
264         isOk = myVboIndices->Init (aGlCtx, 1, myIndices->NbElements, reinterpret_cast<const GLushort*> (myIndices->Data()));
265         break;
266       }
267       case 4:
268       {
269         isOk = myVboIndices->Init (aGlCtx, 1, myIndices->NbElements, reinterpret_cast<const GLuint*> (myIndices->Data()));
270         break;
271       }
272       default: break;
273     }
274     if (!isOk)
275     {
276       clearMemoryGL (aGlCtx);
277       return Standard_False;
278     }
279   }
280
281   if (!aGlCtx->caps->keepArrayData)
282   {
283     myIndices.Nullify();
284     myAttribs.Nullify();
285   }
286   
287   return Standard_True;
288 }
289
290 // =======================================================================
291 // function : DrawArray
292 // purpose  :
293 // =======================================================================
294 void OpenGl_PrimitiveArray::DrawArray (Tint theLightingModel,
295                                        const Aspect_InteriorStyle theInteriorStyle,
296                                        Tint theEdgeFlag,
297                                        const TEL_COLOUR* theInteriorColour,
298                                        const TEL_COLOUR* theLineColour,
299                                        const TEL_COLOUR* theEdgeColour,
300                                        const Handle(OpenGl_Workspace)& theWorkspace) const
301 {
302   const Handle(OpenGl_Context)& aGlContext  = theWorkspace->GetGlContext();
303   const Graphic3d_Vec4*         aFaceColors = myBounds.IsNull() ? NULL : myBounds->Colors;
304   const bool                    toHilight   = (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT) != 0;
305   bool                          hasVColors  = false;
306
307   glColor3fv (myDrawMode <= GL_LINE_STRIP ? theLineColour->rgb : theInteriorColour->rgb);
308
309   // Temporarily disable environment mapping
310   if (myDrawMode <= GL_LINE_STRIP)
311   {
312     glPushAttrib (GL_ENABLE_BIT);
313     glDisable (GL_TEXTURE_1D);
314     glDisable (GL_TEXTURE_2D);
315   }
316
317   if ((myDrawMode >  GL_LINE_STRIP && theInteriorStyle != Aspect_IS_EMPTY) ||
318       (myDrawMode <= GL_LINE_STRIP))
319   {
320     if (toHilight)
321     {
322       aFaceColors = NULL;
323     }
324
325     if (theInteriorStyle == Aspect_IS_HIDDENLINE)
326     {
327       theEdgeFlag = 1;
328       aFaceColors = NULL;
329     }
330
331     // Sometimes the GL_LIGHTING mode is activated here
332     // without glEnable(GL_LIGHTING) call for an unknown reason, so it is necessary
333     // to call glEnable(GL_LIGHTING) to synchronize Light On/Off mechanism*
334     if (theLightingModel == 0 || myDrawMode <= GL_LINE_STRIP)
335       glDisable (GL_LIGHTING);
336     else
337       glEnable (GL_LIGHTING);
338
339     if (!myVboAttribs.IsNull())
340     {
341       myVboAttribs->BindFixed (aGlContext);
342       if (myVboAttribs->HasColorAttribute())
343       {
344         if (toHilight)
345         {
346           // disable per-vertex colors
347           OpenGl_VertexBuffer::unbindFixed (aGlContext, Graphic3d_TOA_COLOR);
348         }
349         else
350         {
351           hasVColors = true;
352         }
353       }
354       if (!myVboIndices.IsNull())
355       {
356         myVboIndices->Bind (aGlContext);
357         if (!myBounds.IsNull())
358         {
359           // draw primitives by vertex count with the indices
360           const size_t aStride  = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
361           GLubyte*     anOffset = NULL;
362           for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
363           {
364             const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
365             if (aFaceColors != NULL) glColor3fv (aFaceColors[aGroupIter].GetData());
366             glDrawElements (myDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
367             anOffset += aStride * aNbElemsInGroup;
368           }
369         }
370         else
371         {
372           // draw one (or sequential) primitive by the indices
373           glDrawElements (myDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), NULL);
374         }
375         myVboIndices->Unbind (aGlContext);
376       }
377       else if (!myBounds.IsNull())
378       {
379         GLint aFirstElem = 0;
380         for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
381         {
382           const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
383           if (aFaceColors != NULL) glColor3fv (aFaceColors[aGroupIter].GetData());
384           glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
385           aFirstElem += aNbElemsInGroup;
386         }
387       }
388       else
389       {
390         if (myDrawMode == GL_POINTS)
391         {
392           DrawMarkers (theWorkspace);
393         }
394         else
395         {
396           glDrawArrays (myDrawMode, 0, myVboAttribs->GetElemsNb());
397         }
398       }
399
400       // bind with 0
401       myVboAttribs->UnbindFixed (aGlContext);
402     }
403     else
404     {
405       GLint aNbComp;
406       for (Standard_Integer anAttribIter = 0; anAttribIter < myAttribs->NbAttributes; ++anAttribIter)
407       {
408         const Graphic3d_Attribute& anAttrib = myAttribs->Attribute (anAttribIter);
409         if (anAttrib.Id == Graphic3d_TOA_COLOR)
410         {
411           if (toHilight)
412           {
413             continue;
414           }
415           hasVColors = true;
416         }
417         const GLenum  aDataType = toGlDataType (anAttrib.DataType, aNbComp);
418         const GLvoid* aData     = myAttribs->Data (anAttribIter);
419         if (aDataType == GL_NONE)
420         {
421           continue;
422         }
423
424         OpenGl_VertexBuffer::bindFixed (aGlContext, anAttrib.Id, aNbComp, aDataType, myAttribs->Stride, aData);
425       }
426
427       if (!myBounds.IsNull())
428       {
429         GLint aFirstElem = 0;
430         if (!myIndices.IsNull())
431         {
432           const GLenum anIndexType = toGlIndexType (myIndices->Stride);
433           for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
434           {
435             const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
436             if (aFaceColors != NULL) glColor3fv (aFaceColors[aGroupIter].GetData());
437             glDrawElements (myDrawMode, aNbElemsInGroup, anIndexType, myIndices->value (aFirstElem));
438             aFirstElem += aNbElemsInGroup;
439           }
440         }
441         else
442         {
443           for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
444           {
445             const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
446             if (aFaceColors != NULL) glColor3fv (aFaceColors[aGroupIter].GetData());
447             glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
448             aFirstElem += aNbElemsInGroup;
449           }
450         }
451       }
452       else if (!myIndices.IsNull())
453       {
454         glDrawElements (myDrawMode, myIndices->NbElements, toGlIndexType (myIndices->Stride), myIndices->Data());
455       }
456       else
457       {
458         if (myDrawMode == GL_POINTS)
459         {
460           DrawMarkers (theWorkspace);
461         }
462         else
463         {
464           glDrawArrays (myDrawMode, 0, myAttribs->NbElements);
465         }
466       }
467
468       for (Standard_Integer anAttribIter = 0; anAttribIter < myAttribs->NbAttributes; ++anAttribIter)
469       {
470         const Graphic3d_Attribute& anAttrib = myAttribs->Attribute (anAttribIter);
471         OpenGl_VertexBuffer::unbindFixed (aGlContext, anAttrib.Id);
472       }
473     }
474   }
475
476   if (hasVColors)
477   {
478     theWorkspace->NamedStatus |= OPENGL_NS_RESMAT;
479   }
480
481   if (theEdgeFlag && myDrawMode > GL_LINE_STRIP)
482   {
483     DrawEdges (theEdgeColour, theWorkspace);
484   }
485
486   if (myDrawMode <= GL_LINE_STRIP)
487     glPopAttrib();
488 }
489
490 // =======================================================================
491 // function : DrawEdges
492 // purpose  :
493 // =======================================================================
494 void OpenGl_PrimitiveArray::DrawEdges (const TEL_COLOUR*               theEdgeColour,
495                                        const Handle(OpenGl_Workspace)& theWorkspace) const
496 {
497   glDisable (GL_LIGHTING);
498
499   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
500   const OpenGl_AspectLine* anAspectLineOld = NULL;
501   if (myDrawMode > GL_LINE_STRIP)
502   {
503     anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace (Standard_True)->AspectEdge());
504     const OpenGl_AspectLine* anAspect = theWorkspace->AspectLine (Standard_True);
505
506     glPushAttrib (GL_POLYGON_BIT);
507     glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
508
509     if (aGlContext->IsGlGreaterEqual (2, 0))
510     {
511       BindProgramWithMaterial (theWorkspace, anAspect);
512     }
513   }
514
515   /// OCC22236 NOTE: draw edges for all situations:
516   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indices array
517   /// 2) draw elements from vertex array, when bounds defines count of primitive's vertices.
518   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
519   if (!myVboAttribs.IsNull())
520   {
521     myVboAttribs->BindFixedPosition (aGlContext);
522     glColor3fv (theEdgeColour->rgb);
523     if (!myVboIndices.IsNull())
524     {
525       myVboIndices->Bind (aGlContext);
526
527       // draw primitives by vertex count with the indices
528       if (!myBounds.IsNull())
529       {
530         const size_t aStride  = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
531         GLubyte*     anOffset = NULL;
532         for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
533         {
534           const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
535           glDrawElements (myDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
536           anOffset += aStride * aNbElemsInGroup;
537         }
538       }
539       // draw one (or sequential) primitive by the indices
540       else
541       {
542         glDrawElements (myDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), NULL);
543       }
544       myVboIndices->Unbind (aGlContext);
545     }
546     else if (!myBounds.IsNull())
547     {
548       GLint aFirstElem = 0;
549       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
550       {
551         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
552         glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
553         aFirstElem += aNbElemsInGroup;
554       }
555     }
556     else
557     {
558       glDrawArrays (myDrawMode, 0, myAttribs->NbElements);
559     }
560
561     // unbind buffers
562     myVboAttribs->UnbindFixed (aGlContext, GL_VERTEX_ARRAY);
563   }
564   else
565   {
566     GLint aNbComp;
567     for (Standard_Integer anAttribIter = 0; anAttribIter < myAttribs->NbAttributes; ++anAttribIter)
568     {
569       const Graphic3d_Attribute& anAttrib = myAttribs->Attribute (anAttribIter);
570       if (anAttrib.Id == Graphic3d_TOA_POS)
571       {
572         const GLenum  aDataType = toGlDataType (anAttrib.DataType, aNbComp);
573         const GLvoid* aData     = myAttribs->Data (anAttribIter);
574         OpenGl_VertexBuffer::bindFixed (aGlContext, anAttrib.Id, aNbComp, aDataType, myAttribs->Stride, aData);
575         break;
576       }
577     }
578
579     glColor3fv (theEdgeColour->rgb);
580     if (!myBounds.IsNull())
581     {
582       if (!myIndices.IsNull())
583       {
584         const GLenum anIndexType = toGlIndexType (myIndices->Stride);
585         GLint aFirstElem = 0;
586         for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
587         {
588           const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
589           glDrawElements (myDrawMode, aNbElemsInGroup, anIndexType, myIndices->value (aFirstElem));
590           aFirstElem += aNbElemsInGroup;
591         }
592       }
593       else
594       {
595         GLint aFirstElem = 0;
596         for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
597         {
598           const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
599           glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
600           aFirstElem += aNbElemsInGroup;
601         }
602       }
603     }
604     else if (!myIndices.IsNull())
605     {
606       glDrawElements (myDrawMode, myIndices->NbElements, toGlIndexType (myIndices->Stride), myIndices->Data());
607     }
608     else
609     {
610       glDrawArrays (myDrawMode, 0, myAttribs->NbElements);
611     }
612   }
613
614   if (myDrawMode > GL_LINE_STRIP)
615   {
616     // Restore line context
617     theWorkspace->SetAspectLine (anAspectLineOld);
618     glPopAttrib();
619   }
620 }
621
622 // =======================================================================
623 // function : DrawMarkers
624 // purpose  :
625 // =======================================================================
626 void OpenGl_PrimitiveArray::DrawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
627 {
628   const OpenGl_AspectMarker* anAspectMarker     = theWorkspace->AspectMarker (Standard_True);
629   const Handle(OpenGl_Context)&     aCtx        = theWorkspace->GetGlContext();
630   const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (theWorkspace);
631   const Standard_Boolean            isHilight   = (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT);
632   if (aCtx->IsGlGreaterEqual (2, 0)
633    && !aSpriteNorm.IsNull() && !aSpriteNorm->IsDisplayList())
634   {
635     // Textured markers will be drawn with the point sprites
636     glPointSize (anAspectMarker->MarkerSize());
637
638     Handle(OpenGl_Texture) aTextureBack;
639     if (anAspectMarker->Type() != Aspect_TOM_POINT)
640     {
641       const Handle(OpenGl_PointSprite)& aSprite = (isHilight && anAspectMarker->SpriteHighlightRes (theWorkspace)->IsValid())
642                                                 ? anAspectMarker->SpriteHighlightRes (theWorkspace)
643                                                 : aSpriteNorm;
644       aTextureBack = theWorkspace->EnableTexture (aSprite);
645
646       glEnable (GL_ALPHA_TEST);
647       glAlphaFunc (GL_GEQUAL, 0.1f);
648
649       glEnable (GL_BLEND);
650       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
651     }
652
653     glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
654
655     glDisable (GL_BLEND);
656     glDisable (GL_ALPHA_TEST);
657     if (anAspectMarker->Type() != Aspect_TOM_POINT)
658     {
659       theWorkspace->EnableTexture (aTextureBack);
660     }
661     glPointSize (1.0f);
662     return;
663   }
664
665   // Textured markers will be drawn with the glBitmap
666   if (anAspectMarker->Type() == Aspect_TOM_POINT
667    || anAspectMarker->Type() == Aspect_TOM_O_POINT)
668   {
669     const GLfloat aPntSize = anAspectMarker->Type() == Aspect_TOM_POINT
670                            ? anAspectMarker->MarkerSize()
671                            : 0.0f;
672     if (aPntSize > 0.0f)
673     {
674       glPointSize (aPntSize);
675     }
676     glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
677     if (aPntSize > 0.0f)
678     {
679       glPointSize (1.0f);
680     }
681   }
682
683   if (anAspectMarker->Type() != Aspect_TOM_POINT
684    && !aSpriteNorm.IsNull())
685   {
686     /**if (!isHilight && (myPArray->vcolours != NULL))
687     {
688       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
689       {
690         glColor4ubv    (myPArray->vcolours[anIter].GetData());
691         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
692         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
693       }
694     }
695     else*/
696     {
697       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
698       {
699         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
700         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
701       }
702     }
703   }
704 }
705
706 // =======================================================================
707 // function : OpenGl_PrimitiveArray
708 // purpose  :
709 // =======================================================================
710 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver*          theDriver,
711                                               const Graphic3d_TypeOfPrimitiveArray theType,
712                                               const Handle(Graphic3d_IndexBuffer)& theIndices,
713                                               const Handle(Graphic3d_Buffer)&      theAttribs,
714                                               const Handle(Graphic3d_BoundBuffer)& theBounds)
715
716 : myIndices   (theIndices),
717   myAttribs   (theAttribs),
718   myBounds    (theBounds),
719   myDrawMode  (DRAW_MODE_NONE),
720   myIsVboInit (Standard_False),
721   myUID       (theDriver->GetNextPrimitiveArrayUID())
722 {
723   if (!myIndices.IsNull()
724     && myIndices->NbElements < 1)
725   {
726     // dummy index buffer?
727     myIndices.Nullify();
728   }
729   if (myAttribs.IsNull())
730   {
731     return;
732   }
733
734   switch (theType)
735   {
736     case Graphic3d_TOPA_POINTS:
737       myDrawMode = GL_POINTS;
738       break;
739     case Graphic3d_TOPA_POLYLINES:
740       myDrawMode = GL_LINE_STRIP;
741       break;
742     case Graphic3d_TOPA_SEGMENTS:
743       myDrawMode = GL_LINES;
744       break;
745     case Graphic3d_TOPA_POLYGONS:
746       myDrawMode = GL_POLYGON;
747       break;
748     case Graphic3d_TOPA_TRIANGLES:
749       myDrawMode = GL_TRIANGLES;
750       break;
751     case Graphic3d_TOPA_QUADRANGLES:
752       myDrawMode = GL_QUADS;
753       break;
754     case Graphic3d_TOPA_TRIANGLESTRIPS:
755       myDrawMode = GL_TRIANGLE_STRIP;
756       break;
757     case Graphic3d_TOPA_QUADRANGLESTRIPS:
758       myDrawMode = GL_QUAD_STRIP;
759       break;
760     case Graphic3d_TOPA_TRIANGLEFANS:
761       myDrawMode = GL_TRIANGLE_FAN;
762       break;
763     case Graphic3d_TOPA_UNDEFINED:
764       break;
765   }
766 }
767
768 // =======================================================================
769 // function : ~OpenGl_PrimitiveArray
770 // purpose  :
771 // =======================================================================
772 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
773 {
774   //
775 }
776
777 // =======================================================================
778 // function : Release
779 // purpose  :
780 // =======================================================================
781 void OpenGl_PrimitiveArray::Release (OpenGl_Context* theContext)
782 {
783   if (!myVboIndices.IsNull())
784   {
785     if (theContext)
786     {
787       theContext->DelayedRelease (myVboIndices);
788     }
789     myVboIndices.Nullify();
790   }
791   if (!myVboAttribs.IsNull())
792   {
793     if (theContext)
794     {
795       theContext->DelayedRelease (myVboAttribs);
796     }
797     myVboAttribs.Nullify();
798   }
799 }
800
801 // =======================================================================
802 // function : Render
803 // purpose  :
804 // =======================================================================
805 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
806 {
807   if (myDrawMode == DRAW_MODE_NONE)
808   {
809     return;
810   }
811
812   const OpenGl_AspectFace*   anAspectFace   = theWorkspace->AspectFace   (Standard_True);
813   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->AspectLine   (Standard_True);
814   const OpenGl_AspectMarker* anAspectMarker = theWorkspace->AspectMarker (myDrawMode == GL_POINTS);
815
816   // create VBOs on first render call
817   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
818   if (!myIsVboInit
819    && !aCtx->caps->vboDisable
820    && aCtx->core15 != NULL
821    && (myDrawMode != GL_POINTS || anAspectMarker->SpriteRes (theWorkspace).IsNull() || !anAspectMarker->SpriteRes (theWorkspace)->IsDisplayList()))
822   {
823     if (!BuildVBO (theWorkspace))
824     {
825       TCollection_ExtendedString aMsg;
826       aMsg += "VBO creation for Primitive Array has failed for ";
827       aMsg += myAttribs->NbElements;
828       aMsg += " vertices. Out of memory?";
829       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_PERFORMANCE_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMsg);
830     }
831     myIsVboInit = Standard_True;
832   }
833
834   if (myDrawMode <= GL_LINE_STRIP)
835   {
836     glDisable (GL_LIGHTING);
837   }
838
839   Tint aFrontLightingModel = anAspectFace->IntFront().color_mask;
840   const TEL_COLOUR* anInteriorColor = &anAspectFace->IntFront().matcol;
841   const TEL_COLOUR* anEdgeColor = &anAspectFace->AspectEdge()->Color();
842   const TEL_COLOUR* aLineColor  = myDrawMode == GL_POINTS ? &anAspectMarker->Color() : &anAspectLine->Color();
843
844   // Use highlight colors
845   if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
846   {
847     anEdgeColor = anInteriorColor = aLineColor = theWorkspace->HighlightColor;
848     aFrontLightingModel = 0;
849   }
850
851   if (aCtx->IsGlGreaterEqual (2, 0))
852   {
853     switch (myDrawMode)
854     {
855       case GL_POINTS:
856       {
857         BindProgramWithMaterial (theWorkspace, anAspectMarker);
858         break;
859       }
860       case GL_LINES:
861       case GL_LINE_STRIP:
862       {
863         BindProgramWithMaterial (theWorkspace, anAspectLine);
864         break;
865       }
866       default: // polygonal array
867       {
868         BindProgramWithMaterial (theWorkspace, anAspectFace);
869         break;
870       }
871     }
872   }
873
874   DrawArray (aFrontLightingModel,
875              anAspectFace->InteriorStyle(),
876              anAspectFace->Edge(),
877              anInteriorColor,
878              aLineColor,
879              anEdgeColor,
880              theWorkspace);
881 }