/* ui_galerkin.c: Galerkin Radiosity User Interface */ #include #include "galerkin.h" #include "galerkinP.h" #include "uit.h" #include "scene.h" #include "statistics.h" #include "canvas.h" #include "render.h" #include "vertex.h" #include "error.h" #include "scratch.h" static Widget galerkinControlPanel; /* The number of needed coefficients for radiance, received radiance and unshot * radiance may change after choosing another approximation order or iteration * method (unshot radiance is only needed for shooting e.g.). ReallocCoefficients() * traverses the element hierarchies of all patches and takes care of reallocating * space for the coefficients. */ static void ElementReallocCoefficientsRecursive(ELEMENT *elem) { ITERATE_REGULAR_SUBELEMENTS(elem, ElementReallocCoefficientsRecursive); ElementReallocCoefficients(elem); } static void PatchReallocCoefficients(PATCH *patch) { ElementReallocCoefficientsRecursive(TOPLEVEL_ELEMENT(patch)); } static void ReallocCoefficients(void) { CanvasPushMode(CANVASMODE_WORKING); PatchListIterate(Patches, PatchReallocCoefficients); CanvasPullMode(); } /* Interactions are kept with the source element for shooting and with the * receiver for gathering. When switching from shooting to gathering, the * interactions must be moved from receiver to source and vice versa. */ static void MoveInteractions(void) { Error("MoveInteractions", "Not yet implemented"); } static void IterationMethodCallback(Widget w, XtPointer client_data, XtPointer call_data) { int set = ((XmToggleButtonCallbackStruct *)call_data)->set; ITERATION_METHOD new_iteration_method = (ITERATION_METHOD)client_data; if (set == XmSET) { if (gal.iteration_method != new_iteration_method) { if (gal.iteration_method == SOUTHWELL) { /* Interactions are kept with the source element for shooting and with the * receiver for gathering. When switching from shooting to gathering, the * interactions must be moved from receiver to source and vice versa. */ MoveInteractions(); } else if (new_iteration_method == SOUTHWELL) { /* Switching from gathering to shooting is a bad idea. Shooting only converges * when starting with the selfemitted radiance as initial unshot and * total radiance. */ Warning(NULL, "Reinitialize the radiance computations"); } gal.iteration_method = new_iteration_method; ReallocCoefficients(); } } } static void ShaftCullModeCallback(Widget w, XtPointer client_data, XtPointer call_data) { int set = ((XmToggleButtonCallbackStruct *)call_data)->set; if (set == XmSET) gal.shaftcullmode = (SHAFTCULLMODE)client_data; } static void ClusteringStrategyCallback(Widget w, XtPointer client_data, XtPointer call_data) { int set = ((XmToggleButtonCallbackStruct *)call_data)->set; if (set == XmSET) gal.clustering_strategy = (CLUSTERING_STRATEGY)client_data; if (gal.iteration_nr > 0) Warning(NULL, "Reinitialize the radiance computations"); } static void ReallocScratchFBSizeCallback(Widget w, XtPointer client_data, XtPointer call_data) { if (gal.scratch && gal.iteration_nr > 0) { ScratchTerminate(); ScratchInit(); } } static void RcvCubatureCallback(Widget w, XtPointer client_data, XtPointer call_data) { SetCubatureRules(&gal.rcv3rule, &gal.rcv4rule, (CUBATURE_DEGREE)client_data); } static void SrcCubatureCallback(Widget w, XtPointer client_data, XtPointer call_data) { SetCubatureRules(&gal.src3rule, &gal.src4rule, (CUBATURE_DEGREE)client_data); } static void ErrorNormCallback(Widget w, XtPointer client_data, XtPointer call_data) { gal.error_norm = (ERROR_NORM)client_data; } static void BasisTypeCallback(Widget w, XtPointer client_data, XtPointer call_data) { BASIS_TYPE old_basis_type = gal.basis_type; gal.basis_type = (BASIS_TYPE)client_data; if (gal.basis_type != old_basis_type) ReallocCoefficients(); } typedef enum {HIERARCHICAL_REFINEMENT, IMPORTANCE, CLUSTERED, LAZY_LINKING, CONSTANT_RADIANCE, AMBIENT_RADIANCE, EXACT_VISIBILITY, MULTIRES_VISIBILITY} BOOLEAN_OPTION; static void BooleanOptionsCallback(Widget w, XtPointer client_data, XtPointer call_data) { int set = (((XmToggleButtonCallbackStruct *)call_data)->set == XmSET); switch ((BOOLEAN_OPTION)client_data) { case HIERARCHICAL_REFINEMENT: gal.hierarchical = set; break; case IMPORTANCE: gal.importance_driven = set; break; case CLUSTERED: gal.clustered = set; if (gal.iteration_nr > 0) Warning(NULL, "Reinitialize the radiance computations"); break; case LAZY_LINKING: gal.lazy_linking = set; break; case EXACT_VISIBILITY: gal.exact_visibility = set; break; case MULTIRES_VISIBILITY: gal.multires_visibility = set; break; case CONSTANT_RADIANCE: gal.use_constant_radiance = set; break; case AMBIENT_RADIANCE: gal.use_ambient_radiance = set; PatchListIterate(Patches, PatchRecomputeColor); RenderScene(); break; default: Fatal(2, "BooleanOptionsCallback", "Invalid client data %d", (int)client_data); } } static void Dismiss(Widget w, XtPointer client_data, XtPointer call_data) { XtUnmanageChild(w); } static void Reinit(Widget w, XtPointer client_data, XtPointer call_data) { if (CanvasGetMode() != CANVASMODE_WORKING) { CanvasPushMode(CANVASMODE_WORKING); SetRadianceMethod(&GalerkinRadiosity); CanvasPullMode(); RenderScene(); } else Error(NULL, "Interrupt computations first before re-initializing"); } static void ReRender(Widget w, XtPointer client_data, XtPointer call_data) { GalerkinRaycast((FILE *)NULL); } void CreateGalerkinControlPanel(void *parent_widget) { Widget form, form1, form2, subform, options, frame, temp; galerkinControlPanel = CreateDialog((Widget)parent_widget, "galerkinControlPanel"); form = CreateRowColumn(galerkinControlPanel, "galerkinControlForm"); /* two columns next to each other */ form1 = CreateRowColumn(form, "galerkinControlForm1"); form2 = CreateRowColumn(form, "galerkinControlForm2"); /* Galerkin control dialog title label */ CreateLabel(form1, "galerkinControlTitle"); /* iteration method frame */ frame = CreateFrame(form1, "galerkinIterationMethodFrame", "galerkinIterationMethodTitle"); subform = CreateRadioBox(frame, "galerkinIterationMethodMenu"); CreateToggleButton(subform, "galJacobiButton", (gal.iteration_method == JACOBI), IterationMethodCallback, (XtPointer)JACOBI); CreateToggleButton(subform, "galGaussSeidelButton", (gal.iteration_method == GAUSS_SEIDEL), IterationMethodCallback, (XtPointer)GAUSS_SEIDEL); CreateToggleButton(subform, "galSouthwellButton", (gal.iteration_method == SOUTHWELL), IterationMethodCallback, (XtPointer)SOUTHWELL); XtManageChild(subform); /* basis frame */ frame = CreateFrame(form1, "galerkinBasisFrame", "galerkinBasisTitle"); subform = CreateRowColumn(frame, "galerkinBasisForm"); options = CreateOptionMenu(subform, "galerkinBasisMenu", "galerkinBasisOptions"); CreateOptionButton(options, "galConstantBasisButton", (gal.basis_type == CONSTANT), BasisTypeCallback, (XtPointer)CONSTANT); CreateOptionButton(options, "galLinearBasisButton", (gal.basis_type == LINEAR), BasisTypeCallback, (XtPointer)LINEAR); CreateOptionButton(options, "galQuadraticBasisButton", (gal.basis_type == QUADRATIC), BasisTypeCallback, (XtPointer)QUADRATIC); CreateOptionButton(options, "galCubicBasisButton", (gal.basis_type == CUBIC), BasisTypeCallback, (XtPointer)CUBIC); XtManageChild(subform); /* shaftculling mode frame */ frame = CreateFrame(form2, "galerkinShaftCullModeFrame", "galerkinShaftCullModeTitle"); subform = CreateRadioBox(frame, "galerkinShaftCullModeMenu"); CreateToggleButton(subform, "galShaftCullNeverButton", (gal.shaftcullmode == NEVER_DO_SHAFTCULLING), ShaftCullModeCallback, (XtPointer)NEVER_DO_SHAFTCULLING); CreateToggleButton(subform, "galShaftCullRefineButton", (gal.shaftcullmode == DO_SHAFTCULLING_FOR_REFINEMENT), ShaftCullModeCallback, (XtPointer)DO_SHAFTCULLING_FOR_REFINEMENT); CreateToggleButton(subform, "galShaftCullAlwaysButton", (gal.shaftcullmode == ALWAYS_DO_SHAFTCULLING), ShaftCullModeCallback, (XtPointer)ALWAYS_DO_SHAFTCULLING); XtManageChild(subform); /* cubature rules frame */ frame = CreateFrame(form2, "galerkinCubatureFrame", "galerkinCubatureTitle"); subform = CreateRowColumn(frame, "galerkinCubatureForm"); options = CreateOptionMenu(subform, "galerkinRcvCubatureMenu", "galerkinRcvCubatureOptions"); CreateOptionButton(options, "galCrDeg1button", (gal.rcv_degree == DEGREE_1), RcvCubatureCallback, (XtPointer)DEGREE_1); CreateOptionButton(options, "galCrDeg2button", (gal.rcv_degree == DEGREE_2), RcvCubatureCallback, (XtPointer)DEGREE_2); CreateOptionButton(options, "galCrDeg3button", (gal.rcv_degree == DEGREE_3), RcvCubatureCallback, (XtPointer)DEGREE_3); CreateOptionButton(options, "galCrDeg4button", (gal.rcv_degree == DEGREE_4), RcvCubatureCallback, (XtPointer)DEGREE_4); CreateOptionButton(options, "galCrDeg5button", (gal.rcv_degree == DEGREE_5), RcvCubatureCallback, (XtPointer)DEGREE_5); CreateOptionButton(options, "galCrDeg6button", (gal.rcv_degree == DEGREE_6), RcvCubatureCallback, (XtPointer)DEGREE_6); CreateOptionButton(options, "galCrDeg7button", (gal.rcv_degree == DEGREE_7), RcvCubatureCallback, (XtPointer)DEGREE_7); CreateOptionButton(options, "galCrDeg8button", (gal.rcv_degree == DEGREE_8), RcvCubatureCallback, (XtPointer)DEGREE_8); CreateOptionButton(options, "galCrDeg9button", (gal.rcv_degree == DEGREE_9), RcvCubatureCallback, (XtPointer)DEGREE_9); CreateOptionButton(options, "galCrDeg3Pbutton", (gal.rcv_degree == DEGREE_3_PROD), RcvCubatureCallback, (XtPointer)DEGREE_3_PROD); CreateOptionButton(options, "galCrDeg5Pbutton", (gal.rcv_degree == DEGREE_5_PROD), RcvCubatureCallback, (XtPointer)DEGREE_5_PROD); CreateOptionButton(options, "galCrDeg7Pbutton", (gal.rcv_degree == DEGREE_7_PROD), RcvCubatureCallback, (XtPointer)DEGREE_7_PROD); options = CreateOptionMenu(subform, "galerkinSrcCubatureMenu", "galerkinSrcCubatureOptions"); CreateOptionButton(options, "galCrDeg1button", (gal.src_degree == DEGREE_1), SrcCubatureCallback, (XtPointer)DEGREE_1); CreateOptionButton(options, "galCrDeg2button", (gal.src_degree == DEGREE_2), SrcCubatureCallback, (XtPointer)DEGREE_2); CreateOptionButton(options, "galCrDeg3button", (gal.src_degree == DEGREE_3), SrcCubatureCallback, (XtPointer)DEGREE_3); CreateOptionButton(options, "galCrDeg4button", (gal.src_degree == DEGREE_4), SrcCubatureCallback, (XtPointer)DEGREE_4); CreateOptionButton(options, "galCrDeg5button", (gal.src_degree == DEGREE_5), SrcCubatureCallback, (XtPointer)DEGREE_5); CreateOptionButton(options, "galCrDeg6button", (gal.src_degree == DEGREE_6), SrcCubatureCallback, (XtPointer)DEGREE_6); CreateOptionButton(options, "galCrDeg7button", (gal.src_degree == DEGREE_7), SrcCubatureCallback, (XtPointer)DEGREE_7); CreateOptionButton(options, "galCrDeg8button", (gal.src_degree == DEGREE_8), SrcCubatureCallback, (XtPointer)DEGREE_8); CreateOptionButton(options, "galCrDeg9button", (gal.src_degree == DEGREE_9), SrcCubatureCallback, (XtPointer)DEGREE_9); CreateOptionButton(options, "galCrDeg3Pbutton", (gal.src_degree == DEGREE_3_PROD), SrcCubatureCallback, (XtPointer)DEGREE_3_PROD); CreateOptionButton(options, "galCrDeg5Pbutton", (gal.src_degree == DEGREE_5_PROD), SrcCubatureCallback, (XtPointer)DEGREE_5_PROD); CreateOptionButton(options, "galCrDeg7Pbutton", (gal.src_degree == DEGREE_7_PROD), SrcCubatureCallback, (XtPointer)DEGREE_7_PROD); XtManageChild(subform); /* accuracy control frame */ frame = CreateFrame(form2, "galerkinAccuracyFrame", "galerkinAccuracyTitle"); subform = CreateRowColumn(frame, "galerkinAccuracyForm"); /* options = CreateOptionMenu(subform, "galerkinErrorNormMenu", "galerkinErrorNormOptions"); CreateOptionButton(options, "galRadianceNormButton", (gal.error_norm == RADIANCE_ERROR), ErrorNormCallback, (XtPointer)RADIANCE_ERROR); CreateOptionButton(options, "galPowerNormButton", (gal.error_norm == POWER_ERROR), ErrorNormCallback, (XtPointer)POWER_ERROR); */ CreateFormEntry(subform, "galLinkErrorLabel", "galLinkErrorTextf", FET_FLOAT, (XtPointer)&gal.rel_link_error_threshold, NULL, 0); CreateFormEntry(subform, "galMinElemAreaLabel", "galMinElemAreaTextf", FET_FLOAT, (XtPointer)&gal.rel_min_elem_area, NULL, 0); XtManageChild(subform); /* visibility options frame */ /* frame = CreateFrame(form2, "galerkinVisibilityFrame", "galerkinVisibilityTitle"); subform = CreateRowColumn(frame, "galerkinVisibilityForm"); CreateToggleButton(subform, "galExactVisibilityButton", gal.exact_visibility, BooleanOptionsCallback, (XtPointer)EXACT_VISIBILITY); CreateToggleButton(subform, "galMultiResVisibilityButton", gal.multires_visibility, BooleanOptionsCallback, (XtPointer)MULTIRES_VISIBILITY); XtManageChild(subform); */ /* other options frame */ frame = CreateFrame(form1, "galerkinVariaFrame", "galerkinVariaTitle"); subform = CreateRowColumn(frame, "galerkinVariaForm"); CreateToggleButton(subform, "galHRButton", gal.hierarchical, BooleanOptionsCallback, (XtPointer)HIERARCHICAL_REFINEMENT); CreateToggleButton(subform, "galLazyLinkingButton", gal.lazy_linking, BooleanOptionsCallback, (XtPointer)LAZY_LINKING); CreateToggleButton(subform, "galClusteredButton", gal.clustered, BooleanOptionsCallback, (XtPointer)CLUSTERED); CreateToggleButton(subform, "galImportanceButton", gal.importance_driven, BooleanOptionsCallback, (XtPointer)IMPORTANCE); /* CreateToggleButton(subform, "galConstantRadianceButton", gal.use_constant_radiance, BooleanOptionsCallback, (XtPointer)CONSTANT_RADIANCE); */ CreateToggleButton(subform, "galAmbientRadianceButton", gal.use_ambient_radiance, BooleanOptionsCallback, (XtPointer)AMBIENT_RADIANCE); XtManageChild(subform); /* clustering frame */ frame = CreateFrame(form1, "galerkinClusteringFrame", "galerkinClusteringTitle"); subform = CreateRadioBox(frame, "galerkinClusteringStrategyMenu"); CreateToggleButton(subform, "galClusIsotropicButton", (gal.clustering_strategy == ISOTROPIC), ClusteringStrategyCallback, (XtPointer)ISOTROPIC); CreateToggleButton(subform, "galClusOrientedButton", (gal.clustering_strategy == ORIENTED), ClusteringStrategyCallback, (XtPointer)ORIENTED); CreateToggleButton(subform, "galClusZVisibilityButton", (gal.clustering_strategy == Z_VISIBILITY), ClusteringStrategyCallback, (XtPointer)Z_VISIBILITY); XtManageChild(subform); /* scratch renderer frame */ frame = CreateFrame(form2, "galerkinScratchRendererFrame", "galerkinScratchRendererTitle"); subform = CreateRowColumn(frame, "galerkinScratchRendererForm"); CreateFormEntry(subform, "galScratchFBSizeLabel", "galMaxScratchFBSizeTextf", FET_INTEGER, (XtPointer)&gal.scratch_fb_size, NULL, 0); CreatePushButton(subform, "galScratchFBReallocButton", ReallocScratchFBSizeCallback, (XtPointer)NULL); XtManageChild(subform); XtManageChild(form1); XtManageChild(form2); XtManageChild(form); XtAddCallback(galerkinControlPanel, XmNokCallback, Dismiss, (XtPointer)NULL); /* unmanage the cancel button */ temp = XmMessageBoxGetChild(galerkinControlPanel, XmDIALOG_CANCEL_BUTTON); XtUnmanageChild(temp); CreatePushButton(galerkinControlPanel, "galerkinReinitButton", Reinit, (XtPointer)NULL); CreatePushButton(galerkinControlPanel, "galerkinRerenderButton", ReRender, (XtPointer)NULL); } void ShowGalerkinControlPanel(void) { if (galerkinControlPanel) XtManageChild(galerkinControlPanel); else Error("ShowGalerkinControlPanel", "Control panel not created yet"); } void HideGalerkinControlPanel(void) { if (galerkinControlPanel) XtUnmanageChild(galerkinControlPanel); else Error("HideGalerkinControlPanel", "Control panel not created yet"); }