0025133: TKOpenGl - Crash on closing a view containing presentations with capping
[occt.git] / src / OpenGl / OpenGl_AspectFace.cxx
1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 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 <Aspect_PolygonOffsetMode.hxx>
17 #include <NCollection_Vec3.hxx>
18
19 #include <OpenGl_AspectFace.hxx>
20 #include <OpenGl_Context.hxx>
21 #include <OpenGl_ShaderManager.hxx>
22 #include <OpenGl_ShaderProgram.hxx>
23 #include <OpenGl_Texture.hxx>
24 #include <OpenGl_Workspace.hxx>
25
26 #include <Graphic3d_ShaderProgram.hxx>
27 #include <Graphic3d_TextureMap.hxx>
28 #include <Graphic3d_TypeOfReflection.hxx>
29 #include <Graphic3d_MaterialAspect.hxx>
30
31 namespace
32 {
33   static OPENGL_SURF_PROP THE_DEFAULT_MATERIAL =
34   {
35     0.2F,  0.8F, 0.1F, 0.0F, // amb, diff, spec, emsv
36     1.0F, 10.0F, 1.0F, 0.0F, // trans, shine, index, env_reflexion
37     0, // isphysic
38     (OPENGL_AMBIENT_MASK | OPENGL_DIFFUSE_MASK | OPENGL_SPECULAR_MASK), // color_mask
39     {{ 1.0F, 1.0F, 1.0F, 1.0F }}, // ambient color
40     {{ 1.0F, 1.0F, 1.0F, 1.0F }}, // diffuse color
41     {{ 1.0F, 1.0F, 1.0F, 1.0F }}, // specular color
42     {{ 1.0F, 1.0F, 1.0F, 1.0F }}, // emissive color
43     {{ 1.0F, 1.0F, 1.0F, 1.0F }}  // material color
44   };
45
46   static const TCollection_AsciiString THE_EMPTY_KEY;
47 };
48
49 // =======================================================================
50 // function : convertMaterial
51 // purpose  :
52 // =======================================================================
53 void OpenGl_AspectFace::convertMaterial (const CALL_DEF_MATERIAL& theMat,
54                                          OPENGL_SURF_PROP&        theSurf)
55 {
56   theSurf.amb  = theMat.IsAmbient  ? theMat.Ambient  : 0.0f;
57   theSurf.diff = theMat.IsDiffuse  ? theMat.Diffuse  : 0.0f;
58   theSurf.spec = theMat.IsSpecular ? theMat.Specular : 0.0f;
59   theSurf.emsv = theMat.IsEmission ? theMat.Emission : 0.0f;
60
61   theSurf.isphysic = theMat.IsPhysic ? 1 : 0; // type of material
62
63   // color of material
64   theSurf.color_mask = 0;
65   if (theMat.IsAmbient)
66   {
67     theSurf.color_mask |= OPENGL_AMBIENT_MASK;
68   }
69   if (theMat.IsDiffuse)
70   {
71     theSurf.color_mask |= OPENGL_DIFFUSE_MASK;
72   }
73   if (theMat.IsSpecular)
74   {
75     theSurf.color_mask |= OPENGL_SPECULAR_MASK;
76   }
77   if (theMat.IsEmission)
78   {
79     theSurf.color_mask |= OPENGL_EMISSIVE_MASK;
80   }
81
82   // ambient color
83   theSurf.ambcol.rgb[0] = theMat.ColorAmb.r;
84   theSurf.ambcol.rgb[1] = theMat.ColorAmb.g;
85   theSurf.ambcol.rgb[2] = theMat.ColorAmb.b;
86   theSurf.ambcol.rgb[3] = 1.0f;
87
88   // diffuse color
89   theSurf.difcol.rgb[0] = theMat.ColorDif.r;
90   theSurf.difcol.rgb[1] = theMat.ColorDif.g;
91   theSurf.difcol.rgb[2] = theMat.ColorDif.b;
92   theSurf.difcol.rgb[3] = 1.0f;
93
94   // specular color
95   theSurf.speccol.rgb[0] = theMat.ColorSpec.r;
96   theSurf.speccol.rgb[1] = theMat.ColorSpec.g;
97   theSurf.speccol.rgb[2] = theMat.ColorSpec.b;
98   theSurf.speccol.rgb[3] = 1.0f;
99
100   // emission color
101   theSurf.emscol.rgb[0] = theMat.ColorEms.r;
102   theSurf.emscol.rgb[1] = theMat.ColorEms.g;
103   theSurf.emscol.rgb[2] = theMat.ColorEms.b;
104   theSurf.emscol.rgb[3] = 1.0f;
105
106   theSurf.shine = 128.0f * float(theMat.Shininess);
107   theSurf.env_reflexion = theMat.EnvReflexion;
108
109   // trans = 0. => opaque
110   // trans = 1. => transparent
111   // in OpenGl it is opposite.
112   theSurf.trans = 1.0f - theMat.Transparency;
113   theSurf.index = theMat.RefractionIndex;
114 }
115
116 // =======================================================================
117 // function : OpenGl_AspectFace
118 // purpose  :
119 // =======================================================================
120 OpenGl_AspectFace::OpenGl_AspectFace()
121 : myInteriorStyle (Aspect_IS_SOLID),
122   myEdge (TOff),
123   myHatch (TEL_HS_SOLID),
124   myDistinguishingMode (TOff),
125   myCullingMode (TelCullNone),
126   myIntFront (THE_DEFAULT_MATERIAL),
127   myIntBack (THE_DEFAULT_MATERIAL),
128   myPolygonOffset (THE_DEFAULT_POFFSET),
129   myDoTextureMap (false)
130 {}
131
132 // =======================================================================
133 // function : SetAspect
134 // purpose  :
135 // =======================================================================
136 void OpenGl_AspectFace::SetAspect (const CALL_DEF_CONTEXTFILLAREA& theAspect)
137 {
138   myInteriorStyle = (Aspect_InteriorStyle )theAspect.Style;
139   myEdge = theAspect.Edge ? TOn : TOff;
140
141   //TelInteriorStyleIndex
142   switch (theAspect.Hatch)
143   {
144     case 0: /* Aspect_HS_HORIZONTAL */
145       myHatch = TEL_HS_HORIZONTAL;
146       break;
147     case 1: /* Aspect_HS_HORIZONTAL_WIDE */
148       myHatch = TEL_HS_HORIZONTAL_SPARSE;
149       break;
150     case 2: /* Aspect_HS_VERTICAL */
151       myHatch = TEL_HS_VERTICAL;
152       break;
153     case 3: /* Aspect_HS_VERTICAL_WIDE */
154       myHatch = TEL_HS_VERTICAL_SPARSE;
155       break;
156     case 4: /* Aspect_HS_DIAGONAL_45 */
157       myHatch = TEL_HS_DIAG_45;
158       break;
159     case 5: /* Aspect_HS_DIAGONAL_45_WIDE */
160       myHatch = TEL_HS_DIAG_45_SPARSE;
161       break;
162     case 6: /* Aspect_HS_DIAGONAL_135 */
163       myHatch = TEL_HS_DIAG_135;
164       break;
165     case 7: /* Aspect_HS_DIAGONAL_135_WIDE */
166       myHatch = TEL_HS_DIAG_135_SPARSE;
167       break;
168     case 8: /* Aspect_HS_GRID */
169       myHatch = TEL_HS_GRID;
170       break;
171     case 9: /* Aspect_HS_GRID_WIDE */
172       myHatch = TEL_HS_GRID_SPARSE;
173       break;
174     case 10: /* Aspect_HS_GRID_DIAGONAL */
175       myHatch = TEL_HS_CROSS;
176       break;
177     case 11: /* Aspect_HS_GRID_DIAGONAL_WIDE */
178       myHatch = TEL_HS_CROSS_SPARSE;
179       break;
180     default:
181       myHatch = 0;
182       break;
183   }
184
185   myDistinguishingMode = theAspect.Distinguish ? TOn : TOff;
186   myCullingMode = theAspect.BackFace ? TelCullBack : TelCullNone;
187
188   convertMaterial (theAspect.Front, myIntFront);
189   convertMaterial (theAspect.Back,  myIntBack);
190
191   //TelInteriorColour
192   myIntFront.matcol.rgb[0] = (float )theAspect.IntColor.r;
193   myIntFront.matcol.rgb[1] = (float )theAspect.IntColor.g;
194   myIntFront.matcol.rgb[2] = (float )theAspect.IntColor.b;
195   myIntFront.matcol.rgb[3] = 1.0f;
196
197   //TelBackInteriorColour
198   myIntBack.matcol.rgb[0] = (float )theAspect.BackIntColor.r;
199   myIntBack.matcol.rgb[1] = (float )theAspect.BackIntColor.g;
200   myIntBack.matcol.rgb[2] = (float )theAspect.BackIntColor.b;
201   myIntBack.matcol.rgb[3] = 1.0f;
202
203   //TelPolygonOffset
204   myPolygonOffset.mode   = (Aspect_PolygonOffsetMode )theAspect.PolygonOffsetMode;
205   myPolygonOffset.factor = theAspect.PolygonOffsetFactor;
206   myPolygonOffset.units  = theAspect.PolygonOffsetUnits;
207
208   CALL_DEF_CONTEXTLINE anEdgeAspect;
209   anEdgeAspect.Color.r  = (float )theAspect.EdgeColor.r;
210   anEdgeAspect.Color.g  = (float )theAspect.EdgeColor.g;
211   anEdgeAspect.Color.b  = (float )theAspect.EdgeColor.b;
212   anEdgeAspect.LineType = (Aspect_TypeOfLine )theAspect.LineType;
213   anEdgeAspect.Width    = (float )theAspect.Width;
214   myAspectEdge.SetAspect (anEdgeAspect);
215
216   myDoTextureMap = (theAspect.Texture.doTextureMap != 0);
217
218   // update texture binding
219   myTexture = theAspect.Texture.TextureMap;
220
221   const TCollection_AsciiString& aTextureKey = myTexture.IsNull() ? THE_EMPTY_KEY : myTexture->GetId();
222   if (aTextureKey.IsEmpty() || myResources.TextureId != aTextureKey)
223   {
224     myResources.ResetTextureReadiness();
225   }
226
227   // update shader program binding
228   myShaderProgram = theAspect.ShaderProgram;
229
230   const TCollection_AsciiString& aShaderKey = myShaderProgram.IsNull() ? THE_EMPTY_KEY : myShaderProgram->GetId();
231   if (aShaderKey.IsEmpty() || myResources.ShaderProgramId != aShaderKey)
232   {
233     myResources.ResetShaderReadiness();
234   }
235 }
236
237 // =======================================================================
238 // function : SetAspect
239 // purpose  :
240 // =======================================================================
241 void OpenGl_AspectFace::SetAspect (const Handle(Graphic3d_AspectFillArea3d)& theAspect)
242 {
243   CALL_DEF_CONTEXTFILLAREA aFaceContext;
244   Standard_Real           aWidth;
245   Quantity_Color          aBackIntColor;
246   Quantity_Color          aEdgeColor;
247   Aspect_TypeOfLine       aLType;
248   Quantity_Color          aIntColor;
249   Aspect_InteriorStyle    aIntStyle;
250   NCollection_Vec3<Standard_Real> aColor;
251
252   theAspect->Values (aIntStyle, aIntColor, aBackIntColor, aEdgeColor, aLType, aWidth);
253   aIntColor.Values (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB);
254
255   aFaceContext.Style      = int (aIntStyle);
256   aFaceContext.IntColor.r = float (aColor.r());
257   aFaceContext.IntColor.g = float (aColor.g());
258   aFaceContext.IntColor.b = float (aColor.b());
259
260   if (theAspect->Distinguish())
261   {
262     aBackIntColor.Values (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB);
263   }
264
265   aFaceContext.BackIntColor.r = float (aColor.r());
266   aFaceContext.BackIntColor.g = float (aColor.g());
267   aFaceContext.BackIntColor.b = float (aColor.b());
268
269   aFaceContext.Edge = theAspect->Edge () ? 1:0;
270   aEdgeColor.Values (aColor.r(), aColor.g(), aColor.b(), Quantity_TOC_RGB);
271
272   aFaceContext.EdgeColor.r = float (aColor.r());
273   aFaceContext.EdgeColor.g = float (aColor.g());
274   aFaceContext.EdgeColor.b = float (aColor.b());
275   aFaceContext.LineType    = int (aLType);
276   aFaceContext.Width       = float (aWidth);
277   aFaceContext.Hatch       = int (theAspect->HatchStyle ());
278
279   aFaceContext.Distinguish = theAspect->Distinguish () ? 1:0;
280   aFaceContext.BackFace    = theAspect->BackFace ()    ? 1:0;
281
282   aFaceContext.Back.Shininess = float ((theAspect->BackMaterial ()).Shininess ());
283   aFaceContext.Back.Ambient   = float ((theAspect->BackMaterial ()).Ambient ());
284   aFaceContext.Back.Diffuse   = float ((theAspect->BackMaterial ()).Diffuse ());
285   aFaceContext.Back.Specular  = float ((theAspect->BackMaterial ()).Specular ());
286   aFaceContext.Back.Transparency  = float ((theAspect->BackMaterial ()).Transparency ());
287   aFaceContext.Back.Emission      = float ((theAspect->BackMaterial ()).Emissive ());
288
289   // Reflection mode
290   aFaceContext.Back.IsAmbient = ((theAspect->BackMaterial ()).ReflectionMode (Graphic3d_TOR_AMBIENT) ? 1 : 0 );
291   aFaceContext.Back.IsDiffuse = ((theAspect->BackMaterial ()).ReflectionMode (Graphic3d_TOR_DIFFUSE) ? 1 : 0 );
292   aFaceContext.Back.IsSpecular = ((theAspect->BackMaterial ()).ReflectionMode (Graphic3d_TOR_SPECULAR) ? 1 : 0 );
293   aFaceContext.Back.IsEmission = ((theAspect->BackMaterial ()).ReflectionMode (Graphic3d_TOR_EMISSION) ? 1 : 0 );
294
295   // Material type
296   const Graphic3d_MaterialAspect aBackMat = theAspect->BackMaterial ();
297   Standard_Boolean isBackPhys = aBackMat.MaterialType (Graphic3d_MATERIAL_PHYSIC);
298   aFaceContext.Back.IsPhysic = (isBackPhys ? 1 : 0 );
299
300   // Specular Color
301   aFaceContext.Back.ColorSpec.r = float (((theAspect->BackMaterial ()).SpecularColor ()).Red ());
302   aFaceContext.Back.ColorSpec.g = float (((theAspect->BackMaterial ()).SpecularColor ()).Green ());
303   aFaceContext.Back.ColorSpec.b = float (((theAspect->BackMaterial ()).SpecularColor ()).Blue ());
304
305   // Ambient color
306   aFaceContext.Back.ColorAmb.r = float (((theAspect->BackMaterial ()).AmbientColor ()).Red ());
307   aFaceContext.Back.ColorAmb.g = float (((theAspect->BackMaterial ()).AmbientColor ()).Green ());
308   aFaceContext.Back.ColorAmb.b = float (((theAspect->BackMaterial ()).AmbientColor ()).Blue ());
309
310   // Diffuse color
311   aFaceContext.Back.ColorDif.r = float (((theAspect->BackMaterial ()).DiffuseColor ()).Red ());
312   aFaceContext.Back.ColorDif.g = float (((theAspect->BackMaterial ()).DiffuseColor ()).Green ());
313   aFaceContext.Back.ColorDif.b = float (((theAspect->BackMaterial ()).DiffuseColor ()).Blue ());
314
315   // Emissive color
316   aFaceContext.Back.ColorEms.r = float (((theAspect->BackMaterial ()).EmissiveColor ()).Red ());
317   aFaceContext.Back.ColorEms.g = float (((theAspect->BackMaterial ()).EmissiveColor ()).Green ());
318   aFaceContext.Back.ColorEms.b = float (((theAspect->BackMaterial ()).EmissiveColor ()).Blue ());
319
320   aFaceContext.Back.EnvReflexion = float ((theAspect->BackMaterial ()).EnvReflexion());
321
322   aFaceContext.Front.Shininess    = float ((theAspect->FrontMaterial ()).Shininess ());
323   aFaceContext.Front.Ambient      = float ((theAspect->FrontMaterial ()).Ambient ());
324   aFaceContext.Front.Diffuse      = float ((theAspect->FrontMaterial ()).Diffuse ());
325   aFaceContext.Front.Specular     = float ((theAspect->FrontMaterial ()).Specular ());
326   aFaceContext.Front.Transparency = float ((theAspect->FrontMaterial ()).Transparency ());
327   aFaceContext.Front.Emission     = float ((theAspect->FrontMaterial ()).Emissive ());
328
329   // Reflection mode
330   aFaceContext.Front.IsAmbient    = ((theAspect->FrontMaterial ()).ReflectionMode (Graphic3d_TOR_AMBIENT) ? 1 : 0);
331   aFaceContext.Front.IsDiffuse    = ((theAspect->FrontMaterial ()).ReflectionMode (Graphic3d_TOR_DIFFUSE) ? 1 : 0);
332   aFaceContext.Front.IsSpecular   = ((theAspect->FrontMaterial ()).ReflectionMode (Graphic3d_TOR_SPECULAR) ? 1 : 0);
333   aFaceContext.Front.IsEmission   = ((theAspect->FrontMaterial ()).ReflectionMode (Graphic3d_TOR_EMISSION) ? 1 : 0);
334
335   // Material type
336   const Graphic3d_MaterialAspect aFrontMat = theAspect->FrontMaterial ();
337   Standard_Boolean isFrontPhys = aFrontMat.MaterialType (Graphic3d_MATERIAL_PHYSIC);
338   aFaceContext.Front.IsPhysic = (isFrontPhys ? 1 : 0 );
339
340   // Specular Color
341   aFaceContext.Front.ColorSpec.r = float (((theAspect->FrontMaterial ()).SpecularColor ()).Red ());
342   aFaceContext.Front.ColorSpec.g = float (((theAspect->FrontMaterial ()).SpecularColor ()).Green ());
343   aFaceContext.Front.ColorSpec.b = float (((theAspect->FrontMaterial ()).SpecularColor ()).Blue ());
344
345   // Ambient color
346   aFaceContext.Front.ColorAmb.r = float (((theAspect->FrontMaterial ()).AmbientColor ()).Red ());
347   aFaceContext.Front.ColorAmb.g = float (((theAspect->FrontMaterial ()).AmbientColor ()).Green ());
348   aFaceContext.Front.ColorAmb.b = float (((theAspect->FrontMaterial ()).AmbientColor ()).Blue ());
349
350   // Diffuse color
351   aFaceContext.Front.ColorDif.r = float (((theAspect->FrontMaterial ()).DiffuseColor ()).Red ());
352   aFaceContext.Front.ColorDif.g = float (((theAspect->FrontMaterial ()).DiffuseColor ()).Green ());
353   aFaceContext.Front.ColorDif.b = float (((theAspect->FrontMaterial ()).DiffuseColor ()).Blue ());
354
355   // Emissive color
356   aFaceContext.Front.ColorEms.r = float (((theAspect->FrontMaterial ()).EmissiveColor ()).Red ());
357   aFaceContext.Front.ColorEms.g = float (((theAspect->FrontMaterial ()).EmissiveColor ()).Green ());
358   aFaceContext.Front.ColorEms.b = float (((theAspect->FrontMaterial ()).EmissiveColor ()).Blue ());
359
360   aFaceContext.Front.EnvReflexion = float ((theAspect->FrontMaterial ()).EnvReflexion());
361   aFaceContext.IsDef = 1;
362   aFaceContext.Texture.TextureMap   = theAspect->TextureMap();
363   aFaceContext.Texture.doTextureMap = theAspect->TextureMapState() ? 1 : 0;
364
365   Standard_Integer aPolyMode;
366   Standard_ShortReal aPolyFactor, aPolyUnits;
367   theAspect->PolygonOffsets (aPolyMode, aPolyFactor, aPolyUnits);
368   aFaceContext.PolygonOffsetMode   = aPolyMode;
369   aFaceContext.PolygonOffsetFactor = (Standard_ShortReal)aPolyFactor;
370   aFaceContext.PolygonOffsetUnits  = (Standard_ShortReal)aPolyUnits;
371
372   aFaceContext.ShaderProgram = theAspect->ShaderProgram();
373
374   SetAspect (aFaceContext);
375 }
376
377 // =======================================================================
378 // function : Render
379 // purpose  :
380 // =======================================================================
381 void OpenGl_AspectFace::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
382 {
383   theWorkspace->SetAspectFace (this);
384 }
385
386 // =======================================================================
387 // function : Release
388 // purpose  :
389 // =======================================================================
390 void OpenGl_AspectFace::Release (OpenGl_Context* theContext)
391 {
392   if (!myResources.Texture.IsNull())
393   {
394     if (theContext)
395     {
396       if (myResources.TextureId.IsEmpty())
397       {
398         theContext->DelayedRelease (myResources.Texture);
399       }
400       else
401       {
402         myResources.Texture.Nullify(); // we need nullify all handles before ReleaseResource() call
403         theContext->ReleaseResource (myResources.TextureId, Standard_True);
404       }
405     }
406     myResources.Texture.Nullify();
407   }
408   myResources.TextureId.Clear();
409   myResources.ResetTextureReadiness();
410
411   if (!myResources.ShaderProgram.IsNull()
412    && theContext)
413   {
414     theContext->ShaderManager()->Unregister (myResources.ShaderProgramId,
415                                              myResources.ShaderProgram);
416   }
417   myResources.ShaderProgramId.Clear();
418   myResources.ResetShaderReadiness();
419 }
420
421 // =======================================================================
422 // function : BuildTexture
423 // purpose  :
424 // =======================================================================
425 void OpenGl_AspectFace::Resources::BuildTexture (const Handle(OpenGl_Workspace)& theWS,
426                                                  const Handle(Graphic3d_TextureMap)& theTexture)
427 {
428   const Handle(OpenGl_Context)& aContext = theWS->GetGlContext();
429
430   // release old texture resource
431   if (!Texture.IsNull())
432   {
433     if (TextureId.IsEmpty())
434     {
435       aContext->DelayedRelease (Texture);
436       Texture.Nullify();
437     }
438     else
439     {
440       Texture.Nullify(); // we need nullify all handles before ReleaseResource() call
441       aContext->ReleaseResource (TextureId, Standard_True);
442     }
443   }
444
445   TextureId = theTexture.IsNull() ? THE_EMPTY_KEY : theTexture->GetId();
446
447   if (!theTexture.IsNull())
448   {
449     if (TextureId.IsEmpty() || !aContext->GetResource<Handle(OpenGl_Texture)> (TextureId, Texture))
450     {
451       Texture = new OpenGl_Texture (theTexture->GetParams());
452       Handle(Image_PixMap) anImage = theTexture->GetImage();
453       if (!anImage.IsNull())
454       {
455         Texture->Init (aContext, *anImage.operator->(), theTexture->Type());
456       }
457       if (!TextureId.IsEmpty())
458       {
459         aContext->ShareResource (TextureId, Texture);
460       }
461     }
462   }
463 }
464
465 // =======================================================================
466 // function : BuildShader
467 // purpose  :
468 // =======================================================================
469 void OpenGl_AspectFace::Resources::BuildShader (const Handle(OpenGl_Workspace)&        theWS,
470                                                 const Handle(Graphic3d_ShaderProgram)& theShader)
471 {
472   const Handle(OpenGl_Context)& aContext = theWS->GetGlContext();
473   if (!aContext->IsGlGreaterEqual (2, 0))
474   {
475     return;
476   }
477
478   // release old shader program resources
479   if (!ShaderProgram.IsNull())
480   {
481     aContext->ShaderManager()->Unregister (ShaderProgramId, ShaderProgram);
482     ShaderProgramId.Clear();
483     ShaderProgram.Nullify();
484   }
485   if (theShader.IsNull())
486   {
487     return;
488   }
489
490   aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram);
491 }