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