0025304: Visualization, TKOpenGl - support texturing within built-in GLSL programs
[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->IsGlGreaterEqual (2, 0))
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     aCtx->core11fwd->glEnable (GL_ALPHA_TEST);
547     aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, 0.1f);
548   #endif
549
550     aCtx->core11fwd->glEnable (GL_BLEND);
551     aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
552
553     aCtx->core11fwd->glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
554
555     aCtx->core11fwd->glDisable (GL_BLEND);
556   #if !defined(GL_ES_VERSION_2_0)
557     aCtx->core11fwd->glDisable (GL_ALPHA_TEST);
558   #endif
559     aCtx->SetPointSize (1.0f);
560     return;
561   }
562   else if (anAspectMarker->Type() == Aspect_TOM_POINT)
563   {
564     aCtx->SetPointSize (anAspectMarker->MarkerSize());
565     aCtx->core11fwd->glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
566     aCtx->SetPointSize (1.0f);
567   }
568 #if !defined(GL_ES_VERSION_2_0)
569   // Textured markers will be drawn with the glBitmap
570   else if (anAspectMarker->Type() != Aspect_TOM_POINT
571        && !aSpriteNorm.IsNull())
572   {
573     /**if (!isHilight && (myPArray->vcolours != NULL))
574     {
575       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
576       {
577         glColor4ubv    (myPArray->vcolours[anIter].GetData());
578         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
579         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
580       }
581     }
582     else*/
583     {
584       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
585       {
586         aCtx->core11->glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
587         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
588       }
589     }
590   }
591 #endif
592 }
593
594 // =======================================================================
595 // function : OpenGl_PrimitiveArray
596 // purpose  :
597 // =======================================================================
598 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver*          theDriver,
599                                               const Graphic3d_TypeOfPrimitiveArray theType,
600                                               const Handle(Graphic3d_IndexBuffer)& theIndices,
601                                               const Handle(Graphic3d_Buffer)&      theAttribs,
602                                               const Handle(Graphic3d_BoundBuffer)& theBounds)
603
604 : myIndices   (theIndices),
605   myAttribs   (theAttribs),
606   myBounds    (theBounds),
607   myDrawMode  (DRAW_MODE_NONE),
608   myIsVboInit (Standard_False)
609 {
610   if (theDriver != NULL)
611   {
612     myUID = theDriver->GetNextPrimitiveArrayUID();
613   }
614
615   if (!myIndices.IsNull()
616     && myIndices->NbElements < 1)
617   {
618     // dummy index buffer?
619     myIndices.Nullify();
620   }
621   if (myAttribs.IsNull())
622   {
623     return;
624   }
625
626   switch (theType)
627   {
628     case Graphic3d_TOPA_POINTS:
629       myDrawMode = GL_POINTS;
630       break;
631     case Graphic3d_TOPA_POLYLINES:
632       myDrawMode = GL_LINE_STRIP;
633       break;
634     case Graphic3d_TOPA_SEGMENTS:
635       myDrawMode = GL_LINES;
636       break;
637     case Graphic3d_TOPA_TRIANGLES:
638       myDrawMode = GL_TRIANGLES;
639       break;
640     case Graphic3d_TOPA_TRIANGLESTRIPS:
641       myDrawMode = GL_TRIANGLE_STRIP;
642       break;
643     case Graphic3d_TOPA_TRIANGLEFANS:
644       myDrawMode = GL_TRIANGLE_FAN;
645       break;
646   #if !defined(GL_ES_VERSION_2_0)
647     case Graphic3d_TOPA_POLYGONS:
648       myDrawMode = GL_POLYGON;
649       break;
650     case Graphic3d_TOPA_QUADRANGLES:
651       myDrawMode = GL_QUADS;
652       break;
653     case Graphic3d_TOPA_QUADRANGLESTRIPS:
654       myDrawMode = GL_QUAD_STRIP;
655       break;
656   #else
657     case Graphic3d_TOPA_POLYGONS:
658     case Graphic3d_TOPA_QUADRANGLES:
659     case Graphic3d_TOPA_QUADRANGLESTRIPS:
660   #endif
661     case Graphic3d_TOPA_UNDEFINED:
662       break;
663   }
664 }
665
666 // =======================================================================
667 // function : ~OpenGl_PrimitiveArray
668 // purpose  :
669 // =======================================================================
670 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
671 {
672   //
673 }
674
675 // =======================================================================
676 // function : Release
677 // purpose  :
678 // =======================================================================
679 void OpenGl_PrimitiveArray::Release (OpenGl_Context* theContext)
680 {
681   myIsVboInit = Standard_False;
682   if (!myVboIndices.IsNull())
683   {
684     if (theContext)
685     {
686       theContext->DelayedRelease (myVboIndices);
687     }
688     myVboIndices.Nullify();
689   }
690   if (!myVboAttribs.IsNull())
691   {
692     if (theContext)
693     {
694       theContext->DelayedRelease (myVboAttribs);
695     }
696     myVboAttribs.Nullify();
697   }
698 }
699
700 // =======================================================================
701 // function : Render
702 // purpose  :
703 // =======================================================================
704 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
705 {
706   if (myDrawMode == DRAW_MODE_NONE)
707   {
708     return;
709   }
710
711   const OpenGl_AspectFace*   anAspectFace   = theWorkspace->AspectFace   (Standard_True);
712   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->AspectLine   (Standard_True);
713   const OpenGl_AspectMarker* anAspectMarker = theWorkspace->AspectMarker (myDrawMode == GL_POINTS);
714
715   // create VBOs on first render call
716   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
717   if (!myIsVboInit)
718   {
719     // compatibility - keep data to draw markers using display lists
720     const Standard_Boolean toKeepData = myDrawMode == GL_POINTS
721                                     && !anAspectMarker->SpriteRes (aCtx).IsNull()
722                                     &&  anAspectMarker->SpriteRes (aCtx)->IsDisplayList();
723     buildVBO (aCtx, toKeepData);
724     myIsVboInit = Standard_True;
725   }
726
727   Tint aFrontLightingModel = anAspectFace->IntFront().color_mask;
728   const TEL_COLOUR* anInteriorColor = &anAspectFace->IntFront().matcol;
729   const TEL_COLOUR* anEdgeColor = &anAspectFace->AspectEdge()->Color();
730   const TEL_COLOUR* aLineColor  = myDrawMode == GL_POINTS ? &anAspectMarker->Color() : &anAspectLine->Color();
731
732   // Use highlight colors
733   if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
734   {
735     anEdgeColor = anInteriorColor = aLineColor = theWorkspace->HighlightColor;
736     aFrontLightingModel = 0;
737   }
738
739   const Standard_Boolean hasColorAttrib = !myVboAttribs.IsNull()
740                                         && myVboAttribs->HasColorAttribute();
741   const Standard_Boolean isLightOn = aFrontLightingModel != 0
742                                  && !myVboAttribs.IsNull()
743                                  &&  myVboAttribs->HasNormalAttribute();
744 #if !defined(GL_ES_VERSION_2_0)
745   // manage FFP lighting
746   if (!isLightOn)
747   {
748     glDisable (GL_LIGHTING);
749   }
750   else
751   {
752     glEnable (GL_LIGHTING);
753   }
754 #endif
755   // Temporarily disable environment mapping
756   Handle(OpenGl_Texture) aTextureBack;
757   if (myDrawMode <= GL_LINE_STRIP)
758   {
759     aTextureBack = theWorkspace->DisableTexture();
760   }
761
762   if ((myDrawMode >  GL_LINE_STRIP && anAspectFace->InteriorStyle() != Aspect_IS_EMPTY) ||
763       (myDrawMode <= GL_LINE_STRIP))
764   {
765     const bool            toHilight   = (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT) != 0;
766     const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->InteriorStyle() != Aspect_IS_HIDDENLINE
767                                       ?  myBounds->Colors
768                                       :  NULL;
769     const Standard_Boolean hasVertColor = hasColorAttrib && !toHilight;
770     if (aCtx->IsGlGreaterEqual (2, 0))
771     {
772       switch (myDrawMode)
773       {
774         case GL_POINTS:
775         {
776           const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (aCtx);
777           if (!aSpriteNorm.IsNull()
778            && !aSpriteNorm->IsDisplayList())
779           {
780             const Handle(OpenGl_PointSprite)& aSprite = (toHilight && anAspectMarker->SpriteHighlightRes (aCtx)->IsValid())
781                                                       ? anAspectMarker->SpriteHighlightRes (aCtx)
782                                                       : aSpriteNorm;
783             theWorkspace->EnableTexture (aSprite);
784             aCtx->ShaderManager()->BindProgram (anAspectMarker, aSprite, isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
785           }
786           else
787           {
788             aCtx->ShaderManager()->BindProgram (anAspectMarker, NULL, isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
789           }
790           break;
791         }
792         case GL_LINES:
793         case GL_LINE_STRIP:
794         {
795           aCtx->ShaderManager()->BindProgram (anAspectLine, NULL, isLightOn, hasVertColor, anAspectLine->ShaderProgramRes (aCtx));
796           break;
797         }
798         default:
799         {
800           const Standard_Boolean isLightOnFace = isLightOn
801                                               && (theWorkspace->ActiveTexture().IsNull()
802                                                || theWorkspace->ActiveTexture()->GetParams()->IsModulate());
803           aCtx->ShaderManager()->BindProgram (anAspectFace, theWorkspace->ActiveTexture(), isLightOnFace, hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
804           break;
805         }
806       }
807     }
808
809     aCtx->SetColor4fv (*(const OpenGl_Vec4* )(myDrawMode <= GL_LINE_STRIP ? aLineColor->rgb : anInteriorColor->rgb));
810
811     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
812   }
813
814   if (myDrawMode <= GL_LINE_STRIP)
815   {
816     theWorkspace->EnableTexture (aTextureBack);
817   }
818   else
819   {
820     if (anAspectFace->Edge()
821      || anAspectFace->InteriorStyle() == Aspect_IS_HIDDENLINE)
822     {
823       drawEdges (anEdgeColor, theWorkspace);
824     }
825   }
826
827   aCtx->BindProgram (NULL);
828 }