0028276: Visualization, Graphic3d_ArrayOfPrimitives - fix usage of 16-bit indices
[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       case Graphic3d_TOD_FLOAT:
57         theNbComp = 1;
58         return GL_FLOAT;
59     }
60     theNbComp = 0;
61     return GL_NONE;
62   }
63
64 }
65
66 //! Auxiliary template for VBO with interleaved attributes.
67 template<class TheBaseClass, int NbAttributes>
68 class OpenGl_VertexBufferT : public TheBaseClass
69 {
70
71 public:
72
73   //! Create uninitialized VBO.
74   OpenGl_VertexBufferT (const Graphic3d_Attribute* theAttribs,
75                         const Standard_Integer     theStride)
76   : Stride (theStride)
77   {
78     memcpy (Attribs, theAttribs, sizeof(Graphic3d_Attribute) * NbAttributes);
79   }
80
81   //! Create uninitialized VBO.
82   OpenGl_VertexBufferT (const Graphic3d_Buffer& theAttribs)
83   : Stride (theAttribs.Stride)
84   {
85     memcpy (Attribs, theAttribs.AttributesArray(), sizeof(Graphic3d_Attribute) * NbAttributes);
86   }
87
88   virtual bool HasColorAttribute() const
89   {
90     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
91     {
92       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
93       if (anAttrib.Id == Graphic3d_TOA_COLOR)
94       {
95         return true;
96       }
97     }
98     return false;
99   }
100
101   virtual bool HasNormalAttribute() const
102   {
103     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
104     {
105       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
106       if (anAttrib.Id == Graphic3d_TOA_NORM)
107       {
108         return true;
109       }
110     }
111     return false;
112   }
113
114   virtual void BindPositionAttribute (const Handle(OpenGl_Context)& theGlCtx) const
115   {
116     if (!TheBaseClass::IsValid())
117     {
118       return;
119     }
120
121     TheBaseClass::Bind (theGlCtx);
122     GLint aNbComp;
123     const GLubyte* anOffset = TheBaseClass::myOffset;
124     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
125     {
126       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
127       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
128       if (aDataType == GL_NONE)
129       {
130         continue;
131       }
132       else if (anAttrib.Id == Graphic3d_TOA_POS)
133       {
134         TheBaseClass::bindAttribute (theGlCtx, Graphic3d_TOA_POS, aNbComp, aDataType, Stride, anOffset);
135         break;
136       }
137
138       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
139     }
140   }
141
142   virtual void BindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
143   {
144     if (!TheBaseClass::IsValid())
145     {
146       return;
147     }
148
149     TheBaseClass::Bind (theGlCtx);
150     GLint aNbComp;
151     const GLubyte* anOffset = TheBaseClass::myOffset;
152     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
153     {
154       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
155       const GLenum   aDataType = toGlDataType (anAttrib.DataType, aNbComp);
156       if (aDataType == GL_NONE)
157       {
158         continue;
159       }
160
161       TheBaseClass::bindAttribute (theGlCtx, anAttrib.Id, aNbComp, aDataType, Stride, anOffset);
162       anOffset += Graphic3d_Attribute::Stride (anAttrib.DataType);
163     }
164   }
165
166   virtual void UnbindAllAttributes (const Handle(OpenGl_Context)& theGlCtx) const
167   {
168     if (!TheBaseClass::IsValid())
169     {
170       return;
171     }
172     TheBaseClass::Unbind (theGlCtx);
173
174     for (Standard_Integer anAttribIter = 0; anAttribIter < NbAttributes; ++anAttribIter)
175     {
176       const Graphic3d_Attribute& anAttrib = Attribs[anAttribIter];
177       TheBaseClass::unbindAttribute (theGlCtx, anAttrib.Id);
178     }
179   }
180
181 public:
182
183   Graphic3d_Attribute Attribs[NbAttributes];
184   Standard_Integer    Stride;
185
186 };
187
188 // =======================================================================
189 // function : clearMemoryGL
190 // purpose  :
191 // =======================================================================
192 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
193 {
194   if (!myVboIndices.IsNull())
195   {
196     myVboIndices->Release (theGlCtx.operator->());
197     myVboIndices.Nullify();
198   }
199   if (!myVboAttribs.IsNull())
200   {
201     myVboAttribs->Release (theGlCtx.operator->());
202     myVboAttribs.Nullify();
203   }
204 }
205
206 // =======================================================================
207 // function : initNormalVbo
208 // purpose  :
209 // =======================================================================
210 Standard_Boolean OpenGl_PrimitiveArray::initNormalVbo (const Handle(OpenGl_Context)& theCtx) const
211 {
212   switch (myAttribs->NbAttributes)
213   {
214     case 1:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 1> (*myAttribs); break;
215     case 2:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 2> (*myAttribs); break;
216     case 3:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 3> (*myAttribs); break;
217     case 4:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 4> (*myAttribs); break;
218     case 5:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 5> (*myAttribs); break;
219     case 6:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 6> (*myAttribs); break;
220     case 7:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 7> (*myAttribs); break;
221     case 8:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 8> (*myAttribs); break;
222     case 9:  myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 9> (*myAttribs); break;
223     case 10: myVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBuffer, 10>(*myAttribs); break;
224   }
225
226   if (!myVboAttribs->init (theCtx, 0, myAttribs->NbElements, myAttribs->Data(), GL_NONE, myAttribs->Stride))
227   {
228     TCollection_ExtendedString aMsg;
229     aMsg += "VBO creation for Primitive Array has failed for ";
230     aMsg += myAttribs->NbElements;
231     aMsg += " vertices. Out of memory?";
232     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
233
234     clearMemoryGL (theCtx);
235     return Standard_False;
236   }
237   else if (myIndices.IsNull())
238   {
239     return Standard_True;
240   }
241
242   myVboIndices = new OpenGl_IndexBuffer();
243   bool isOk = false;
244   switch (myIndices->Stride)
245   {
246     case 2:
247     {
248       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLushort*> (myIndices->Data()));
249       break;
250     }
251     case 4:
252     {
253       isOk = myVboIndices->Init (theCtx, 1, myIndices->NbElements, reinterpret_cast<const GLuint*> (myIndices->Data()));
254       break;
255     }
256     default:
257     {
258       clearMemoryGL (theCtx);
259       return Standard_False;
260     }
261   }
262   if (!isOk)
263   {
264     TCollection_ExtendedString aMsg;
265     aMsg += "VBO creation for Primitive Array has failed for ";
266     aMsg += myIndices->NbElements;
267     aMsg += " indices. Out of memory?";
268     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
269     clearMemoryGL (theCtx);
270     return Standard_False;
271   }
272   return Standard_True;
273 }
274
275 // =======================================================================
276 // function : buildVBO
277 // purpose  :
278 // =======================================================================
279 Standard_Boolean OpenGl_PrimitiveArray::buildVBO (const Handle(OpenGl_Context)& theCtx,
280                                                   const Standard_Boolean        theToKeepData) const
281 {
282   bool isNormalMode = theCtx->ToUseVbo();
283   clearMemoryGL (theCtx);
284   if (myAttribs.IsNull()
285    || myAttribs->IsEmpty()
286    || myAttribs->NbElements < 1
287    || myAttribs->NbAttributes < 1
288    || myAttribs->NbAttributes > 10)
289   {
290     // vertices should be always defined - others are optional
291     return Standard_False;
292   }
293
294   if (isNormalMode
295    && initNormalVbo (theCtx))
296   {
297     if (!theCtx->caps->keepArrayData
298      && !theToKeepData)
299     {
300       myIndices.Nullify();
301       myAttribs.Nullify();
302     }
303     return Standard_True;
304   }
305
306   Handle(OpenGl_VertexBufferCompat) aVboAttribs;
307   switch (myAttribs->NbAttributes)
308   {
309     case 1:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 1> (*myAttribs); break;
310     case 2:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 2> (*myAttribs); break;
311     case 3:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 3> (*myAttribs); break;
312     case 4:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 4> (*myAttribs); break;
313     case 5:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 5> (*myAttribs); break;
314     case 6:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 6> (*myAttribs); break;
315     case 7:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 7> (*myAttribs); break;
316     case 8:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 8> (*myAttribs); break;
317     case 9:  aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 9> (*myAttribs); break;
318     case 10: aVboAttribs = new OpenGl_VertexBufferT<OpenGl_VertexBufferCompat, 10>(*myAttribs); break;
319   }
320   aVboAttribs->initLink (myAttribs, 0, myAttribs->NbElements, GL_NONE);
321   if (!myIndices.IsNull())
322   {
323     Handle(OpenGl_VertexBufferCompat) aVboIndices = new OpenGl_VertexBufferCompat();
324     switch (myIndices->Stride)
325     {
326       case 2:
327       {
328         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_SHORT);
329         break;
330       }
331       case 4:
332       {
333         aVboIndices->initLink (myIndices, 1, myIndices->NbElements, GL_UNSIGNED_INT);
334         break;
335       }
336       default:
337       {
338         return Standard_False;
339       }
340     }
341     myVboIndices = aVboIndices;
342   }
343   myVboAttribs = aVboAttribs;
344   if (!theCtx->caps->keepArrayData
345    && !theToKeepData)
346   {
347     // does not make sense for compatibility mode
348     //myIndices.Nullify();
349     //myAttribs.Nullify();
350   }
351
352   return Standard_True;
353 }
354
355 // =======================================================================
356 // function : drawArray
357 // purpose  :
358 // =======================================================================
359 void OpenGl_PrimitiveArray::drawArray (const Handle(OpenGl_Workspace)& theWorkspace,
360                                        const Graphic3d_Vec4*           theFaceColors,
361                                        const Standard_Boolean          theHasVertColor) const
362 {
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   const Handle(OpenGl_Context)& aGlContext  = theWorkspace->GetGlContext();
376   const bool                    toHilight   = theWorkspace->ToHighlight();
377   myVboAttribs->BindAllAttributes (aGlContext);
378   if (theHasVertColor && toHilight)
379   {
380     // disable per-vertex color
381     OpenGl_VertexBuffer::unbindAttribute (aGlContext, Graphic3d_TOA_COLOR);
382   }
383   if (!myVboIndices.IsNull())
384   {
385     myVboIndices->Bind (aGlContext);
386     GLubyte* anOffset = myVboIndices->GetDataOffset();
387     if (!myBounds.IsNull())
388     {
389       // draw primitives by vertex count with the indices
390       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
391       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
392       {
393         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
394         if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
395         glDrawElements (myDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
396         anOffset += aStride * aNbElemsInGroup;
397       }
398     }
399     else
400     {
401       // draw one (or sequential) primitive by the indices
402       glDrawElements (myDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
403     }
404     myVboIndices->Unbind (aGlContext);
405   }
406   else if (!myBounds.IsNull())
407   {
408     GLint aFirstElem = 0;
409     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
410     {
411       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
412       if (theFaceColors != NULL) aGlContext->SetColor4fv (theFaceColors[aGroupIter]);
413       glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
414       aFirstElem += aNbElemsInGroup;
415     }
416   }
417   else
418   {
419     if (myDrawMode == GL_POINTS)
420     {
421       drawMarkers (theWorkspace);
422     }
423     else
424     {
425       glDrawArrays (myDrawMode, 0, myVboAttribs->GetElemsNb());
426     }
427   }
428
429   // bind with 0
430   myVboAttribs->UnbindAllAttributes (aGlContext);
431 }
432
433 // =======================================================================
434 // function : drawEdges
435 // purpose  :
436 // =======================================================================
437 void OpenGl_PrimitiveArray::drawEdges (const OpenGl_Vec4&              theEdgeColour,
438                                        const Handle(OpenGl_Workspace)& theWorkspace) const
439 {
440   const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
441   if (myVboAttribs.IsNull())
442   {
443     return;
444   }
445
446 #if !defined(GL_ES_VERSION_2_0)
447   if (aGlContext->core11 != NULL)
448   {
449     glDisable (GL_LIGHTING);
450   }
451 #endif
452
453   const OpenGl_AspectLine* anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace()->AspectEdge());
454   const OpenGl_AspectLine* anAspect = theWorkspace->ApplyAspectLine();
455
456 #if !defined(GL_ES_VERSION_2_0)
457   glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
458 #endif
459
460   if (aGlContext->core20fwd != NULL)
461   {
462     aGlContext->ShaderManager()->BindLineProgram (NULL,
463                                                   anAspect->Aspect()->Type() != Aspect_TOL_SOLID,
464                                                   Standard_False,
465                                                   Standard_False,
466                                                   anAspect->ShaderProgramRes (aGlContext));
467   }
468
469   /// OCC22236 NOTE: draw edges for all situations:
470   /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indices array
471   /// 2) draw elements from vertex array, when bounds defines count of primitive's vertices.
472   /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
473   myVboAttribs->BindPositionAttribute (aGlContext);
474
475   aGlContext->SetColor4fv   (theEdgeColour);
476   aGlContext->SetTypeOfLine (anAspect->Aspect()->Type());
477   aGlContext->SetLineWidth  (anAspect->Aspect()->Width());
478
479   if (!myVboIndices.IsNull())
480   {
481     myVboIndices->Bind (aGlContext);
482     GLubyte* anOffset = myVboIndices->GetDataOffset();
483
484     // draw primitives by vertex count with the indices
485     if (!myBounds.IsNull())
486     {
487       const size_t aStride = myVboIndices->GetDataType() == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int);
488       for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
489       {
490         const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
491         glDrawElements (myDrawMode, aNbElemsInGroup, myVboIndices->GetDataType(), anOffset);
492         anOffset += aStride * aNbElemsInGroup;
493       }
494     }
495     // draw one (or sequential) primitive by the indices
496     else
497     {
498       glDrawElements (myDrawMode, myVboIndices->GetElemsNb(), myVboIndices->GetDataType(), anOffset);
499     }
500     myVboIndices->Unbind (aGlContext);
501   }
502   else if (!myBounds.IsNull())
503   {
504     GLint aFirstElem = 0;
505     for (Standard_Integer aGroupIter = 0; aGroupIter < myBounds->NbBounds; ++aGroupIter)
506     {
507       const GLint aNbElemsInGroup = myBounds->Bounds[aGroupIter];
508       glDrawArrays (myDrawMode, aFirstElem, aNbElemsInGroup);
509       aFirstElem += aNbElemsInGroup;
510     }
511   }
512   else
513   {
514     glDrawArrays (myDrawMode, 0, !myVboAttribs.IsNull() ? myVboAttribs->GetElemsNb() : myAttribs->NbElements);
515   }
516
517   // unbind buffers
518   myVboAttribs->UnbindAttribute (aGlContext, Graphic3d_TOA_POS);
519
520   // restore line context
521   theWorkspace->SetAspectLine (anAspectLineOld);
522 }
523
524 // =======================================================================
525 // function : drawMarkers
526 // purpose  :
527 // =======================================================================
528 void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
529 {
530   const OpenGl_AspectMarker* anAspectMarker     = theWorkspace->ApplyAspectMarker();
531   const Handle(OpenGl_Context)&     aCtx        = theWorkspace->GetGlContext();
532   const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (aCtx);
533   if (!aSpriteNorm.IsNull()
534    && !aSpriteNorm->IsDisplayList())
535   {
536     // Textured markers will be drawn with the point sprites
537     aCtx->SetPointSize (anAspectMarker->MarkerSize());
538     aCtx->SetPointSpriteOrigin();
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->Aspect()->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->Aspect()->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->ApplyAspectFace();
693   const OpenGl_AspectLine*   anAspectLine   = theWorkspace->ApplyAspectLine();
694   const OpenGl_AspectMarker* anAspectMarker = myDrawMode == GL_POINTS
695                                             ? theWorkspace->ApplyAspectMarker()
696                                             : theWorkspace->AspectMarker();
697
698   // create VBOs on first render call
699   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
700   if (!myIsVboInit)
701   {
702     // compatibility - keep data to draw markers using display lists
703     const Standard_Boolean toKeepData = myDrawMode == GL_POINTS
704                                     && !anAspectMarker->SpriteRes (aCtx).IsNull()
705                                     &&  anAspectMarker->SpriteRes (aCtx)->IsDisplayList();
706   #if defined (GL_ES_VERSION_2_0)
707     processIndices (aCtx);
708   #endif
709     buildVBO (aCtx, toKeepData);
710     myIsVboInit = Standard_True;
711   }
712
713   const Standard_Boolean hasColorAttrib = !myVboAttribs.IsNull()
714                                         && myVboAttribs->HasColorAttribute();
715   const Standard_Boolean isLightOn = !anAspectFace->IsNoLighting()
716                                   && !myVboAttribs.IsNull()
717                                   &&  myVboAttribs->HasNormalAttribute();
718
719   // Temporarily disable environment mapping
720   Handle(OpenGl_Texture) aTextureBack;
721   bool toDrawArray = true;
722   if (myDrawMode > GL_LINE_STRIP)
723   {
724     toDrawArray = anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_EMPTY;
725   }
726   else if (myDrawMode <= GL_LINE_STRIP)
727   {
728     aTextureBack = theWorkspace->DisableTexture();
729     if (myDrawMode == GL_POINTS)
730     {
731       toDrawArray = anAspectMarker->Aspect()->Type() != Aspect_TOM_EMPTY;
732     }
733     else
734     {
735       toDrawArray = anAspectLine->Aspect()->Type() != Aspect_TOL_EMPTY;
736     }
737   }
738
739   if (toDrawArray)
740   {
741     const bool             toHilight    = theWorkspace->ToHighlight();
742     const Standard_Boolean hasVertColor = hasColorAttrib && !toHilight;
743     switch (myDrawMode)
744     {
745       case GL_POINTS:
746       {
747         const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (aCtx);
748         if (!aSpriteNorm.IsNull()
749          && !aSpriteNorm->IsDisplayList())
750         {
751           const Handle(OpenGl_PointSprite)& aSprite = (toHilight && anAspectMarker->SpriteHighlightRes (aCtx)->IsValid())
752                                                     ? anAspectMarker->SpriteHighlightRes (aCtx)
753                                                     : aSpriteNorm;
754           theWorkspace->EnableTexture (aSprite);
755           aCtx->ShaderManager()->BindMarkerProgram (aSprite, isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
756         }
757         else
758         {
759           aCtx->ShaderManager()->BindMarkerProgram (NULL, isLightOn, hasVertColor, anAspectMarker->ShaderProgramRes (aCtx));
760         }
761         break;
762       }
763       case GL_LINES:
764       case GL_LINE_STRIP:
765       {
766         aCtx->ShaderManager()->BindLineProgram (NULL,
767                                                 anAspectLine->Aspect()->Type() != Aspect_TOL_SOLID,
768                                                 isLightOn,
769                                                 hasVertColor,
770                                                 anAspectLine->ShaderProgramRes (aCtx));
771         break;
772       }
773       default:
774       {
775         const Handle(OpenGl_Texture)& aTexture = theWorkspace->ActiveTexture();
776         const Standard_Boolean isLightOnFace = isLightOn
777                                             && (aTexture.IsNull()
778                                              || aTexture->GetParams()->IsModulate());
779         const Standard_Boolean toEnableEnvMap = (!aTexture.IsNull() && (aTexture == theWorkspace->EnvironmentTexture()));
780         aCtx->ShaderManager()->BindFaceProgram (aTexture,
781                                                 isLightOnFace,
782                                                 hasVertColor,
783                                                 toEnableEnvMap,
784                                                 anAspectFace->ShaderProgramRes (aCtx));
785         break;
786       }
787     }
788
789   #if !defined(GL_ES_VERSION_2_0)
790     // manage FFP lighting
791     if (aCtx->ActiveProgram().IsNull()
792      && aCtx->core11 != NULL)
793     {
794       if (!isLightOn)
795       {
796         glDisable (GL_LIGHTING);
797       }
798       else
799       {
800         glEnable (GL_LIGHTING);
801       }
802     }
803   #endif
804
805     if (!theWorkspace->ActiveTexture().IsNull()
806      && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
807     {
808       aCtx->SetTextureMatrix (theWorkspace->ActiveTexture()->GetParams());
809     }
810
811     if (myDrawMode <= GL_LINE_STRIP)
812     {
813       const OpenGl_Vec4& aLineColor = myDrawMode == GL_POINTS ? theWorkspace->MarkerColor() : theWorkspace->LineColor();
814       aCtx->SetColor4fv (aLineColor);
815     }
816     else
817     {
818       const OpenGl_Vec4& anInteriorColor = theWorkspace->InteriorColor();
819       aCtx->SetColor4fv (anInteriorColor);
820     }
821     if (myDrawMode == GL_LINES
822      || myDrawMode == GL_LINE_STRIP)
823     {
824       aCtx->SetTypeOfLine (anAspectLine->Aspect()->Type());
825       aCtx->SetLineWidth  (anAspectLine->Aspect()->Width());
826     }
827
828     const Graphic3d_Vec4* aFaceColors = !myBounds.IsNull() && !toHilight && anAspectFace->Aspect()->InteriorStyle() != Aspect_IS_HIDDENLINE
829                                       ?  myBounds->Colors
830                                       :  NULL;
831
832     const Standard_Boolean isHighlightWithTransparency = toHilight &&
833       myDrawMode > GL_LINE_STRIP &&
834       theWorkspace->InteriorColor().a() > 0.05f;
835     GLint  aPrevBlendSrc = GL_SRC_ALPHA, aPrevBlendDst = GL_ONE_MINUS_SRC_ALPHA;
836     GLboolean wasBlendEnabled = GL_FALSE;
837     if (isHighlightWithTransparency)
838     {
839       wasBlendEnabled = glIsEnabled (GL_BLEND);
840       #if !defined(GL_ES_VERSION_2_0)
841         glGetIntegerv (GL_BLEND_SRC, &aPrevBlendSrc);
842         glGetIntegerv (GL_BLEND_DST, &aPrevBlendDst);
843       #endif
844       if (!wasBlendEnabled)
845       {
846         glEnable (GL_BLEND);
847       }
848       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
849     }
850
851     drawArray (theWorkspace, aFaceColors, hasColorAttrib);
852
853     if (isHighlightWithTransparency)
854     {
855       glBlendFunc (aPrevBlendSrc, aPrevBlendDst);
856       if (!wasBlendEnabled)
857       {
858         glDisable (GL_BLEND);
859       }
860     }
861   }
862
863   if (myDrawMode <= GL_LINE_STRIP)
864   {
865     theWorkspace->EnableTexture (aTextureBack);
866   }
867   else
868   {
869     if (anAspectFace->Aspect()->ToDrawEdges()
870      || anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_HIDDENLINE)
871     {
872       const OpenGl_Vec4& anEdgeColor = theWorkspace->EdgeColor();
873       drawEdges (anEdgeColor, theWorkspace);
874
875       // restore OpenGL polygon mode if needed
876     #if !defined(GL_ES_VERSION_2_0)
877       if (anAspectFace->Aspect()->InteriorStyle() >= Aspect_IS_HATCH)
878       {
879         glPolygonMode (GL_FRONT_AND_BACK,
880           anAspectFace->Aspect()->InteriorStyle() == Aspect_IS_POINT ? GL_POINT : GL_FILL);
881       }
882     #endif
883     }
884   }
885 }
886
887 // =======================================================================
888 // function : setDrawMode
889 // purpose  :
890 // =======================================================================
891 void OpenGl_PrimitiveArray::setDrawMode (const Graphic3d_TypeOfPrimitiveArray theType)
892 {
893   if (myAttribs.IsNull())
894   {
895     myDrawMode = DRAW_MODE_NONE;
896     return;
897   }
898
899   switch (theType)
900   {
901     case Graphic3d_TOPA_POINTS:
902       myDrawMode = GL_POINTS;
903       break;
904     case Graphic3d_TOPA_POLYLINES:
905       myDrawMode = GL_LINE_STRIP;
906       break;
907     case Graphic3d_TOPA_SEGMENTS:
908       myDrawMode = GL_LINES;
909       break;
910     case Graphic3d_TOPA_TRIANGLES:
911       myDrawMode = GL_TRIANGLES;
912       break;
913     case Graphic3d_TOPA_TRIANGLESTRIPS:
914       myDrawMode = GL_TRIANGLE_STRIP;
915       break;
916     case Graphic3d_TOPA_TRIANGLEFANS:
917       myDrawMode = GL_TRIANGLE_FAN;
918       break;
919   #if !defined(GL_ES_VERSION_2_0)
920     case Graphic3d_TOPA_POLYGONS:
921       myDrawMode = GL_POLYGON;
922       break;
923     case Graphic3d_TOPA_QUADRANGLES:
924       myDrawMode = GL_QUADS;
925       break;
926     case Graphic3d_TOPA_QUADRANGLESTRIPS:
927       myDrawMode = GL_QUAD_STRIP;
928       break;
929   #else
930     case Graphic3d_TOPA_POLYGONS:
931     case Graphic3d_TOPA_QUADRANGLES:
932     case Graphic3d_TOPA_QUADRANGLESTRIPS:
933   #endif
934     case Graphic3d_TOPA_UNDEFINED:
935       break;
936   }
937 }
938
939 // =======================================================================
940 // function : processIndices
941 // purpose  :
942 // =======================================================================
943 Standard_Boolean OpenGl_PrimitiveArray::processIndices (const Handle(OpenGl_Context)& theContext) const
944 {
945   if (myIndices.IsNull()
946    || myAttribs.IsNull()
947    || theContext->hasUintIndex)
948   {
949     return Standard_True;
950   }
951
952   if (myAttribs->NbElements > std::numeric_limits<GLushort>::max())
953   {
954     Handle(Graphic3d_Buffer) anAttribs = new Graphic3d_Buffer (new NCollection_AlignedAllocator (16));
955     if (!anAttribs->Init (myIndices->NbElements, myAttribs->AttributesArray(), myAttribs->NbAttributes))
956     {
957       return Standard_False; // failed to initialize attribute array
958     }
959
960     for (Standard_Integer anIdxIdx = 0; anIdxIdx < myIndices->NbElements; ++anIdxIdx)
961     {
962       const Standard_Integer anIndex = myIndices->Index (anIdxIdx);
963       memcpy (anAttribs->ChangeData() + myAttribs->Stride * anIdxIdx,
964               myAttribs->Data()       + myAttribs->Stride * anIndex,
965               myAttribs->Stride);
966     }
967
968     myIndices.Nullify();
969     myAttribs = anAttribs;
970   }
971
972   return Standard_True;
973 }
974
975 // =======================================================================
976 // function : InitBuffers
977 // purpose  :
978 // =======================================================================
979 void OpenGl_PrimitiveArray::InitBuffers (const Handle(OpenGl_Context)&        theContext,
980                                          const Graphic3d_TypeOfPrimitiveArray theType,
981                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
982                                          const Handle(Graphic3d_Buffer)&      theAttribs,
983                                          const Handle(Graphic3d_BoundBuffer)& theBounds)
984 {
985   // Release old graphic resources
986   Release (theContext.operator->());
987
988   myIndices = theIndices;
989   myAttribs = theAttribs;
990   myBounds = theBounds;
991 #if defined(GL_ES_VERSION_2_0)
992   processIndices (theContext);
993 #endif
994
995   setDrawMode (theType);
996 }