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