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