diff options
author | Thomas White <taw@physics.org> | 2010-06-24 16:48:32 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2012-02-22 15:26:51 +0100 |
commit | e2a154ddefd961a79437cdac79fb5e46cda4a855 (patch) | |
tree | a9e236120d56b39df546826b4efa0ecfc5ca0ec8 /src | |
parent | ac5c6c8bcf1b870b4049aeb290f4af3c49086076 (diff) |
Move POV-ray stuff to a new file
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.in | 5 | ||||
-rw-r--r-- | src/povray.c | 281 | ||||
-rw-r--r-- | src/povray.h | 22 | ||||
-rw-r--r-- | src/render_hkl.c | 265 |
5 files changed, 312 insertions, 263 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5a9cd309..259542fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,7 @@ powder_plot_SOURCES = powder_plot.c cell.c utils.c image.c hdf5-file.c \ detector.c powder_plot_LDADD = @LIBS@ -render_hkl_SOURCES = render_hkl.c cell.c reflections.c utils.c +render_hkl_SOURCES = render_hkl.c cell.c reflections.c utils.c povray.c render_hkl_LDADD = @LIBS@ calibrate_detector_SOURCES = calibrate_detector.c utils.c hdf5-file.c image.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 403e790e..950b5789 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -108,7 +108,7 @@ am_process_hkl_OBJECTS = process_hkl.$(OBJEXT) sfac.$(OBJEXT) \ process_hkl_OBJECTS = $(am_process_hkl_OBJECTS) process_hkl_DEPENDENCIES = am_render_hkl_OBJECTS = render_hkl.$(OBJEXT) cell.$(OBJEXT) \ - reflections.$(OBJEXT) utils.$(OBJEXT) + reflections.$(OBJEXT) utils.$(OBJEXT) povray.$(OBJEXT) render_hkl_OBJECTS = $(am_render_hkl_OBJECTS) render_hkl_DEPENDENCIES = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) @@ -261,7 +261,7 @@ powder_plot_SOURCES = powder_plot.c cell.c utils.c image.c hdf5-file.c \ detector.c powder_plot_LDADD = @LIBS@ -render_hkl_SOURCES = render_hkl.c cell.c reflections.c utils.c +render_hkl_SOURCES = render_hkl.c cell.c reflections.c utils.c povray.c render_hkl_LDADD = @LIBS@ calibrate_detector_SOURCES = calibrate_detector.c utils.c hdf5-file.c image.c \ filters.c peaks.c detector.c cell.c diffraction.c \ @@ -393,6 +393,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/likelihood.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pattern_sim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peaks.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/povray.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powder_plot.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process_hkl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reflections.Po@am__quote@ diff --git a/src/povray.c b/src/povray.c new file mode 100644 index 00000000..69e5b3cc --- /dev/null +++ b/src/povray.c @@ -0,0 +1,281 @@ +/* + * povray.c + * + * Invoke POV-ray + * + * (c) 2006-2010 Thomas White <taw@physics.org> + * + * Part of CrystFEL - crystallography with a FEL + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "cell.h" +#include "utils.h" + + +#define MAX_PROC (256) + + +int povray_render_animation(UnitCell *cell, double *ref, + unsigned int *c, unsigned int nproc) +{ + FILE *fh; + double asx, asy, asz; + double bsx, bsy, bsz; + double csx, csy, csz; + pid_t pids[MAX_PROC]; + float max; + int i; + signed int h, k, l; + + if ( (nproc > MAX_PROC) || (nproc < 1) ) { + ERROR("Number of processes must be a number between 1 and %i\n", + MAX_PROC); + return 1; + } + + fh = fopen("render.pov", "w"); + fprintf(fh, "/* POV-Ray scene written by CrystFEL */\n\n"); + fprintf(fh, "#include \"colors.inc\"\n"); + fprintf(fh, "#include \"textures.inc\"\n\n"); + fprintf(fh, "global_settings {\n"); + fprintf(fh, " assumed_gamma 1.0\n"); + fprintf(fh, " ambient_light 5.0\n"); + fprintf(fh, "}\n\n"); + + /* First quarter */ + fprintf(fh, "#if ( (clock >= 0) & (clock <= 124) )\n"); + fprintf(fh, "camera { location <0.0, -3.0, 0.0>" + " sky z direction 1.1*y\n" + " right -x*(image_width/image_height)\n" + " look_at <0.0, 0.0, 0.0> }\n\n"); + fprintf(fh, "#end\n"); + + /* Second quarter */ + fprintf(fh, "#if ( (clock >= 125) & (clock <= 249) )\n"); + fprintf(fh, "camera { location <0.0," + " -(2.0+cos(radians((clock-125)*(180/125)))), 0.0>" + " sky z direction 1.1*y\n" + " right -x*(image_width/image_height)\n" + " look_at <0.0, 0.0, 0.0> }\n\n"); + fprintf(fh, "#end\n"); + + /* Third quarter */ + fprintf(fh, "#if ( (clock >= 250) & (clock <= 374) )\n"); + fprintf(fh, "camera { location <0.0, -1.0, 0.0>" + " sky z direction 1.1*y\n" + " right -x*(image_width/image_height)\n" + " look_at <0.0, 0.0, 0.0> }\n\n"); + fprintf(fh, "#end\n"); + + /* Fourth quarter */ + fprintf(fh, "#if ( (clock >= 375) & (clock <= 500) )\n"); + fprintf(fh, "camera { location <0.0," + " -(2.0+cos(radians((clock-375)*(180/125)+180))), 0.0>" + " sky z direction 1.1*y\n" + " right -x*(image_width/image_height)\n" + " look_at <0.0, 0.0, 0.0> }\n\n"); + fprintf(fh, "#end\n"); + + fprintf(fh, "light_source { <-3.0 -3.0 3.0> White }\n"); + fprintf(fh, "light_source { <+3.0 -3.0 3.0> White }\n"); + fprintf(fh, "light_source { <0.0, -3.0, 0.0> 2*White }\n"); + fprintf(fh, "plane {z,-2.0 pigment { rgb <0.0, 0.0, 0.1> } }\n"); + fprintf(fh, "plane {-z,-2.0 pigment { rgb <0.0, 0.0, 0.05> } }\n\n"); + + cell_get_reciprocal(cell, &asx, &asy, &asz, + &bsx, &bsy, &bsz, + &csx, &csy, &csz); + + fprintf(fh, "#declare WCA = (720/19);\n"); + fprintf(fh, "#declare WCL = (360/8.5);\n"); + fprintf(fh, "#declare TA = (4.875);\n"); + fprintf(fh, "#declare TB = (1.125);\n"); + + fprintf(fh, "#declare TRANS = \n"); + fprintf(fh, "transform {\n"); + + /* First half */ + + /* Acceleration */ + fprintf(fh, "#if ( clock <= 24 )\n" + "rotate <0, 0, 0.5*WCA*(clock/25)*(clock/25)>\n" + "#end\n" + + /* Cruise */ + "#if ( (clock >= 25) & (clock <= 224) )\n" + "rotate <0, 0, (WCA/2)+WCA*((clock-25)/25)>\n" + "#end\n" + + /* Overlap */ + + /* Deceleration */ + "#if ( (clock >= 225) & (clock <= 274) )\n" + "rotate <0, 0, 360-WCA + WCA*((clock-225)/25) " + " - 0.5*(WCA/2)*((clock-225)/25)*((clock-225)/25) >\n" + "#end\n" + + /* Acceleration */ + "#if ( (clock >= 225) & (clock <= 274) )\n" + "rotate <0.5*(WCL/2)*((clock-225)/25)*((clock-225)/25), 0, 0>\n" + "#end\n" + + /* Second half */ + + /* Cruise */ + "#if ( (clock >= 275) & (clock <= 396) )\n" + "rotate <WCL + WCL*((clock-275)/25), 0, 0>\n" + "#end\n" + + /* Deceleration to pause */ + "#if ( (clock >= 397) & (clock <= 421) )\n" + "rotate <(1+TA)*WCL+ WCL*((clock-397)/25) " + " - 0.5*WCL*((clock-397)/25)*((clock-397)/25), 0, 0 >\n" + "#end\n" + + /* Acceleration after pause */ + "#if ( (clock >= 422) & (clock <= 446) )\n" + "rotate <(1.5+TA)*WCL" + " + 0.5*WCL*((clock-422)/25)*((clock-422)/25), 0, 0>\n" + "#end\n" + + /* Final Cruise */ + "#if ( (clock >= 447) & (clock <= 474) )\n" + "rotate <(2+TA)*WCL + WCL*((clock-447)/25), 0, 0>\n" + "#end\n" + + /* Final Deceleration */ + "#if ( (clock >= 475) & (clock <= 499) )\n" + "rotate <(2+TA+TB)*WCL + WCL*((clock-475)/25) " + " - 0.5*WCL*((clock-475)/25)*((clock-475)/25), 0, 0 >\n" + "#end\n"); + + fprintf(fh, "}\n"); + + max = 0.5e6; + for ( h=-INDMAX; h<INDMAX; h++ ) { + for ( k=-INDMAX; k<INDMAX; k++ ) { + for ( l=-INDMAX; l<INDMAX; l++ ) { + + float radius, x, y, z; + int s; + float val, p, r, g, b, trans; + + if ( !lookup_count(c, h, k, l) ) continue; + + val = lookup_intensity(ref, h, k, l); + + val = max-val; + + s = val / (max/6); + p = fmod(val, max/6); + p /= (max/6); + + r = 0; g = 0; b = 0; + + if ( (val < 0.0) ) { + s = 0; + p = 1.0; + } + if ( (val > max) ) { + s = 6; + } + switch ( s ) { + case 0 : /* Black to blue */ + r = 0.0; g = 0.0; b = p; + break; + case 1 : /* Blue to green */ + r = 0.0; g = p; b = 1.0-p; + break; + case 2 : /* Green to red */ + r =p; g = 1.0-p; b = 0.0; + break; + case 3 : /* Red to Orange */ + r = 1.0; g = 0.5*p; b = 0.0; + break; + case 4 : /* Orange to Yellow */ + r = 1.0; g = 0.5 + 0.5*p; b = 0.0; + break; + case 5 : /* Yellow to White */ + r = 1.0; g = 1.0; b = 1.0*p; + break; + case 6 : /* Pixel has hit the maximum value */ + r = 1.0; g = 1.0; b = 1.0; + break; + } + + val = max-val; + + if ( val <= 0.0 ) continue; + radius = 0.1 * sqrt(sqrt(val))/1e2; + radius -= 0.005; + if ( radius > 0.03 ) radius = 0.03; + if ( radius <= 0.0 ) continue; + trans = (0.03-radius)/0.03; + radius += 0.002; + + x = asx*h + bsx*k + csx*l; + y = asy*h + bsy*k + csy*l; + z = asz*h + bsz*k + csz*l; + + fprintf(fh, "sphere { <%.5f, %.5f, %.5f>, %.5f " + "texture{pigment{color rgb <%f, %f, %f>" + " transmit %f} " + "finish { reflection 0.1 } } \n" + "transform { TRANS }\n" + "}\n", + x/1e9, y/1e9, z/1e9, radius, r, g, b, trans); + + } + } + } + + fprintf(fh, "\n"); + fclose(fh); + + for ( i=0; i<nproc; i++ ) { + + pids[i] = fork(); + if ( !( (pids[i] != 0) && (pids[i] != -1) ) ) { + if ( pids[i] == -1 ) { + ERROR("fork() failed.\n"); + } else { + + char minf[256]; + char maxf[256]; + float nf, xf, nsec; + + nsec = 500.0 / (float)nproc; + nf = nsec * (float)i; + xf = (nsec * (float)i + nsec) - 1.0; + + snprintf(minf, 255, "+SF%i", (int)nf); + snprintf(maxf, 255, "+EF%i", (int)xf); + + /* Forked successfully, child process */ + execlp("povray", "", "+W1024", "+H768", + "+Irender.pov", "+Orender.png", + "+KFI0", "+KFF499", "+KI0", "+KF499", + minf, maxf, "-D", NULL); + + } + } /* else start the next one */ + } + + for ( i=0; i<nproc; i++ ) { + int r; + waitpid(pids[i], &r, 0); + } + + return 0; +} diff --git a/src/povray.h b/src/povray.h new file mode 100644 index 00000000..f60bd566 --- /dev/null +++ b/src/povray.h @@ -0,0 +1,22 @@ +/* + * povray.c + * + * Invoke POV-ray + * + * (c) 2006-2010 Thomas White <taw@physics.org> + * + * Part of CrystFEL - crystallography with a FEL + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef POVRAY_H +#define POVRAY_H + +extern int povray_render_animation(UnitCell *cell, double *ref, + unsigned int *c, unsigned int nproc); + +#endif /* POVRAY_H */ diff --git a/src/render_hkl.c b/src/render_hkl.c index e8590096..e1498b6c 100644 --- a/src/render_hkl.c +++ b/src/render_hkl.c @@ -20,23 +20,19 @@ #include <string.h> #include <unistd.h> #include <getopt.h> -#include <sys/types.h> -#include <sys/wait.h> #include <cairo.h> #include <cairo-pdf.h> #include "utils.h" #include "reflections.h" - - -#define MAX_PROC (256) +#include "povray.h" static void show_help(const char *s) { printf("Syntax: %s [options] <file.hkl>\n\n", s); printf( -"Render intensity lists using POV-ray.\n" +"Render intensity lists in various ways.\n" "\n" " -h, --help Display this help message.\n" " --povray Render a 3D animation using POV-ray.\n" @@ -172,253 +168,6 @@ out: } -static void povray_render_animation(UnitCell *cell, double *ref, - unsigned int *c, unsigned int nproc) -{ - FILE *fh; - double asx, asy, asz; - double bsx, bsy, bsz; - double csx, csy, csz; - pid_t pids[MAX_PROC]; - float max; - int i; - signed int h, k, l; - - fh = fopen("render.pov", "w"); - fprintf(fh, "/* POV-Ray scene written by CrystFEL */\n\n"); - fprintf(fh, "#include \"colors.inc\"\n"); - fprintf(fh, "#include \"textures.inc\"\n\n"); - fprintf(fh, "global_settings {\n"); - fprintf(fh, " assumed_gamma 1.0\n"); - fprintf(fh, " ambient_light 5.0\n"); - fprintf(fh, "}\n\n"); - - /* First quarter */ - fprintf(fh, "#if ( (clock >= 0) & (clock <= 124) )\n"); - fprintf(fh, "camera { location <0.0, -3.0, 0.0>" - " sky z direction 1.1*y\n" - " right -x*(image_width/image_height)\n" - " look_at <0.0, 0.0, 0.0> }\n\n"); - fprintf(fh, "#end\n"); - - /* Second quarter */ - fprintf(fh, "#if ( (clock >= 125) & (clock <= 249) )\n"); - fprintf(fh, "camera { location <0.0," - " -(2.0+cos(radians((clock-125)*(180/125)))), 0.0>" - " sky z direction 1.1*y\n" - " right -x*(image_width/image_height)\n" - " look_at <0.0, 0.0, 0.0> }\n\n"); - fprintf(fh, "#end\n"); - - /* Third quarter */ - fprintf(fh, "#if ( (clock >= 250) & (clock <= 374) )\n"); - fprintf(fh, "camera { location <0.0, -1.0, 0.0>" - " sky z direction 1.1*y\n" - " right -x*(image_width/image_height)\n" - " look_at <0.0, 0.0, 0.0> }\n\n"); - fprintf(fh, "#end\n"); - - /* Fourth quarter */ - fprintf(fh, "#if ( (clock >= 375) & (clock <= 500) )\n"); - fprintf(fh, "camera { location <0.0," - " -(2.0+cos(radians((clock-375)*(180/125)+180))), 0.0>" - " sky z direction 1.1*y\n" - " right -x*(image_width/image_height)\n" - " look_at <0.0, 0.0, 0.0> }\n\n"); - fprintf(fh, "#end\n"); - - fprintf(fh, "light_source { <-3.0 -3.0 3.0> White }\n"); - fprintf(fh, "light_source { <+3.0 -3.0 3.0> White }\n"); - fprintf(fh, "light_source { <0.0, -3.0, 0.0> 2*White }\n"); - fprintf(fh, "plane {z,-2.0 pigment { rgb <0.0, 0.0, 0.1> } }\n"); - fprintf(fh, "plane {-z,-2.0 pigment { rgb <0.0, 0.0, 0.05> } }\n\n"); - - cell_get_reciprocal(cell, &asx, &asy, &asz, - &bsx, &bsy, &bsz, - &csx, &csy, &csz); - - fprintf(fh, "#declare WCA = (720/19);\n"); - fprintf(fh, "#declare WCL = (360/8.5);\n"); - fprintf(fh, "#declare TA = (4.875);\n"); - fprintf(fh, "#declare TB = (1.125);\n"); - - fprintf(fh, "#declare TRANS = \n"); - fprintf(fh, "transform {\n"); - - /* First half */ - - /* Acceleration */ - fprintf(fh, "#if ( clock <= 24 )\n" - "rotate <0, 0, 0.5*WCA*(clock/25)*(clock/25)>\n" - "#end\n" - - /* Cruise */ - "#if ( (clock >= 25) & (clock <= 224) )\n" - "rotate <0, 0, (WCA/2)+WCA*((clock-25)/25)>\n" - "#end\n" - - /* Overlap */ - - /* Deceleration */ - "#if ( (clock >= 225) & (clock <= 274) )\n" - "rotate <0, 0, 360-WCA + WCA*((clock-225)/25) " - " - 0.5*(WCA/2)*((clock-225)/25)*((clock-225)/25) >\n" - "#end\n" - - /* Acceleration */ - "#if ( (clock >= 225) & (clock <= 274) )\n" - "rotate <0.5*(WCL/2)*((clock-225)/25)*((clock-225)/25), 0, 0>\n" - "#end\n" - - /* Second half */ - - /* Cruise */ - "#if ( (clock >= 275) & (clock <= 396) )\n" - "rotate <WCL + WCL*((clock-275)/25), 0, 0>\n" - "#end\n" - - /* Deceleration to pause */ - "#if ( (clock >= 397) & (clock <= 421) )\n" - "rotate <(1+TA)*WCL+ WCL*((clock-397)/25) " - " - 0.5*WCL*((clock-397)/25)*((clock-397)/25), 0, 0 >\n" - "#end\n" - - /* Acceleration after pause */ - "#if ( (clock >= 422) & (clock <= 446) )\n" - "rotate <(1.5+TA)*WCL" - " + 0.5*WCL*((clock-422)/25)*((clock-422)/25), 0, 0>\n" - "#end\n" - - /* Final Cruise */ - "#if ( (clock >= 447) & (clock <= 474) )\n" - "rotate <(2+TA)*WCL + WCL*((clock-447)/25), 0, 0>\n" - "#end\n" - - /* Final Deceleration */ - "#if ( (clock >= 475) & (clock <= 499) )\n" - "rotate <(2+TA+TB)*WCL + WCL*((clock-475)/25) " - " - 0.5*WCL*((clock-475)/25)*((clock-475)/25), 0, 0 >\n" - "#end\n"); - - fprintf(fh, "}\n"); - - max = 0.5e6; - for ( h=-INDMAX; h<INDMAX; h++ ) { - for ( k=-INDMAX; k<INDMAX; k++ ) { - for ( l=-INDMAX; l<INDMAX; l++ ) { - - float radius, x, y, z; - int s; - float val, p, r, g, b, trans; - - if ( !lookup_count(c, h, k, l) ) continue; - - val = lookup_intensity(ref, h, k, l); - - val = max-val; - - s = val / (max/6); - p = fmod(val, max/6); - p /= (max/6); - - r = 0; g = 0; b = 0; - - if ( (val < 0.0) ) { - s = 0; - p = 1.0; - } - if ( (val > max) ) { - s = 6; - } - switch ( s ) { - case 0 : /* Black to blue */ - r = 0.0; g = 0.0; b = p; - break; - case 1 : /* Blue to green */ - r = 0.0; g = p; b = 1.0-p; - break; - case 2 : /* Green to red */ - r =p; g = 1.0-p; b = 0.0; - break; - case 3 : /* Red to Orange */ - r = 1.0; g = 0.5*p; b = 0.0; - break; - case 4 : /* Orange to Yellow */ - r = 1.0; g = 0.5 + 0.5*p; b = 0.0; - break; - case 5 : /* Yellow to White */ - r = 1.0; g = 1.0; b = 1.0*p; - break; - case 6 : /* Pixel has hit the maximum value */ - r = 1.0; g = 1.0; b = 1.0; - break; - } - - val = max-val; - - if ( val <= 0.0 ) continue; - radius = 0.1 * sqrt(sqrt(val))/1e2; - radius -= 0.005; - if ( radius > 0.03 ) radius = 0.03; - if ( radius <= 0.0 ) continue; - trans = (0.03-radius)/0.03; - radius += 0.002; - - x = asx*h + bsx*k + csx*l; - y = asy*h + bsy*k + csy*l; - z = asz*h + bsz*k + csz*l; - - fprintf(fh, "sphere { <%.5f, %.5f, %.5f>, %.5f " - "texture{pigment{color rgb <%f, %f, %f>" - " transmit %f} " - "finish { reflection 0.1 } } \n" - "transform { TRANS }\n" - "}\n", - x/1e9, y/1e9, z/1e9, radius, r, g, b, trans); - - } - } - } - - fprintf(fh, "\n"); - fclose(fh); - - for ( i=0; i<nproc; i++ ) { - - pids[i] = fork(); - if ( !( (pids[i] != 0) && (pids[i] != -1) ) ) { - if ( pids[i] == -1 ) { - ERROR("fork() failed.\n"); - } else { - - char minf[256]; - char maxf[256]; - float nf, xf, nsec; - - nsec = 500.0 / (float)nproc; - nf = nsec * (float)i; - xf = (nsec * (float)i + nsec) - 1.0; - - snprintf(minf, 255, "+SF%i", (int)nf); - snprintf(maxf, 255, "+EF%i", (int)xf); - - /* Forked successfully, child process */ - execlp("povray", "", "+W1024", "+H768", - "+Irender.pov", "+Orender.png", - "+KFI0", "+KFF499", "+KI0", "+KF499", - minf, maxf, "-D", NULL); - - } - } /* else start the next one */ - } - - for ( i=0; i<nproc; i++ ) { - int r; - waitpid(pids[i], &r, 0); - } -} - - int main(int argc, char *argv[]) { int c; @@ -430,6 +179,7 @@ int main(int argc, char *argv[]) int config_zoneaxis = 0; unsigned int nproc = 1; char *pdb = NULL; + int r = 0; /* Long options */ const struct option longopts[] = { @@ -469,11 +219,6 @@ int main(int argc, char *argv[]) pdb = strdup("molecule.pdb"); } - if ( (nproc > MAX_PROC) || (nproc < 1) ) { - ERROR("Number of processes is invalid.\n"); - return 1; - } - infile = argv[optind]; cell = load_cell_from_pdb(pdb); @@ -489,7 +234,7 @@ int main(int argc, char *argv[]) } if ( config_povray ) { - povray_render_animation(cell, ref, cts, nproc); + r = povray_render_animation(cell, ref, cts, nproc); } else if ( config_zoneaxis ) { render_za(cell, ref, cts); } else { @@ -498,5 +243,5 @@ int main(int argc, char *argv[]) free(pdb); - return 0; + return r; } |