c943f915880a99763ac5c060c4fb627d03757c70
[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_Aspects.hxx>
17 #include <OpenGl_Context.hxx>
18 #include <OpenGl_GraphicDriver.hxx>
19 #include <OpenGl_IndexBuffer.hxx>
20 #include <OpenGl_PointSprite.hxx>
21 #include <OpenGl_PrimitiveArray.hxx>
22 #include <OpenGl_Sampler.hxx>
23 #include <OpenGl_ShaderManager.hxx>
24 #include <OpenGl_ShaderProgram.hxx>
25 #include <OpenGl_Structure.hxx>
26 #include <OpenGl_VertexBufferCompat.hxx>
27 #include <OpenGl_View.hxx>
28 #include <OpenGl_Workspace.hxx>
29 #include <Graphic3d_TextureParams.hxx>
30 #include <NCollection_AlignedAllocator.hxx>
31
32 namespace
33 {
34   //! Convert data type to GL info
35   inline GLenum toGlDataType (const Graphic3d_TypeOfData theType,
36                               GLint&                     theNbComp)
37   {
38     switch (theType)
39     {
40       case Graphic3d_TOD_USHORT:
41         theNbComp = 1;
42         return GL_UNSIGNED_SHORT;
43       case Graphic3d_TOD_UINT:
44         theNbComp = 1;
45         return GL_UNSIGNED_INT;
46       case Graphic3d_TOD_VEC2:
47         theNbComp = 2;
48         return GL_FLOAT;
49       case Graphic3d_TOD_VEC3:
50         theNbComp = 3;
51         return GL_FLOAT;
52       case Graphic3d_TOD_VEC4:
53         theNbComp = 4;
54         return GL_FLOAT;
55       case Graphic3d_TOD_VEC4UB:
56         theNbComp = 4;
57         return GL_UNSIGNED_BYTE;
58       case Graphic3d_TOD_FLOAT:
59         theNbComp = 1;
60         return GL_FLOAT;
61     }
62     theNbComp = 0;
63     return GL_NONE;
64   }
65
66 }
67
68 //! Auxiliary template for VBO with interleaved attributes.
69 template<class TheBaseClass, int NbAttributes>
70 class OpenGl_VertexBufferT : public TheBaseClass
71 {
72 public:
73
74   //! Create uninitialized VBO.
75   OpenGl_VertexBufferT (const Graphic3d_Buffer& theAttribs)
76   : Stride (theAttribs.IsInterleaved() ? theAttribs.Stride : 0)
77   {
78     memcpy (Attribs, theAttribs.AttributesArray(), sizeof(Graphic3d_Attribute) * NbAttributes);
79   }
80
81   virtual bool HasColorAttribute() const
82   {
83     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
84     {
85       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
86       if (anAttrib.Id == Graphic3d_TOA_COLOR)
87       {
88         return true;
89       }
90     }
91     return false;
92   }
93
94   virtual bool HasNormalAttribute() const
95   {
96     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
97     {
98       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
99       if (anAttrib.Id == Graphic3d_TOA_NORM)
100       {
101         return true;
102       }
103     }
104     return false;
105   }
106
107   virtual void BindPositionAttribute (const Handle(OpenGl_Context)& theGlCtx) const
108   {
109     if (!TheBaseClass::IsValid())
110     {
111       return;
112     }
113
114     TheBaseClass::Bind (theGlCtx);
115     GLint aNbComp;
116     const GLubyte* anOffset = TheBaseClass::myOffset;
117     const Standard_Size aMuliplier = Stride != 0 ? 1 : TheBaseClass::myElemsNb;
118     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
119     {
120       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
121       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
122       if (anAttrib.Id == Graphic3d_TOA_POS
123        && aDataType != GL_NONE)
124       {
125         TheBaseClass::bindAttribute (theGlCtx, Graphic3d_TOA_POS, aNbComp, aDataType, Stride, anOffset);
126         break;
127       }
128
129       anOffset += aMuliplier * Graphic3d_Attribute::Stride (anAttrib.DataType);
130     }
131   }
132
133   virtual void BindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
134   {
135     if (!TheBaseClass::IsValid())
136     {
137       return;
138     }
139
140     TheBaseClass::Bind (theGlCtx);
141     GLint aNbComp;
142     const GLubyte* anOffset = TheBaseClass::myOffset;
143     const Standard_Size aMuliplier = Stride != 0 ? 1 : TheBaseClass::myElemsNb;
144     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
145     {
146       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
147       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
148       if (aDataType != GL_NONE)
149       {
150         TheBaseClass::bindAttribute (theGlCtx, anAttrib.Id, aNbComp, aDataType, Stride, anOffset);
151       }
152       anOffset += aMuliplier * Graphic3d_Attribute::Stride (anAttrib.DataType);
153     }
154   }
155
156   virtual void UnbindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
157   {
158     if (!TheBaseClass::IsValid())
159     {
160       return;
161     }
162     TheBaseClass::Unbind (theGlCtx);
163
164     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
165     {
166       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
167       TheBaseClass::unbindAttribute (theGlCtx, anAttrib.Id);
168     }
169   }
170
171 private:
172
173   Graphic3d_Attribute Attribs[NbAttributes];
174   Standard_Integer    Stride;
175
176 };
177
178 // =======================================================================
179 // function : clearMemoryGL
180 // purpose  :
181 // =======================================================================
182 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
183 {
184   if (!myVboIndices.IsNull())
185   {
186     myVboIndices->Release (theGlCtx.operator->());
187     myVboIndices.Nullify();
188   }
189   if (!myVboAttribs.IsNull())
190   {
191     myVboAttribs->Release (theGlCtx.operator->());
192     myVboAttribs.Nullify();
193   }
194 }
195
196 // =======================================================================
197 // function : initNormalVbo
198 // purpose  :
199 // =======================================================================
200 Standard_Boolean OpenGl_PrimitiveArray::initNormalVbo (const Handle(OpenGl_Context)& theCtx) const
201 {
202   switch (myAttribs->NbAttributes)
203   {
204     case 1:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 1> (*myAttribs); break;
205     case 2:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 2> (*myAttribs); break;
206     case 3:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 3> (*myAttribs); break;
207     case 4:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 4> (*myAttribs); break;
208     case 5:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 5> (*myAttribs); break;
209     case 6:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 6> (*myAttribs); break;
210     case 7:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 7> (*myAttribs); break;
211     case 8:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 8> (*myAttribs); break;
212     case 9:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 9> (*myAttribs); break;
213     case 10: myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 10>(*myAttribs); break;
214   }
215
216   const Standard_Boolean isAttribMutable     = myAttribs->IsMutable();
217   const Standard_Boolean isAttribInterleaved = myAttribs->IsInterleaved();
218   if (myAttribs->NbElements != myAttribs->NbMaxElements()
219    && myIndices.IsNull()
220    && (!isAttribInterleaved || isAttribMutable))
221   {
222     throw Standard_ProgramError ("OpenGl_PrimitiveArray::buildVBO() - vertex attribute data with reserved size is not supported");
223   }
224
225   // specify data type as Byte and NbComponents as Stride, so that OpenGl_VertexBuffer::EstimatedDataSize() will return correct value
226   const Standard_Integer aNbVertexes = (isAttribMutable || !isAttribInterleaved) ? myAttribs->NbMaxElements() : myAttribs->NbElements;
227   if (!myVboAttribs->init (theCtx, myAttribs->Stride, aNbVertexes, myAttribs->Data(), GL_UNSIGNED_BYTE, myAttribs->Stride))
228   {
229     TCollection_ExtendedString aMsg = TCollection_ExtendedString("VBO creation for Primitive Array has failed for ") + aNbVertexes + " vertices. Out of memory?";
230     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
231
232     clearMemoryGL (theCtx);
233     return Standard_False;
234   }
235   else if (myIndices.IsNull())
236   {
237     if (isAttribMutable && isAttribInterleaved)
238     {
239       // for mutable interlaced array we can change dynamically number of vertexes (they will be just skipped at the end of buffer);
240       // this doesn't matter in case if we have indexed array
241       myVboAttribs->SetElemsNb (myAttribs->NbElements);
242     }
243     return Standard_True;
244   }
245
246   const Standard_Integer aNbIndexes = !myIndices->IsMutable() ? myIndices->NbElements : myIndices->NbMaxElements();
247   myVboIndices = new OpenGl_IndexBuffer();
248   bool isOk = false;
249   switch (myIndices->Stride)
250   {
251     case 2:
252     {
253       isOk = myVboIndices->Init (theCtx, 1, aNbIndexes, reinterpret_cast<const GLushort*> (myIndices->Data()));
254       myVboIndices->SetElemsNb (myIndices->NbElements);
255       myIndices->Validate();
256       break;
257     }
258     case 4:
259     {
260       isOk = myVboIndices->Init (theCtx, 1, aNbIndexes, reinterpret_cast<const GLuint*> (myIndices->Data()));
261       myVboIndices->SetElemsNb (myIndices->NbElements);
262       myIndices->Validate();
263       break;
264     }
265     default:
266     {
267       clearMemoryGL (theCtx);
268       return Standard_False;
269     }
270   }
271   if (!isOk)
272   {
273     TCollection_ExtendedString aMsg = TCollection_ExtendedString("VBO creation for Primitive Array has failed for ") + aNbIndexes + " indices. Out of memory?";
274     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
275     clearMemoryGL (theCtx);
276     return Standard_False;
277   }
278   return Standard_True;
279 }
280
281 // =======================================================================
282 // function : buildVBO
283 // purpose  :
284 // =======================================================================
285 Standard_Boolean OpenGl_PrimitiveArray::buildVBO (const Handle(OpenGl_Context)& theCtx,
286                                                   const Standard_Boolean        theToKeepData) const
287 {
288   bool isNormalMode = theCtx->ToUseVbo();
289   clearMemoryGL (theCtx);
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      && !myAttribs->IsMutable())
306     {
307       myIndices.Nullify();
308       myAttribs.Nullify();
309     }
310     else
311     {
312       myAttribs->Validate();
313     }
314     return Standard_True;
315   }
316
317   Handle(OpenGl_VertexBufferCompat) aVboAttribs;
318   switch (myAttribs->NbAttributes)
319   {
320     case 1:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 1> (*myAttribs); break;
321     case 2:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 2> (*myAttribs); break;
322     case 3:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 3> (*myAttribs); break;
323     case 4:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 4> (*myAttribs); break;
324     case 5:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 5> (*myAttribs); break;
325     case 6:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 6> (*myAttribs); break;
326     case 7:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 7> (*myAttribs); break;
327     case 8:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 8> (*myAttribs); break;
328     case 9:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 9> (*myAttribs); break;
329     case 10: aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 10>(*myAttribs); break;
330   }
331   aVboAttribs->initLink (myAttribs, 0, myAttribs->NbElements, GL_NONE);
332   if (!myIndices.IsNull())
333   {
334     Handle(OpenGl_VertexBufferCompat) aVboIndices = new OpenGl_VertexBufferCompat();
335     switch (myIndices->Stride)
336     {
337       case 2:
338       {
339         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_SHORT);
340         break;
341       }
342       case 4:
343       {
344         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_INT);
345         break;
346       }
347       default:
348       {
349         return Standard_False;
350       }
351     }
352     myVboIndices = aVboIndices;
353   }
354   myVboAttribs = aVboAttribs;
355   if (!theCtx->caps->keepArrayData
356    && !theToKeepData)
357   {
358     // does not make sense for compatibility mode
359     //myIndices.Nullify();
360     //myAttribs.Nullify();
361   }
362
363   return Standard_True;
364 }
365
366 // =======================================================================
367 // function : updateVBO
368 // purpose  :
369 // =======================================================================
370 void OpenGl_PrimitiveArray::updateVBO (const Handle(OpenGl_Context)& theCtx) const
371 {
372   if (!myAttribs.IsNull())
373   {
374     Graphic3d_BufferRange aRange = myAttribs->InvalidatedRange();
375     if (!aRange.IsEmpty()
376      &&  myVboAttribs->IsValid()
377      && !myVboAttribs->IsVirtual())
378     {
379       myVboAttribs->Bind (theCtx);
380       theCtx->core15fwd->glBufferSubData (myVboAttribs->GetTarget(),
381                                           aRange.Start,
382                                           aRange.Length,
383                                           myAttribs->Data() + aRange.Start);
384       myVboAttribs->Unbind (theCtx);
385       if (myAttribs->IsInterleaved())
386       {
387         myVboAttribs->SetElemsNb (myAttribs->NbElements);
388       }
389     }
390     myAttribs->Validate();
391   }
392   if (!myIndices.IsNull())
393   {
394     Graphic3d_BufferRange aRange = myIndices->InvalidatedRange();
395     if (!aRange.IsEmpty()
396      &&  myVboIndices->IsValid()
397      && !myVboIndices->IsVirtual())
398     {
399       myVboIndices->Bind (theCtx);
400       theCtx->core15fwd->glBufferSubData (myVboIndices->GetTarget(),
401                                           aRange.Start,
402                                           aRange.Length,
403                                           myIndices->Data() + aRange.Start);
404       myVboIndices->Unbind (theCtx);
405       myVboIndices->SetElemsNb (myIndices->NbElements);
406     }
407     myIndices->Validate();
408   }
409 }
410
411 // =======================================================================
412 // function : drawArray
413 // purpose  :
414 // =======================================================================
415 void OpenGl_PrimitiveArray::drawArray (const Handle(OpenGl_Workspace)& theWorkspace,
416                                        const Graphic3d_Vec4*           theFaceColors,
417                                        const Standard_Boolean          theHasVertColor) const
418 {
419   if (myVboAttribs.IsNull())
420   {
421   #if !defined(GL_ES_VERSION_2_0)
422     if (myDrawMode == GL_POINTS)
423     {
424       // extreme compatibility mode - without sprites but with markers
425       drawMarkers (theWorkspace);
426     }
427   #endif
428     return;
429   }
430
431   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
432   const bool                    toHilight  = theWorkspace->ToHighlight();
433   const GLenum aDrawMode = !aGlContext->ActiveProgram().IsNull()
434                          && aGlContext->ActiveProgram()->HasTessellationStage()
435                          ? GL_PATCHES
436                          : myDrawMode;
437   myVboAttribs->BindAllAttributes (aGlContext);
438   if (theHasVertColor && toHilight)
439   {
440     // disable per-vertex color
441     OpenGl_VertexBuffer::unbindAttribute (aGlContext, Graphic3d_TOA_COLOR);
442   }
443   if (!myVboIndices.IsNull())
444   {
445     myVboIndices->Bind (aGlContext);
446     GLubyte* anOffset = myVboIndices->GetDataOffset();
447     if (!myBounds.IsNull())
448     {
449       // draw primitives by vertex count with the indices
450       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
451       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
452       {
453         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
454         if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
455         glDrawElements (aDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
456         anOffset += aStride * aNbElemsInGroup;
457       }
458     }
459     else
460     {
461       // draw one (or sequential) primitive by the indices
462       glDrawElements (aDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
463     }
464     myVboIndices->Unbind (aGlContext);
465   }
466   else if (!myBounds.IsNull())
467   {
468     GLint aFirstElem = 0;
469     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
470     {
471       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
472       if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
473       glDrawArrays (aDrawMode, aFirstElem, aNbElemsInGroup);
474       aFirstElem += aNbElemsInGroup;
475     }
476   }
477   else
478   {
479     if (myDrawMode == GL_POINTS)
480     {
481       drawMarkers (theWorkspace);
482     }
483     else
484     {
485       glDrawArrays (aDrawMode, 0, myVboAttribs->GetElemsNb());
486     }
487   }
488
489   // bind with 0
490   myVboAttribs->UnbindAllAttributes (aGlContext);
491 }
492
493 // =======================================================================
494 // function : drawEdges
495 // purpose  :
496 // =======================================================================
497 void OpenGl_PrimitiveArray::drawEdges (const Handle(OpenGl_Workspace)& theWorkspace) const
498 {
499   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
500   if (myVboAttribs.IsNull())
501   {
502     return;
503   }
504
505   const OpenGl_Aspects* anAspect = theWorkspace->Aspects();
506 #if !defined(GL_ES_VERSION_2_0)
507   const Standard_Integer aPolyModeOld = aGlContext->SetPolygonMode (GL_LINE);
508 #endif
509
510   if (aGlContext->core20fwd != NULL)
511   {
512     aGlContext->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), anAspect->Aspect()->EdgeLineType(),
513                                                   Graphic3d_TOSM_UNLIT, Graphic3d_AlphaMode_Opaque, Standard_False,
514                                                   anAspect->ShaderProgramRes (aGlContext));
515   }
516   aGlContext->SetSampleAlphaToCoverage (aGlContext->ShaderManager()->MaterialState().HasAlphaCutoff());
517   const GLenum aDrawMode = !aGlContext->ActiveProgram().IsNull()
518                          && aGlContext->ActiveProgram()->HasTessellationStage()
519                          ? GL_PATCHES
520                          : myDrawMode;
521 #if !defined(GL_ES_VERSION_2_0)
522   if (aGlContext->ActiveProgram().IsNull()
523    && aGlContext->core11 != NULL)
524   {
525     glDisable (GL_LIGHTING);
526   }
527 #endif
528
529   /// OCC22236 NOTE: draw edges for all situations:
530   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indices array
531   /// 2) draw elements from vertex array, when bounds defines count of primitive's vertices.
532   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
533   myVboAttribs->BindPositionAttribute (aGlContext);
534
535   aGlContext->SetColor4fv (theWorkspace->EdgeColor().a() >= 0.1f
536                          ? theWorkspace->EdgeColor()
537                          : theWorkspace->View()->BackgroundColor());
538   aGlContext->SetLineStipple((float )anAspect->Aspect()->LineStippleFactor(), anAspect->Aspect()->LinePattern());
539   aGlContext->SetLineWidth  (anAspect->Aspect()->EdgeWidth());
540
541   if (!myVboIndices.IsNull())
542   {
543     myVboIndices->Bind (aGlContext);
544     GLubyte* anOffset = myVboIndices->GetDataOffset();
545
546     // draw primitives by vertex count with the indices
547     if (!myBounds.IsNull())
548     {
549       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
550       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
551       {
552         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
553         glDrawElements (aDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
554         anOffset += aStride * aNbElemsInGroup;
555       }
556     }
557     // draw one (or sequential) primitive by the indices
558     else
559     {
560       glDrawElements (aDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
561     }
562     myVboIndices->Unbind (aGlContext);
563   }
564   else if (!myBounds.IsNull())
565   {
566     GLint aFirstElem = 0;
567     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
568     {
569       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
570       glDrawArrays (aDrawMode, aFirstElem, aNbElemsInGroup);
571       aFirstElem += aNbElemsInGroup;
572     }
573   }
574   else
575   {
576     glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
577   }
578
579   // unbind buffers
580   myVboAttribs->UnbindAttribute (aGlContext, Graphic3d_TOA_POS);
581
582   // restore line context
583 #if !defined(GL_ES_VERSION_2_0)
584   aGlContext->SetPolygonMode (aPolyModeOld);
585 #endif
586 }
587
588 // =======================================================================
589 // function : drawMarkers
590 // purpose  :
591 // =======================================================================
592 void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
593 {
594   const OpenGl_Aspects* anAspectMarker = theWorkspace->Aspects();
595   const Handle(OpenGl_Context)&   aCtx = theWorkspace->GetGlContext();
596   const GLenum aDrawMode = !aCtx->ActiveProgram().IsNull()
597                          && aCtx->ActiveProgram()->HasTessellationStage()
598                          ? GL_PATCHES
599                          : myDrawMode;
600   if (anAspectMarker->HasPointSprite (aCtx))
601   {
602     // Textured markers will be drawn with the point sprites
603     aCtx->SetPointSize (anAspectMarker->MarkerSize());
604     aCtx->SetPointSpriteOrigin();
605   #if !defined(GL_ES_VERSION_2_0)
606     if (aCtx->core11 != NULL)
607     {
608       aCtx->core11fwd->glEnable (GL_ALPHA_TEST);
609       aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, 0.1f);
610     }
611   #endif
612
613     aCtx->core11fwd->glEnable (GL_BLEND);
614     aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
615
616     aCtx->core11fwd->glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
617
618     aCtx->core11fwd->glDisable (GL_BLEND);
619   #if !defined(GL_ES_VERSION_2_0)
620     if (aCtx->core11 != NULL)
621     {
622       if (aCtx->ShaderManager()->MaterialState().AlphaCutoff() >= ShortRealLast())
623       {
624         aCtx->core11fwd->glDisable (GL_ALPHA_TEST);
625       }
626       else
627       {
628         aCtx->core11fwd->glAlphaFunc (GL_GEQUAL, aCtx->ShaderManager()->MaterialState().AlphaCutoff());
629       }
630     }
631   #endif
632     aCtx->SetPointSize (1.0f);
633     return;
634   }
635   else if (anAspectMarker->Aspect()->MarkerType() == Aspect_TOM_POINT)
636   {
637     aCtx->SetPointSize (anAspectMarker->MarkerSize());
638     aCtx->core11fwd->glDrawArrays (aDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
639     aCtx->SetPointSize (1.0f);
640   }
641 #if !defined(GL_ES_VERSION_2_0)
642   // Textured markers will be drawn with the glBitmap
643   else if (anAspectMarker->Aspect()->MarkerType() != Aspect_TOM_POINT)
644   {
645     const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (aCtx, false);
646     if (aSpriteNorm.IsNull())
647     {
648       return;
649     }
650
651     /**if (!isHilight && (myPArray->vcolours != NULL))
652     {
653       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
654       {
655         glColor4ubv    (myPArray->vcolours[anIter].GetData());
656         glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
657         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
658       }
659     }
660     else*/
661     {
662       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
663       {
664         aCtx->core11->glRasterPos3fv (myAttribs->Value<Graphic3d_Vec3> (anIter).GetData());
665         aSpriteNorm->DrawBitmap (theWorkspace->GetGlContext());
666       }
667     }
668   }
669 #endif
670 }
671
672 // =======================================================================
673 // function : OpenGl_PrimitiveArray
674 // purpose  :
675 // =======================================================================
676 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver* theDriver)
677
678 : myDrawMode  (DRAW_MODE_NONE),
679   myIsFillType(Standard_False),
680   myIsVboInit (Standard_False)
681 {
682   if (theDriver != NULL)
683   {
684     myUID = theDriver->GetNextPrimitiveArrayUID();
685   }
686 }
687
688 // =======================================================================
689 // function : OpenGl_PrimitiveArray
690 // purpose  :
691 // =======================================================================
692 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (const OpenGl_GraphicDriver*          theDriver,
693                                               const Graphic3d_TypeOfPrimitiveArray theType,
694                                               const Handle(Graphic3d_IndexBuffer)& theIndices,
695                                               const Handle(Graphic3d_Buffer)&      theAttribs,
696                                               const Handle(Graphic3d_BoundBuffer)& theBounds)
697
698 : myIndices   (theIndices),
699   myAttribs   (theAttribs),
700   myBounds    (theBounds),
701   myDrawMode  (DRAW_MODE_NONE),
702   myIsFillType(Standard_False),
703   myIsVboInit (Standard_False)
704 {
705   if (!myIndices.IsNull()
706     && myIndices->NbElements < 1)
707   {
708     // dummy index buffer?
709     myIndices.Nullify();
710   }
711
712   if (theDriver != NULL)
713   {
714     myUID = theDriver->GetNextPrimitiveArrayUID();
715   #if defined (GL_ES_VERSION_2_0)
716     const Handle(OpenGl_Context)& aCtx = theDriver->GetSharedContext();
717     if (!aCtx.IsNull())
718     {
719       processIndices (aCtx);
720     }
721   #endif
722   }
723
724   setDrawMode (theType);
725 }
726
727 // =======================================================================
728 // function : ~OpenGl_PrimitiveArray
729 // purpose  :
730 // =======================================================================
731 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
732 {
733   //
734 }
735
736 // =======================================================================
737 // function : Release
738 // purpose  :
739 // =======================================================================
740 void OpenGl_PrimitiveArray::Release (OpenGl_Context* theContext)
741 {
742   myIsVboInit = Standard_False;
743   if (!myVboIndices.IsNull())
744   {
745     if (theContext)
746     {
747       theContext->DelayedRelease (myVboIndices);
748     }
749     myVboIndices.Nullify();
750   }
751   if (!myVboAttribs.IsNull())
752   {
753     if (theContext)
754     {
755       theContext->DelayedRelease (myVboAttribs);
756     }
757     myVboAttribs.Nullify();
758   }
759 }
760
761 // =======================================================================
762 // function : EstimatedDataSize
763 // purpose  :
764 // =======================================================================
765 Standard_Size OpenGl_PrimitiveArray::EstimatedDataSize() const
766 {
767   Standard_Size aSize = 0;
768   if (!myVboAttribs.IsNull())
769   {
770     aSize += myVboAttribs->EstimatedDataSize();
771   }
772   if (!myVboIndices.IsNull())
773   {
774     aSize += myVboIndices->EstimatedDataSize();
775   }
776   return aSize;
777 }
778
779 // =======================================================================
780 // function : UpdateDrawStats
781 // purpose  :
782 // =======================================================================
783 void OpenGl_PrimitiveArray::UpdateDrawStats (Graphic3d_FrameStatsDataTmp& theStats,
784                                              bool theIsDetailed) const
785 {
786   ++theStats[Graphic3d_FrameStatsCounter_NbElemsNotCulled];
787   if (myIsFillType)
788   {
789     ++theStats[Graphic3d_FrameStatsCounter_NbElemsFillNotCulled];
790   }
791   else if (myDrawMode == GL_POINTS)
792   {
793     ++theStats[Graphic3d_FrameStatsCounter_NbElemsPointNotCulled];
794   }
795   else
796   {
797     ++theStats[Graphic3d_FrameStatsCounter_NbElemsLineNotCulled];
798   }
799
800   if (!theIsDetailed
801   ||  myVboAttribs.IsNull()
802   || !myVboAttribs->IsValid())
803   {
804     return;
805   }
806
807   const Standard_Integer aNbIndices = !myVboIndices.IsNull() ? myVboIndices->GetElemsNb() : myVboAttribs->GetElemsNb();
808   const Standard_Integer aNbBounds  = !myBounds.IsNull() ? myBounds->NbBounds : 1;
809   switch (myDrawMode)
810   {
811     case GL_POINTS:
812     {
813       theStats[Graphic3d_FrameStatsCounter_NbPointsNotCulled] += aNbIndices;
814       break;
815     }
816     case GL_LINES:
817     {
818       theStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled] += aNbIndices / 2;
819       break;
820     }
821     case GL_LINE_STRIP:
822     {
823       theStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled] += aNbIndices - aNbBounds;
824       break;
825     }
826     case GL_LINES_ADJACENCY:
827     {
828       theStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled] += aNbIndices / 4;
829       break;
830     }
831     case GL_LINE_STRIP_ADJACENCY:
832     {
833       theStats[Graphic3d_FrameStatsCounter_NbLinesNotCulled] += aNbIndices - 4 * aNbBounds;
834       break;
835     }
836     case GL_TRIANGLES:
837     {
838       theStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 3;
839       break;
840     }
841     case GL_TRIANGLE_STRIP:
842     case GL_TRIANGLE_FAN:
843     {
844       theStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices - 2 * aNbBounds;
845       break;
846     }
847     case GL_TRIANGLES_ADJACENCY:
848     {
849       theStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 6;
850       break;
851     }
852     case GL_TRIANGLE_STRIP_ADJACENCY:
853     {
854       theStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices - 4 * aNbBounds;
855       break;
856     }
857   #if !defined(GL_ES_VERSION_2_0)
858     case GL_QUADS:
859     {
860       theStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += aNbIndices / 2;
861       break;
862     }
863     case GL_QUAD_STRIP:
864     {
865       theStats[Graphic3d_FrameStatsCounter_NbTrianglesNotCulled] += (aNbIndices / 2 - aNbBounds) * 2;
866       break;
867     }
868   #endif
869   }
870 }
871
872 // =======================================================================
873 // function : Render
874 // purpose  :
875 // =======================================================================
876 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
877 {
878   if (myDrawMode == DRAW_MODE_NONE)
879   {
880     return;
881   }
882
883   const OpenGl_Aspects* anAspectFace = theWorkspace->Aspects();
884   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
885
886   bool toDrawArray = true, toSetLinePolygMode = false;
887   int toDrawInteriorEdges = 0; // 0 - no edges, 1 - glsl edges, 2 - polygonMode
888   if (myIsFillType)
889   {
890     toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY;
891     if (anAspectFace->Aspect()->ToDrawEdges())
892     {
893       toDrawInteriorEdges = 1;
894       toDrawArray = true;
895     #if !defined(GL_ES_VERSION_2_0)
896       if (anAspectFace->Aspect()->EdgeLineType() != Aspect_TOL_SOLID
897        || aCtx->hasGeometryStage == OpenGl_FeatureNotAvailable
898        || aCtx->caps->usePolygonMode)
899       {
900         toDrawInteriorEdges = 2;
901         if (anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_EMPTY)
902         {
903           if (anAspectFace->Aspect()->EdgeLineType() != Aspect_TOL_SOLID)
904           {
905             toDrawArray = false;
906           }
907           else
908           {
909             toSetLinePolygMode = true;
910           }
911         }
912       }
913     #endif
914     }
915   }
916   else
917   {
918     if (myDrawMode == GL_POINTS)
919     {
920       if (anAspectFace->Aspect()->MarkerType() == Aspect_TOM_EMPTY)
921       {
922         return;
923       }
924     }
925     else
926     {
927       if (anAspectFace->Aspect()->LineType() == Aspect_TOL_EMPTY)
928       {
929         return;
930       }
931     }
932   }
933
934   // create VBOs on first render call
935   if (!myIsVboInit)
936   {
937     // compatibility - keep data to draw markers using display lists
938     Standard_Boolean toKeepData = myDrawMode == GL_POINTS
939                                && anAspectFace->IsDisplayListSprite (aCtx);
940   #if defined (GL_ES_VERSION_2_0)
941     processIndices (aCtx);
942   #endif
943     buildVBO (aCtx, toKeepData);
944     myIsVboInit = Standard_True;
945   }
946   else if ((!myAttribs.IsNull()
947          &&  myAttribs->IsMutable())
948         || (!myIndices.IsNull()
949          &&  myIndices->IsMutable()))
950   {
951     updateVBO (aCtx);
952   }
953
954   Graphic3d_TypeOfShadingModel aShadingModel = Graphic3d_TOSM_UNLIT;
955   anAspectFace = theWorkspace->ApplyAspects (false); // do not bind textures before binding the program
956   const Handle(OpenGl_TextureSet)& aTextureSet = theWorkspace->TextureSet();
957   const bool toEnableEnvMap = !aTextureSet.IsNull()
958                             && aTextureSet == theWorkspace->EnvironmentTexture();
959   if (toDrawArray)
960   {
961     const bool hasColorAttrib = !myVboAttribs.IsNull()
962                               && myVboAttribs->HasColorAttribute();
963     const bool toHilight    = theWorkspace->ToHighlight();
964     const bool hasVertColor = hasColorAttrib && !toHilight;
965     const bool hasVertNorm  = !myVboAttribs.IsNull() && myVboAttribs->HasNormalAttribute();
966     switch (myDrawMode)
967     {
968       case GL_POINTS:
969       {
970         aShadingModel = aCtx->ShaderManager()->ChooseMarkerShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
971         aCtx->ShaderManager()->BindMarkerProgram (aTextureSet,
972                                                   aShadingModel, Graphic3d_AlphaMode_Opaque,
973                                                   hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
974         break;
975       }
976       case GL_LINES:
977       case GL_LINE_STRIP:
978       {
979         aShadingModel = aCtx->ShaderManager()->ChooseLineShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
980         aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(),
981                                                 anAspectFace->Aspect()->LineType(),
982                                                 aShadingModel,
983                                                 Graphic3d_AlphaMode_Opaque,
984                                                 hasVertColor,
985                                                 anAspectFace->ShaderProgramRes (aCtx));
986         break;
987       }
988       default:
989       {
990         aShadingModel = aCtx->ShaderManager()->ChooseFaceShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
991         aCtx->ShaderManager()->BindFaceProgram (aTextureSet,
992                                                 aShadingModel,
993                                                 aCtx->ShaderManager()->MaterialState().HasAlphaCutoff() ? Graphic3d_AlphaMode_Mask : Graphic3d_AlphaMode_Opaque,
994                                                 toDrawInteriorEdges == 1 ? anAspectFace->Aspect()->InteriorStyle() : Aspect_IS_SOLID,
995                                                 hasVertColor,
996                                                 toEnableEnvMap,
997                                                 toDrawInteriorEdges == 1,
998                                                 anAspectFace->ShaderProgramRes (aCtx));
999         if (toDrawInteriorEdges == 1)
1000         {
1001           aCtx->ShaderManager()->PushInteriorState (aCtx->ActiveProgram(), anAspectFace->Aspect());
1002         }
1003       #if !defined (GL_ES_VERSION_2_0)
1004         else if (toSetLinePolygMode)
1005         {
1006           aCtx->SetPolygonMode (GL_LINE);
1007         }
1008       #else
1009         (void )toSetLinePolygMode;
1010       #endif
1011         break;
1012       }
1013     }
1014
1015     // bind textures after GLSL program to set mock textures to slots used by program
1016     aCtx->BindTextures (aTextureSet, aCtx->ActiveProgram());
1017     if (!aTextureSet.IsNull()
1018      && !aTextureSet->IsEmpty()
1019      && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
1020     {
1021       if (const Handle(OpenGl_Texture)& aFirstTexture = aTextureSet->First())
1022       {
1023         aCtx->SetTextureMatrix (aFirstTexture->Sampler()->Parameters(), aFirstTexture->IsTopDown());
1024       }
1025     }
1026     aCtx->SetSampleAlphaToCoverage (aCtx->ShaderManager()->MaterialState().HasAlphaCutoff());
1027
1028     const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
1029                                       ?  myBounds->Colors
1030                                       :  NULL;
1031     const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
1032     aCtx->SetColor4fv (anInteriorColor);
1033     if (!myIsFillType)
1034     {
1035       if (myDrawMode == GL_LINES
1036        || myDrawMode == GL_LINE_STRIP)
1037       {
1038         aCtx->SetLineStipple((float )anAspectFace->Aspect()->LineStippleFactor(), anAspectFace->Aspect()->LinePattern());
1039         aCtx->SetLineWidth  (anAspectFace->Aspect()->LineWidth());
1040       }
1041
1042       drawArray (theWorkspace, aFaceColors, hasColorAttrib);
1043       return;
1044     }
1045
1046     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
1047
1048     // draw outline - only closed triangulation with defined vertex normals can be drawn in this way
1049     if (anAspectFace->Aspect()->ToDrawSilhouette()
1050      && aCtx->ToCullBackFaces()
1051      && aCtx->ShaderManager()->BindOutlineProgram())
1052     {
1053       const Graphic3d_Vec2i aViewSize (aCtx->Viewport()[2], aCtx->Viewport()[3]);
1054       const Standard_Integer aMin = aViewSize.minComp();
1055       const GLfloat anEdgeWidth  = (GLfloat )anAspectFace->Aspect()->EdgeWidth() * aCtx->LineWidthScale() / (GLfloat )aMin;
1056       const GLfloat anOrthoScale = theWorkspace->View()->Camera()->IsOrthographic() ? (GLfloat )theWorkspace->View()->Camera()->Scale() : -1.0f;
1057
1058       const Handle(OpenGl_ShaderProgram)& anOutlineProgram = aCtx->ActiveProgram();
1059       anOutlineProgram->SetUniform (aCtx, anOutlineProgram->GetStateLocation (OpenGl_OCCT_SILHOUETTE_THICKNESS), anEdgeWidth);
1060       anOutlineProgram->SetUniform (aCtx, anOutlineProgram->GetStateLocation (OpenGl_OCCT_ORTHO_SCALE),          anOrthoScale);
1061       aCtx->SetColor4fv (anAspectFace->Aspect()->EdgeColorRGBA());
1062
1063       aCtx->core11fwd->glCullFace (GL_FRONT);
1064       drawArray (theWorkspace, NULL, false);
1065
1066       aCtx->core11fwd->glCullFace (GL_BACK);
1067     }
1068   }
1069
1070 #if !defined(GL_ES_VERSION_2_0)
1071   // draw triangulation edges using Polygon Mode
1072   if (toDrawInteriorEdges == 2)
1073   {
1074     if (anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_HOLLOW
1075      && anAspectFace->Aspect()->EdgeLineType()  == Aspect_TOL_SOLID)
1076     {
1077       aCtx->SetPolygonMode (GL_FILL);
1078     }
1079     else
1080     {
1081       drawEdges (theWorkspace);
1082     }
1083   }
1084 #endif
1085 }
1086
1087 // =======================================================================
1088 // function : setDrawMode
1089 // purpose  :
1090 // =======================================================================
1091 void OpenGl_PrimitiveArray::setDrawMode (const Graphic3d_TypeOfPrimitiveArray theType)
1092 {
1093   if (myAttribs.IsNull())
1094   {
1095     myDrawMode = DRAW_MODE_NONE;
1096     myIsFillType = false;
1097     return;
1098   }
1099
1100   switch (theType)
1101   {
1102     case Graphic3d_TOPA_POINTS:
1103       myDrawMode   = GL_POINTS;
1104       myIsFillType = false;
1105       break;
1106     case Graphic3d_TOPA_SEGMENTS:
1107       myDrawMode   = GL_LINES;
1108       myIsFillType = false;
1109       break;
1110     case Graphic3d_TOPA_POLYLINES:
1111       myDrawMode   = GL_LINE_STRIP;
1112       myIsFillType = false;
1113       break;
1114     case Graphic3d_TOPA_TRIANGLES:
1115       myDrawMode   = GL_TRIANGLES;
1116       myIsFillType = true;
1117       break;
1118     case Graphic3d_TOPA_TRIANGLESTRIPS:
1119       myDrawMode   = GL_TRIANGLE_STRIP;
1120       myIsFillType = true;
1121       break;
1122     case Graphic3d_TOPA_TRIANGLEFANS:
1123       myDrawMode   = GL_TRIANGLE_FAN;
1124       myIsFillType = true;
1125       break;
1126     //
1127     case Graphic3d_TOPA_LINES_ADJACENCY:
1128       myDrawMode = GL_LINES_ADJACENCY;
1129       myIsFillType = false;
1130       break;
1131     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:
1132       myDrawMode   = GL_LINE_STRIP_ADJACENCY;
1133       myIsFillType = false;
1134       break;
1135     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:
1136       myDrawMode   = GL_TRIANGLES_ADJACENCY;
1137       myIsFillType = true;
1138       break;
1139     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY:
1140       myDrawMode   = GL_TRIANGLE_STRIP_ADJACENCY;
1141       myIsFillType = true;
1142       break;
1143     //
1144   #if !defined(GL_ES_VERSION_2_0)
1145     case Graphic3d_TOPA_QUADRANGLES:
1146       myDrawMode   = GL_QUADS;
1147       myIsFillType = true;
1148       break;
1149     case Graphic3d_TOPA_QUADRANGLESTRIPS:
1150       myDrawMode   = GL_QUAD_STRIP;
1151       myIsFillType = true;
1152       break;
1153     case Graphic3d_TOPA_POLYGONS:
1154       myDrawMode   = GL_POLYGON;
1155       myIsFillType = true;
1156       break;
1157   #else
1158     case Graphic3d_TOPA_QUADRANGLES:
1159     case Graphic3d_TOPA_QUADRANGLESTRIPS:
1160     case Graphic3d_TOPA_POLYGONS:
1161   #endif
1162     case Graphic3d_TOPA_UNDEFINED:
1163       myDrawMode   = DRAW_MODE_NONE;
1164       myIsFillType = false;
1165       break;
1166   }
1167 }
1168
1169 // =======================================================================
1170 // function : processIndices
1171 // purpose  :
1172 // =======================================================================
1173 Standard_Boolean OpenGl_PrimitiveArray::processIndices (const Handle(OpenGl_Context)& theContext) const
1174 {
1175   if (myIndices.IsNull()
1176    || myAttribs.IsNull()
1177    || theContext->hasUintIndex)
1178   {
1179     return Standard_True;
1180   }
1181
1182   if (myAttribs->NbElements > std::numeric_limits<GLushort>::max())
1183   {
1184     Handle(Graphic3d_Buffer) anAttribs = new Graphic3d_Buffer (new NCollection_AlignedAllocator (16));
1185     if (!anAttribs->Init (myIndices->NbElements, myAttribs->AttributesArray(), myAttribs->NbAttributes))
1186     {
1187       return Standard_False; // failed to initialize attribute array
1188     }
1189
1190     for (Standard_Integer anIdxIdx = 0; anIdxIdx < myIndices->NbElements; ++anIdxIdx)
1191     {
1192       const Standard_Integer anIndex = myIndices->Index (anIdxIdx);
1193       memcpy (anAttribs->ChangeData() + myAttribs->Stride * anIdxIdx,
1194               myAttribs->Data()       + myAttribs->Stride * anIndex,
1195               myAttribs->Stride);
1196     }
1197
1198     myIndices.Nullify();
1199     myAttribs = anAttribs;
1200   }
1201
1202   return Standard_True;
1203 }
1204
1205 // =======================================================================
1206 // function : InitBuffers
1207 // purpose  :
1208 // =======================================================================
1209 void OpenGl_PrimitiveArray::InitBuffers (const Handle(OpenGl_Context)&        theContext,
1210                                          const Graphic3d_TypeOfPrimitiveArray theType,
1211                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
1212                                          const Handle(Graphic3d_Buffer)&      theAttribs,
1213                                          const Handle(Graphic3d_BoundBuffer)& theBounds)
1214 {
1215   // Release old graphic resources
1216   Release (theContext.get());
1217
1218   myIndices = theIndices;
1219   myAttribs = theAttribs;
1220   myBounds = theBounds;
1221 #if defined(GL_ES_VERSION_2_0)
1222   processIndices (theContext);
1223 #endif
1224
1225   setDrawMode (theType);
1226 }
1227
1228 // =======================================================================
1229 // function : DumpJson
1230 // purpose  :
1231 // =======================================================================
1232 void OpenGl_PrimitiveArray::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1233 {
1234   OCCT_DUMP_CLASS_BEGIN (theOStream, OpenGl_PrimitiveArray)
1235
1236   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, OpenGl_Element)
1237
1238   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myVboIndices.get())
1239   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myVboAttribs.get())
1240
1241   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myIndices.get())
1242   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myAttribs.get())
1243   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myBounds.get())
1244
1245   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDrawMode)
1246   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsFillType)
1247   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsVboInit)
1248   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myUID)
1249 }