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