1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
20 #include <OpenGl_IndexBuffer.hxx>
21 #include <OpenGl_Context.hxx>
23 #include <OpenGl_PrimitiveArray.hxx>
25 #include <OpenGl_AspectFace.hxx>
26 #include <OpenGl_GraphicDriver.hxx>
27 #include <OpenGl_Structure.hxx>
28 #include <OpenGl_Workspace.hxx>
30 #include <InterfaceGraphic_PrimitiveArray.hxx>
32 // =======================================================================
33 // function : clearMemoryOwn
35 // =======================================================================
36 void OpenGl_PrimitiveArray::clearMemoryOwn() const
38 Standard::Free ((Standard_Address& )myPArray->edges);
39 Standard::Free ((Standard_Address& )myPArray->vertices);
40 Standard::Free ((Standard_Address& )myPArray->vcolours);
41 Standard::Free ((Standard_Address& )myPArray->vnormals);
42 Standard::Free ((Standard_Address& )myPArray->vtexels);
43 Standard::Free ((Standard_Address& )myPArray->edge_vis); /// ???
45 myPArray->edges = NULL;
46 myPArray->vertices = NULL;
47 myPArray->vcolours = NULL;
48 myPArray->vnormals = NULL;
49 myPArray->vtexels = NULL;
50 myPArray->edge_vis = NULL;
53 // =======================================================================
54 // function : clearMemoryGL
56 // =======================================================================
57 void OpenGl_PrimitiveArray::clearMemoryGL (const Handle(OpenGl_Context)& theGlCtx) const
59 for (Standard_Integer anIter = 0; anIter < VBOMaxType; ++anIter)
61 if (!myVbos[anIter].IsNull())
63 myVbos[anIter]->Release (theGlCtx.operator->());
64 myVbos[anIter].Nullify();
69 // =======================================================================
70 // function : BuildVBO
72 // =======================================================================
73 Standard_Boolean OpenGl_PrimitiveArray::BuildVBO (const Handle(OpenGl_Workspace)& theWorkspace) const
75 const Handle(OpenGl_Context)& aGlCtx = theWorkspace->GetGlContext();
76 if (myPArray->vertices == NULL)
78 // vertices should be always defined - others are optional
79 return Standard_False;
81 myVbos[VBOVertices] = new OpenGl_VertexBuffer();
82 if (!myVbos[VBOVertices]->Init (aGlCtx, 3, myPArray->num_vertexs, &myPArray->vertices[0].xyz[0]))
84 clearMemoryGL (aGlCtx);
85 return Standard_False;
88 if (myPArray->edges != NULL
89 && myPArray->num_edges > 0)
91 myVbos[VBOEdges] = new OpenGl_IndexBuffer();
92 if (!myVbos[VBOEdges]->Init (aGlCtx, 1, myPArray->num_edges, (GLuint* )myPArray->edges))
94 clearMemoryGL (aGlCtx);
95 return Standard_False;
98 if (myPArray->vcolours != NULL)
100 myVbos[VBOVcolours] = new OpenGl_VertexBuffer();
101 if (!myVbos[VBOVcolours]->Init (aGlCtx, 4, myPArray->num_vertexs, (GLubyte* )myPArray->vcolours))
103 clearMemoryGL (aGlCtx);
104 return Standard_False;
107 if (myPArray->vnormals != NULL)
109 myVbos[VBOVnormals] = new OpenGl_VertexBuffer();
110 if (!myVbos[VBOVnormals]->Init (aGlCtx, 3, myPArray->num_vertexs, &myPArray->vnormals[0].xyz[0]))
112 clearMemoryGL (aGlCtx);
113 return Standard_False;
116 if (myPArray->vtexels)
118 myVbos[VBOVtexels] = new OpenGl_VertexBuffer();
119 if (!myVbos[VBOVtexels]->Init (aGlCtx, 2, myPArray->num_vertexs, &myPArray->vtexels[0].xy[0]))
121 clearMemoryGL (aGlCtx);
122 return Standard_False;
127 return Standard_True;
130 // =======================================================================
131 // function : DrawArray
133 // =======================================================================
134 void OpenGl_PrimitiveArray::DrawArray (Tint theLightingModel,
135 const Aspect_InteriorStyle theInteriorStyle,
137 const TEL_COLOUR* theInteriorColour,
138 const TEL_COLOUR* theLineColour,
139 const TEL_COLOUR* theEdgeColour,
140 const OPENGL_SURF_PROP* theFaceProp,
141 const Handle(OpenGl_Workspace)& theWorkspace) const
143 const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
147 // Following pointers have been provided for performance improvement
148 tel_colour pfc = myPArray->fcolours;
149 Tint* pvc = myPArray->vcolours;
152 for (i = 0; i < myPArray->num_vertexs; ++i)
154 transp = int(theFaceProp->trans * 255.0f);
155 #if defined (sparc) || defined (__sparc__) || defined (__sparc)
156 pvc[i] = (pvc[i] & 0xffffff00);
159 pvc[i] = (pvc[i] & 0x00ffffff);
160 pvc[i] += transp << 24;
165 switch (myPArray->type)
167 case TelPointsArrayType:
168 case TelPolylinesArrayType:
169 case TelSegmentsArrayType:
170 glColor3fv (theLineColour->rgb);
172 case TelPolygonsArrayType:
173 case TelTrianglesArrayType:
174 case TelQuadranglesArrayType:
175 case TelTriangleStripsArrayType:
176 case TelQuadrangleStripsArrayType:
177 case TelTriangleFansArrayType:
178 glColor3fv (theInteriorColour->rgb);
182 // Temporarily disable environment mapping
183 if (myDrawMode <= GL_LINE_STRIP)
185 glPushAttrib (GL_ENABLE_BIT);
186 glDisable (GL_TEXTURE_1D);
187 glDisable (GL_TEXTURE_2D);
190 if ((myDrawMode > GL_LINE_STRIP && theInteriorStyle != Aspect_IS_EMPTY) ||
191 (myDrawMode <= GL_LINE_STRIP))
193 if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
199 if (theInteriorStyle == Aspect_IS_HIDDENLINE)
206 // Sometimes the GL_LIGHTING mode is activated here
207 // without glEnable(GL_LIGHTING) call for an unknown reason, so it is necessary
208 // to call glEnable(GL_LIGHTING) to synchronize Light On/Off mechanism*
209 if (theLightingModel == 0 || myDrawMode <= GL_LINE_STRIP)
210 glDisable (GL_LIGHTING);
212 glEnable (GL_LIGHTING);
216 if (myPArray->vertices != NULL)
218 glVertexPointer (3, GL_FLOAT, 0, myPArray->vertices); // array of vertices
219 glEnableClientState (GL_VERTEX_ARRAY);
221 if (myPArray->vnormals != NULL)
223 glNormalPointer (GL_FLOAT, 0, myPArray->vnormals); // array of normals
224 glEnableClientState (GL_NORMAL_ARRAY);
226 if (myPArray->vtexels != NULL)
228 glTexCoordPointer (2, GL_FLOAT, 0, myPArray->vtexels); // array of texture coordinates
229 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
234 glColorPointer (4, GL_UNSIGNED_BYTE, 0, pvc); // array of colors
235 glEnableClientState (GL_COLOR_ARRAY);
236 glColorMaterial (GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
237 glEnable (GL_COLOR_MATERIAL);
242 // Bindings concrete pointer in accordance with VBO buffer
243 myVbos[VBOVertices]->BindFixed (aGlContext, GL_VERTEX_ARRAY);
244 if (!myVbos[VBOVnormals].IsNull())
246 myVbos[VBOVnormals]->BindFixed (aGlContext, GL_NORMAL_ARRAY);
248 if (!myVbos[VBOVtexels].IsNull() && (theWorkspace->NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
250 myVbos[VBOVtexels]->BindFixed (aGlContext, GL_TEXTURE_COORD_ARRAY);
252 if (!myVbos[VBOVcolours].IsNull())
254 myVbos[VBOVcolours]->BindFixed (aGlContext, GL_COLOR_ARRAY);
255 glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
256 glEnable (GL_COLOR_MATERIAL);
260 /// OCC22236 NOTE: draw for all situations:
261 /// 1) draw elements from myPArray->bufferVBO[VBOEdges] indicies array
262 /// 2) draw elements from vertice array, when bounds defines count of primitive's verts.
263 /// 3) draw primitive by vertexes if no edges and bounds array is specified
266 if (!myVbos[VBOEdges].IsNull())
268 myVbos[VBOEdges]->Bind (aGlContext);
269 if (myPArray->num_bounds > 0)
271 // draw primitives by vertex count with the indicies
272 Tint* anOffset = NULL;
273 for (i = 0; i < myPArray->num_bounds; ++i)
275 if (pfc != NULL) glColor3fv (pfc[i].rgb);
276 glDrawElements (myDrawMode, myPArray->bounds[i], myVbos[VBOEdges]->GetDataType(), anOffset);
277 anOffset += myPArray->bounds[i];
282 // draw one (or sequential) primitive by the indicies
283 glDrawElements (myDrawMode, myPArray->num_edges, myVbos[VBOEdges]->GetDataType(), NULL);
285 myVbos[VBOEdges]->Unbind (aGlContext);
287 else if (myPArray->num_bounds > 0)
289 for (i = n = 0; i < myPArray->num_bounds; ++i)
291 if (pfc != NULL) glColor3fv (pfc[i].rgb);
292 glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
293 n += myPArray->bounds[i];
298 glDrawArrays (myDrawMode, 0, myVbos[VBOVertices]->GetElemsNb());
302 myVbos[VBOVertices]->UnbindFixed (aGlContext, GL_VERTEX_ARRAY);
303 if (!myVbos[VBOVnormals].IsNull())
305 myVbos[VBOVnormals]->UnbindFixed (aGlContext, GL_NORMAL_ARRAY);
307 if (!myVbos[VBOVtexels].IsNull() && (theWorkspace->NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
309 myVbos[VBOVtexels]->UnbindFixed (aGlContext, GL_TEXTURE_COORD_ARRAY);
311 if (!myVbos[VBOVcolours].IsNull())
313 myVbos[VBOVcolours]->UnbindFixed (aGlContext, GL_COLOR_ARRAY);
314 glDisable (GL_COLOR_MATERIAL);
315 theWorkspace->NamedStatus |= OPENGL_NS_RESMAT; // Reset material
320 if (myPArray->num_bounds > 0)
322 if (myPArray->num_edges > 0)
324 for (i = n = 0; i < myPArray->num_bounds; ++i)
326 if (pfc != NULL) glColor3fv (pfc[i].rgb);
327 glDrawElements (myDrawMode, myPArray->bounds[i], GL_UNSIGNED_INT, (GLenum* )&myPArray->edges[n]);
328 n += myPArray->bounds[i];
333 for (i = n = 0; i < myPArray->num_bounds; ++i)
335 if (pfc != NULL) glColor3fv (pfc[i].rgb);
336 glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
337 n += myPArray->bounds[i];
341 else if (myPArray->num_edges > 0)
343 glDrawElements (myDrawMode, myPArray->num_edges, GL_UNSIGNED_INT, (GLenum* )myPArray->edges);
347 glDrawArrays (myDrawMode, 0, myPArray->num_vertexs);
352 glDisable (GL_COLOR_MATERIAL);
353 theWorkspace->NamedStatus |= OPENGL_NS_RESMAT; // Reset material
356 glDisableClientState (GL_VERTEX_ARRAY);
357 if (myPArray->vcolours != NULL)
358 glDisableClientState (GL_COLOR_ARRAY);
359 if (myPArray->vnormals != NULL)
360 glDisableClientState (GL_NORMAL_ARRAY);
361 if (myPArray->vtexels != NULL)
362 glDisableClientState (GL_TEXTURE_COORD_ARRAY);
366 // On some NVIDIA graphic cards, using glEdgeFlagPointer() in
367 // combination with VBO (edge flag data put into a VBO buffer)
368 // leads to a crash in a driver. Therefore, edge flags are simply
369 // igonored when VBOs are enabled, so all the edges are drawn if
370 // edge visibility is turned on. In order to draw edges selectively,
371 // either disable VBO or turn off edge visibilty in the current
372 // primitive array and create a separate primitive array (segments)
373 // and put edges to be drawn into it.
374 if (theEdgeFlag && myDrawMode > GL_LINE_STRIP)
376 DrawEdges (theEdgeColour, theWorkspace);
379 if (myDrawMode <= GL_LINE_STRIP)
383 // =======================================================================
384 // function : DrawEdges
386 // =======================================================================
387 void OpenGl_PrimitiveArray::DrawEdges (const TEL_COLOUR* theEdgeColour,
388 const Handle(OpenGl_Workspace)& theWorkspace) const
390 glDisable (GL_LIGHTING);
392 const Handle(OpenGl_Context)& aGlContext = theWorkspace->GetGlContext();
393 const OpenGl_AspectLine* anAspectLineOld = NULL;
394 if (myDrawMode > GL_LINE_STRIP)
396 anAspectLineOld = theWorkspace->SetAspectLine (theWorkspace->AspectFace (Standard_True)->AspectEdge());
397 theWorkspace->AspectLine (Standard_True);
399 glPushAttrib (GL_POLYGON_BIT);
400 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
405 /// OCC22236 NOTE: draw edges for all situations:
406 /// 1) draw elements with GL_LINE style as edges from myPArray->bufferVBO[VBOEdges] indicies array
407 /// 2) draw elements from vertice array, when bounds defines count of primitive's verts.
408 /// 3) draw primitive's edges by vertexes if no edges and bounds array is specified
411 myVbos[VBOVertices]->BindFixed (aGlContext, GL_VERTEX_ARRAY);
412 glColor3fv (theEdgeColour->rgb);
413 if (!myVbos[VBOEdges].IsNull())
415 myVbos[VBOEdges]->Bind (aGlContext);
417 // draw primitives by vertex count with the indicies
418 if (myPArray->num_bounds > 0)
421 for (i = 0, offset = 0; i < myPArray->num_bounds; ++i)
423 glDrawElements (myDrawMode, myPArray->bounds[i], myVbos[VBOEdges]->GetDataType(), offset);
424 offset += myPArray->bounds[i];
427 // draw one (or sequential) primitive by the indicies
430 glDrawElements (myDrawMode, myVbos[VBOEdges]->GetElemsNb(), myVbos[VBOEdges]->GetDataType(), NULL);
432 myVbos[VBOEdges]->Unbind (aGlContext);
434 else if (myPArray->num_bounds > 0)
436 for (i = n = 0; i < myPArray->num_bounds; ++i)
438 glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
439 n += myPArray->bounds[i];
444 glDrawArrays (myDrawMode, 0, myPArray->num_vertexs);
448 myVbos[VBOVertices]->UnbindFixed (aGlContext, GL_VERTEX_ARRAY);
452 glEnableClientState (GL_VERTEX_ARRAY);
453 glVertexPointer (3, GL_FLOAT, 0, myPArray->vertices); // array of vertices
455 glColor3fv (theEdgeColour->rgb);
456 if (myPArray->num_bounds > 0)
458 if (myPArray->num_edges > 0)
460 for (i = n = 0; i < myPArray->num_bounds; ++i)
462 if (myPArray->edge_vis)
464 glBegin (myDrawMode);
465 for (j = 0; j < myPArray->bounds[i]; ++j)
467 glEdgeFlag (myPArray->edge_vis[n+j]);
468 glVertex3fv (&myPArray->vertices[myPArray->edges[n+j]].xyz[0]);
474 glDrawElements (myDrawMode, myPArray->bounds[i], GL_UNSIGNED_INT, (GLenum* )&myPArray->edges[n]);
476 n += myPArray->bounds[i];
481 for (i = n = 0 ; i < myPArray->num_bounds; ++i)
483 glDrawArrays (myDrawMode, n, myPArray->bounds[i]);
484 n += myPArray->bounds[i];
488 else if (myPArray->num_edges > 0)
490 if (myPArray->edge_vis)
492 glBegin (myDrawMode);
493 for (i = 0; i < myPArray->num_edges; ++i)
495 glEdgeFlag (myPArray->edge_vis[i]);
496 glVertex3fv (&myPArray->vertices[myPArray->edges[i]].xyz[0]);
502 glDrawElements (myDrawMode, myPArray->num_edges, GL_UNSIGNED_INT, (GLenum* )myPArray->edges);
507 glDrawArrays (myDrawMode, 0, myPArray->num_vertexs);
511 if (myDrawMode > GL_LINE_STRIP)
513 // Restore line context
514 theWorkspace->SetAspectLine (anAspectLineOld);
519 // =======================================================================
520 // function : OpenGl_PrimitiveArray
522 // =======================================================================
523 OpenGl_PrimitiveArray::OpenGl_PrimitiveArray (CALL_DEF_PARRAY* thePArray)
524 : myPArray (thePArray),
525 myDrawMode (DRAW_MODE_NONE),
526 myIsVboInit (Standard_False)
528 switch (myPArray->type)
530 case TelPointsArrayType:
531 myDrawMode = GL_POINTS;
533 case TelPolylinesArrayType:
534 myDrawMode = GL_LINE_STRIP;
536 case TelSegmentsArrayType:
537 myDrawMode = GL_LINES;
539 case TelPolygonsArrayType:
540 myDrawMode = GL_POLYGON;
542 case TelTrianglesArrayType:
543 myDrawMode = GL_TRIANGLES;
545 case TelQuadranglesArrayType:
546 myDrawMode = GL_QUADS;
548 case TelTriangleStripsArrayType:
549 myDrawMode = GL_TRIANGLE_STRIP;
551 case TelQuadrangleStripsArrayType:
552 myDrawMode = GL_QUAD_STRIP;
554 case TelTriangleFansArrayType:
555 myDrawMode = GL_TRIANGLE_FAN;
560 // =======================================================================
561 // function : ~OpenGl_PrimitiveArray
563 // =======================================================================
564 OpenGl_PrimitiveArray::~OpenGl_PrimitiveArray()
569 // =======================================================================
570 // function : Release
572 // =======================================================================
573 void OpenGl_PrimitiveArray::Release (const Handle(OpenGl_Context)& theContext)
575 for (Standard_Integer anIter = 0; anIter < VBOMaxType; ++anIter)
577 if (!myVbos[anIter].IsNull())
579 if (!theContext.IsNull())
581 theContext->DelayedRelease (myVbos[anIter]);
583 myVbos[anIter].Nullify();
588 // =======================================================================
591 // =======================================================================
592 void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
594 if (myPArray == NULL || myDrawMode == DRAW_MODE_NONE || myPArray->num_vertexs <= 0)
599 // create VBOs on first render call
600 if (!myIsVboInit && OpenGl_GraphicDriver::ToUseVBO() && theWorkspace->GetGlContext()->core15 != NULL)
602 BuildVBO (theWorkspace);
603 myIsVboInit = Standard_True;
606 switch (myPArray->type)
608 case TelPointsArrayType:
609 case TelPolylinesArrayType:
610 case TelSegmentsArrayType:
612 glDisable (GL_LIGHTING);
619 const OpenGl_AspectFace* anAspectFace = theWorkspace->AspectFace (Standard_True);
620 const OpenGl_AspectLine* anAspectLine = theWorkspace->AspectLine (Standard_True);
621 const OpenGl_AspectMarker* anAspectMarker = theWorkspace->AspectMarker (myPArray->type == TelPointsArrayType);
623 Tint aFrontLightingModel = anAspectFace->IntFront.color_mask;
624 const TEL_COLOUR* anInteriorColor = &anAspectFace->IntFront.matcol;
625 const TEL_COLOUR* anEdgeColor = &anAspectFace->AspectEdge()->Color();
626 const TEL_COLOUR* aLineColor = (myPArray->type == TelPointsArrayType) ? &anAspectMarker->Color() : &anAspectLine->Color();
628 // Use highlight colors
629 if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
631 anEdgeColor = anInteriorColor = aLineColor = theWorkspace->HighlightColor;
632 aFrontLightingModel = 0;
635 DrawArray (aFrontLightingModel,
636 anAspectFace->InteriorStyle,
641 &anAspectFace->IntFront,