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