]> git.pld-linux.org Git - packages/povray.git/blob - povray-pvm.patch
- use proper types on AMD64
[packages/povray.git] / povray-pvm.patch
1 diff -Naur source.ori/optin.c source/optin.c
2 --- source.ori/optin.c  Sat Jun 30 01:49:21 2001
3 +++ source/optin.c      Sat Jun 30 10:01:28 2001
4 @@ -30,7 +30,8 @@
5  *
6  *  Written by CEY 4/94 based on existing code and INI code from CDW.
7  *
8 -*  ---
9 +*  Modified Oct. 96 by Deischi for PVM
10 +*  Modified Jun 2001 by Agaran for conditional PVM build
11  *
12  * Modification by Thomas Willhalm, March 1999, used with permission.
13  *
14 @@ -56,7 +57,9 @@
15  #include "targa.h"
16  #include "userio.h"
17  #include "png_pov.h"
18 -
19 +#ifdef USE_PVM
20 +#include "pvm.h"
21 +#endif
22  
23  
24  /*****************************************************************************
25 @@ -187,7 +190,23 @@
26  
27    { BITS_PER_COLOR_OP, "Bits_Per_Color" },
28    { BITS_PER_COLOUR_OP, "Bits_Per_Colour" },
29 +#ifdef USE_PVM
30 + { INCLUDE_INI_OP, "Include_Ini" },
31 +
32 + /* new options for PVM-Pov */
33 + { PVM_TASKS_OP, "PVM_Tasks" },
34 + { PVM_WIDTH_OP, "PVM_Width" },
35 + { PVM_HEIGHT_OP, "PVM_Height" },
36 + { PVM_SLAVE_OP, "PVM_Slave" },
37 + { PVM_ARCH_OP, "PVM_Arch" },
38 + { PVM_NICE_OP, "PVM_Nice" },
39 + { PVM_WD_OP, "PVM_WD" },
40 + { PVM_HOSTS_OP, "PVM_Hosts" },
41 + { PVM_USE_OP, "PVM" }
42 +
43 +#else
44    { INCLUDE_INI_OP, "Include_Ini" }
45 +#endif
46  };
47  
48  static char temp_string[3]="\0\0";
49 @@ -229,7 +248,8 @@
50  *
51  * CHANGES
52  *
53 -*   -
54 +*   Oct. 1996: Added options for PVMPOV [Deischi]
55 +*   jun 2001: conditional pvm
56  *
57  ******************************************************************************/
58  
59 @@ -560,6 +580,44 @@
60      case INCLUDE_INI_OP:
61        value[0] = '\0';
62        return value;
63 +#ifdef USE_PVM
64 +     /*
65 +      * PVM Options
66 +      */
67 +    case PVM_TASKS_OP:
68 +        sprintf(value, "%d", PvmTasks);
69 +        return value;
70 +    case PVM_WIDTH_OP:
71 +        sprintf(value, "%d", PvmChunkWidth);
72 +        return value;
73 +    case PVM_HEIGHT_OP:
74 +        sprintf(value, "%d", PvmChunkHeight);
75 +        return value;
76 +    case PVM_SLAVE_OP:
77 +        strncpy(value, PvmSlavename ? PvmSlavename : "", 128);
78 +        return value;
79 +    case PVM_ARCH_OP:
80 +        sprintf(value, "%s", PvmArch);
81 +        return value;
82 +    case PVM_NICE_OP:
83 +        sprintf(value, "%d", PvmNice);
84 +        return value;
85 +    case PVM_WD_OP:
86 +        strncpy(value, PvmWorkingDir, PATH_MAX);
87 +        return value;
88 +    case PVM_HOSTS_OP:
89 +        if(PvmHosts) {
90 +          int i;
91 +          for(i=0; i < PvmHostsN; i++) {
92 +              strncat(value, PvmHosts[i], 128);
93 +              strncat(value, ",", 128);
94 +          }
95 +        }
96 +        return value;
97 +    case PVM_USE_OP:
98 +        sprintf(value, "%s", (PvmTasks || PvmSlave) ? "On" : "Off");
99 +        return value;
100 +#endif
101  
102      default:
103        Error("Unknown INI option in Write_INI.");
104 @@ -602,6 +660,8 @@
105  *   Sep 1994 : Added options for union splitting, vista/light buffer. [DB]
106  *   Jan 1995 : Added options for histogram grid. [CJC]
107  *   Feb 1995 : Added options for console/file redirection and .INI writing [SCD]
108 +*   Oct 1996 : Added options for PVMPOV [Deischi]
109 +*   jun 2001 : added condititional build for pvm
110  *
111  ******************************************************************************/
112  
113 @@ -1024,13 +1084,67 @@
114        break;
115  
116      /*  "N" option flag is used by networking (multi-processor) options.
117 -
118 -    case 'N':
119 -    case 'n':
120 -
121 -      break;
122 -
123       */
124 +#ifdef USE_PVM
125 +       /* 
126 +        * PVM-POV 
127 +        *
128 +        */
129 +   case 'N': /* switches used for PVMPOV */
130 +   case 'n':
131 +       switch( Option_String[1]) {
132 +       case '\0':      /* Start one slave/available PVM host */
133 +         process_variable(PVM_USE_OP, Add_Option ? "On" : "Off");
134 +         break;
135 +       case 'a': /* Select a particular architecture to run the slaves on */
136 +       case 'A':
137 +         process_variable(PVM_ARCH_OP, Option_String+2);
138 +         break;
139 +       case 'n': /* Sets the niceness (priority) level */
140 +       case 'N':
141 +         process_variable(PVM_NICE_OP, Option_String+2);
142 +         break;
143 +       case 't': /* Sets the number of tasks to run.  Default is 1 per host */
144 +       case 'T':
145 +         process_variable(PVM_TASKS_OP, Option_String+2);
146 +         break;
147 +       case 'h': /* The height of a single grid block, in pixels */
148 +       case 'H':
149 +         process_variable(PVM_HEIGHT_OP, Option_String+2);
150 +         break;
151 +       case 'w': /* The width of a single grid block, in pixels */
152 +       case 'W':
153 +         process_variable(PVM_WIDTH_OP, Option_String+2);
154 +         break;          
155 +       case 's': /* specify the name of the slave */
156 +       case 'S':
157 +         process_variable(PVM_SLAVE_OP, Option_String+2);
158 +         break;
159 +       case 'd': /* specify working directory for the slaves */
160 +       case 'D':
161 +          process_variable(PVM_WD_OP, Option_String+2);
162 +          break;
163 +         /* Internal sub-option "-nI" indicates a PVM slave task.
164 +          * This will be appended to current argv string, so it will override
165 +          * the previous -nxx options. */
166 +       case 'i':
167 +       case 'I':
168 +         PvmTasks = 1;
169 +         PvmSlave = 1;
170 +         
171 +         if (chdir(&Option_String[2]) < 0) {
172 +             fprintf(stderr, "Slave cannot cd to %s.\n", &Option_String[2]);
173 +             exit(1);
174 +         }
175 +         break;
176 +         
177 +       default:
178 +         fprintf(stderr, "Illegal +N%c switch setting\n", Option_String[1]);
179 +         break;
180 +       } /* switch */
181 +       break;
182 +#endif
183 +     
184  
185      case 'O':
186      case 'o':
187 @@ -1262,7 +1376,8 @@
188  *
189  * CHANGES
190  *
191 -*   -
192 +*   Oct 1996 : Added options for PVMPOV [Deischi]
193 +*   jun 2001 : conditional build for pvm
194  *
195  ******************************************************************************/
196  
197 @@ -1445,21 +1560,36 @@
198        return;
199  
200      case END_COLUMN_OP:
201 +#ifdef USE_PVM
202 +       /* tw */
203 +      if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF) {
204 +#else
205        { /* tw */
206        if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF)
207 +#endif
208          if(floatval > 0.0 && floatval <= 1.0)
209          {
210            opts.Last_Column = -1;
211            opts.Last_Column_Percent = floatval;
212          }
213 +#ifdef USE_PVM
214 +        else {
215 +         opts.Last_Column = (int) floatval; }
216 +#else
217          else
218            opts.Last_Column = (int) floatval;
219 +#endif
220        } /* tw */
221        return;
222  
223      case END_ROW_OP:
224 +#ifdef USE_PVM
225 +       /* tw */
226 +      if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF) {
227 +#else
228        { /* tw */ 
229        if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF)
230 +#endif
231          if(floatval > 0.0 && floatval <= 1.0)
232          {
233            opts.Last_Line = -1;
234 @@ -1831,6 +1961,86 @@
235          Error ("Could not open Include_Ini='%s'.\n", value);
236        }
237        return;
238 +
239 +#ifdef USE_PVM
240 +      /* 
241 +       * Options for PVMPOV
242 +       */
243 +   case PVM_TASKS_OP:
244 +       if (sscanf(value, "%d", &PvmTasks) != 1 || PvmTasks < 1) { 
245 +         PvmTasks = 9999;   /* Try to start one slave/available PVM host */
246 +       } 
247 +       return;
248
249 +   case PVM_WIDTH_OP:
250 +       if (sscanf(value, "%d", &PvmChunkWidth) != 1 || PvmChunkWidth < 4)
251 +         PvmChunkWidth = PVM_DEFAULT_GRID_WIDTH;
252 +       return;
253
254 +   case PVM_HEIGHT_OP:
255 +       if (sscanf(value, "%d", &PvmChunkHeight) != 1 || PvmChunkHeight < 4)
256 +         PvmChunkHeight = PVM_DEFAULT_GRID_HEIGHT;
257 +       return;
258 +         
259 +   case PVM_SLAVE_OP:
260 +       PvmSlavename = POV_MALLOC( sizeof(char)*(strlen(value)+1), 
261 +                                "PVM Slavename");
262 +       strcpy(PvmSlavename, value);
263 +       return;
264 +         
265 +   case PVM_ARCH_OP:
266 +       strncpy(PvmArch,value,19);
267 +       PvmArch[19] = '\0';
268 +         
269 +       if (PvmTasks < 1)
270 +         PvmTasks = 9999;   /* Try to start one slave/available PVM host */
271 +       return;
272
273 +   case PVM_NICE_OP:
274 +       if (sscanf(value, "%d", &PvmNice) != 1 || PvmNice < 0) {
275 +         PvmNice = PVM_DEFAULT_NICE;
276 +       }
277 +       return;
278 +
279 +   case PVM_WD_OP:
280 +       strncpy(PvmWorkingDir, value, PATH_MAX);
281 +       return;
282 +
283 +   case PVM_HOSTS_OP: {
284 +       char * c = value;
285 +       char * c2;
286 +       int n;
287 +
288 +       PvmHostsN = 1;                  /* count number of names */
289 +       while((c = strchr(c, ',')) != NULL) {
290 +          c ++;
291 +          PvmHostsN ++;
292 +       }
293 +       PvmHosts = (char**)POV_MALLOC( sizeof(char*) * PvmHostsN, "PvmHosts");
294 +
295 +       c = value;
296 +       c2 = strchr(c,',');
297 +       for(i=0; i < PvmHostsN; i++) {
298 +          n = (c2) ? c2 - c : strlen(c);
299 +          PvmHosts[i] = (char*)POV_MALLOC( sizeof(char) * (n + 1), "PvmHosts[i]");
300 +          strncpy(PvmHosts[i], c, n);
301 +          PvmHosts[i][n] = '\0';
302 +
303 +          if(c2) c = c2 + 1;
304 +          c2 = strchr(c, ',');
305 +       }
306 +
307 +       PvmTasks = PvmHostsN;
308 +
309 +       return;
310 +
311 +   }
312 +   case PVM_USE_OP:
313 +       PvmTasks = istrue(value) ? 9999 : 0;
314 +       return;
315 +
316 +#endif 
317 +
318  
319      default:
320        Warning(0.0,"Unimplemented INI '%s'.\n",Option_Variable[variable].Token_Name);
321 diff -Naur source.ori/optin.h source/optin.h
322 --- source.ori/optin.h  Sat Jun 30 01:49:21 2001
323 +++ source/optin.h      Sat Jun 30 03:43:53 2001
324 @@ -19,6 +19,10 @@
325  * DKBTrace was originally written by David K. Buck.
326  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
327  *
328 +*
329 +* Oct 1996 : Added options for PVMPOV [Deischi]
330 +* Jun 2001 : Added conditional build for PVM Support [Agaran]
331 +*
332  *****************************************************************************/
333  
334  
335 @@ -131,6 +135,19 @@
336    BITS_PER_COLOR_OP,
337    BITS_PER_COLOUR_OP,
338    INCLUDE_INI_OP,
339 +
340 +#ifdef USE_PVM
341 +  /* new options for PVMPOV */
342 +  PVM_TASKS_OP,
343 +  PVM_WIDTH_OP,
344 +  PVM_HEIGHT_OP,
345 +  PVM_SLAVE_OP,
346 +  PVM_ARCH_OP,
347 +  PVM_NICE_OP,
348 +  PVM_WD_OP,
349 +  PVM_HOSTS_OP,
350 +  PVM_USE_OP,
351 +#endif
352  
353    MAX_OPTION
354  } INI_OP;
355 diff -Naur source.ori/optout.c source/optout.c
356 --- source.ori/optout.c Sat Jun 30 01:49:21 2001
357 +++ source/optout.c     Sat Jun 30 09:25:02 2001
358 @@ -19,6 +19,9 @@
359  * DKBTrace was originally written by David K. Buck.
360  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
361  *
362 +* Oct 1996 : Added options for PVMPOV [Deischi]
363 +* jun 2001 : added conditional build for pvm
364 +*
365  *****************************************************************************/
366  
367  #include <ctype.h>
368 @@ -65,8 +68,9 @@
369  #include "povray.h"
370  #include "optin.h"
371  #include "optout.h"
372 -
373 -
374 +#ifdef USE_PVM
375 +#include "pvm.h"
376 +#endif
377  
378  /*****************************************************************************
379  * Local preprocessor defines
380 @@ -611,6 +615,9 @@
381  *   Dec 1994 : Changed to show options depending on parameter n. [DB]
382  *
383  *   Feb 1995 : Changed to terminate only if f != 0. [DB]
384 +*   
385 +*   Oct 1996 : Added options from PVMPOV [Deischi]
386 +*   Jun 2001 : conditional build for pvm
387  *
388  ******************************************************************************/
389  
390 @@ -640,7 +647,12 @@
391        Banner("    4     Output Options - file related\n");
392        Banner("    5     Tracing Options\n");
393        Banner("    6     Animation Options\n");
394 +#ifdef USE_PVM
395 +      Banner("    7     PVM Options\n");
396 +      Banner("    8     Redirecting Options\n");
397 +#else
398        Banner("    7     Redirecting Options\n");
399 +#endif
400  
401        break;
402  
403 @@ -767,6 +779,40 @@
404  
405        break;
406  
407 +#ifdef USE_PVM
408 +    /* PVM options. */
409 +
410 +    case 7:
411 +
412 +      Banner("\n");
413 +      Banner("PVM options\n");
414 +      Banner("\n");
415 +      Banner("  N         = Turn on PVM\n");
416 +      Banner("  NTnnn     = Spawn number of tasks\n");
417 +      Banner("  NAs       = Spawn only on architecture\n");
418 +      Banner("  NWnnn     = Width of each chunk\n");
419 +      Banner("  NHnnn     = Height of each chunk\n");
420 +      Banner("  NNnnn     = Niceness of slaves\n");
421 +      Banner("  NSs       = Name of slaves (executable)\n");
422 +      Banner("  NDnnn     = Name of the working directory\n");
423 +      Banner("  pvm_hosts = n,n,..  = List of hostnames to use\n");
424 +      Banner("\n");
425 +
426 +    /* Redirecting options. */
427 +
428 +      Banner("\n");
429 +      Banner("Redirecting options\n");
430 +      Banner("\n");
431 +      Banner("  GI<name>= write all .INI parameters to file name\n");
432 +      Banner("  Gx<name>= write stream x to console and/or file name\n");
433 +      Banner("            GA - All streams (except status)\n");
434 +      Banner("            GD - Debug stream\n");
435 +      Banner("            GF - Fatal stream\n");
436 +      Banner("            GR - Render stream\n");
437 +      Banner("            GS - Statistics stream\n");
438 +      Banner("            GW - Warning stream\n");
439 +#else 
440 +
441      /* Redirecting options. */
442  
443      case 7:
444 @@ -782,6 +828,7 @@
445        Banner("            GR - Render stream\n");
446        Banner("            GS - Statistics stream\n");
447        Banner("            GW - Warning stream\n");
448 +#endif
449  
450        break;
451  
452 @@ -867,7 +914,8 @@
453  *
454  * CHANGES
455  *
456 -*   -
457 +*   Oct 1996 : Added options from PVMPOV [Deischi]
458 +*   Jun 2001 : Added conditional build for PVM Support [Agaran]
459  *
460  ******************************************************************************/
461  
462 @@ -1089,6 +1137,26 @@
463    }
464  
465    Render_Info("\n");
466 +#if USE_PVM
467 +  if(PvmTasks) {
468 +      int i;
469 +      Render_Info("PVM Options\n");
470 +      Render_Info("  Block Width....%8d", PvmChunkWidth);
471 +      Render_Info("  Block Height...%8d\n", PvmChunkHeight);
472 +      Render_Info("  PVM Tasks......%8d\n", PvmTasks);
473 +      Render_Info("  PVM Nice.......%8d\n", PvmNice);
474 +      Render_Info("  PVM Arch....... %s\n", PvmArch);
475 +      Render_Info("  PVM Slave...... %s\n", PvmSlavename ? PvmSlavename : "");
476 +      Render_Info("  PVM WorkingDir. %s\n", PvmWorkingDir);
477 +      if(PvmHosts) {
478 +        Render_Info("  Pvm Hosts......");
479 +        for(i=0; i < PvmHostsN; i++) {
480 +            Render_Info(" %s", PvmHosts[i]);
481 +        }
482 +        Render_Info("\n");
483 +      }
484 +  }
485 +#endif
486  
487    /* Print redirecting options. */
488  
489 diff -Naur source.ori/optout.h source/optout.h
490 --- source.ori/optout.h Sat Jun 30 01:49:21 2001
491 +++ source/optout.h     Sat Jun 30 02:17:45 2001
492 @@ -19,6 +19,10 @@
493  * DKBTrace was originally written by David K. Buck.
494  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
495  *
496 +* Oct 1996 : Added options for PVMPOV [Deischi]
497 +* May 1999 : Changed code to work with POVRAY 3.1e [Flierl]
498 +* Jun 2001 : conditional build for PVM [agaran]
499 +*
500  *****************************************************************************/
501  
502  
503 @@ -36,12 +40,19 @@
504  #define POV_RAY_VERSION "3.1g"
505  
506  #define DISTRIBUTION_MESSAGE_1 "This is an unofficial version compiled by:"
507 +#ifdef USE_PVM
508 +#define DISTRIBUTION_MESSAGE_2 "Jakob Flierl <flierl@luga.de> - PVMPOV Version 3.1e.2"
509 +#else
510  #define DISTRIBUTION_MESSAGE_2 "FILL IN NAME HERE........................."
511 +#endif
512  #define DISTRIBUTION_MESSAGE_3 "The POV-Ray Team(tm) is not responsible for supporting this version."
513  
514  /* Number of help pages (numbered 0 to MAX_HELP_PAGE). */
515 -
516 +#ifdef USE_PVM
517 +#define MAX_HELP_PAGE 8
518 +#else
519  #define MAX_HELP_PAGE 7
520 +#endif
521  
522  
523  
524 diff -Naur source.ori/povray.c source/povray.c
525 --- source.ori/povray.c Sat Jun 30 01:49:21 2001
526 +++ source/povray.c     Sat Jun 30 09:55:32 2001
527 @@ -20,6 +20,10 @@
528  * DKBTrace was originally written by David K. Buck.
529  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
530  *
531 +* Oct 1996 : Added options for PVMPOV [Deischi]
532 +* May 1999 : Changed code to work with POVRAY 3.1e [Flierl]
533 +* Jun 2001 : Added conditional build for PVM [Agaran]
534 +*
535  *****************************************************************************/
536  
537  #include <ctype.h>
538 @@ -69,7 +73,9 @@
539  #include "userio.h"     /*Error,Warning,Init_Text_Streams*/
540  #include "lbuffer.h"
541  #include "vbuffer.h"
542 -
543 +#ifdef USE_PVM
544 +#include "pvm.h"
545 +#endif
546  
547  /*****************************************************************************
548  * Local preprocessor defines
549 @@ -157,9 +163,15 @@
550  static void fix_up_rendering_window (void);
551  static void fix_up_animation_values (void);
552  static void fix_up_scene_name (void);
553 +#ifdef USE_PVM
554 +void set_output_file_handle (void);
555 +void setup_output_file_name (void);
556 +void open_output_file (void);
557 +#else
558  static void set_output_file_handle (void);
559  static void setup_output_file_name (void);
560  static void open_output_file (void);
561 +#endif
562  static void FrameRender (void);
563  static void init_statistics (COUNTER *);
564  static void sum_statistics (COUNTER *, COUNTER *);
565 @@ -192,7 +204,8 @@
566  *
567  * CHANGES
568  *
569 -*   -
570 +*   Oct 1996 : Added PVM Support [Deischi]
571 +*   Jun 2001 : Added conditional build for PVM Support [Agaran]
572  *
573  ******************************************************************************/
574  
575 @@ -262,17 +275,31 @@
576    }
577  #endif
578  
579 +#ifdef USE_PVM
580 +  /* If slave, turn off certain optiongs */
581 +  if ( PvmSlave)
582 +      opts.Options &= ~(DISPLAY | VERBOSE);
583 +#endif
584 +
585    /* Strip path and extension off input name to create scene name */
586    fix_up_scene_name ();
587    
588    /* Redirect text streams [SCD 2/95] */
589    Open_Text_Streams();
590  
591 +#ifdef USE_PVM
592 +  if ( !PvmSlave) {
593 +      /* Write .INI file [SCD 2/95] */
594 +      Write_INI_File();
595 +
596 +      ALT_WRITE_INI_FILE
597 +  }
598 +#else
599    /* Write .INI file [SCD 2/95] */
600    Write_INI_File();
601    
602    ALT_WRITE_INI_FILE
603 -
604 +#endif
605    /* Make sure clock is okay, validate animation parameters */
606    fix_up_animation_values();
607  
608 @@ -282,9 +309,18 @@
609    /* Set output file handle for options screen. */
610    set_output_file_handle();
611  
612 +#ifdef USE_PVM
613 +  /* Initialize PVM master */
614 +  if ( !PvmSlave && PvmTasks)
615 +      Pvm_Master_Init(argc, argv);
616 +
617 +  /* Print options used. */
618 +  if ( !PvmSlave)
619 +      Print_Options();
620 +#else
621    /* Print options used. */
622    Print_Options();
623 -  
624 +#endif
625    /* BEGIN SECTION */
626    /* VARIOUS INITIALIZATION THAT ONLY NEEDS TO BE DONE 1/EXECUTION */
627  
628 @@ -306,6 +342,32 @@
629  
630    /* END SECTION */
631  
632 +#ifdef USE_PVM
633 +  /* PVM Slave */
634 +  if (PvmSlave ) {
635 +      if( Pvm_Slave_Init() < 0)
636 +        return;
637 +
638 +      Pvm_Slave_Control();            /* get the first block to do */
639 +      while(PvmNextFrame <= opts.FrameSeq.FinalFrame) {
640 +        /* set frame number */
641 +        opts.FrameSeq.FrameNumber = PvmNextFrame;
642 +        /* calculate clock value */
643 +        opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock +
644 +            ((DBL)(opts.FrameSeq.FrameNumber - opts.FrameSeq.InitialFrame)) *
645 +            Clock_Delta;
646 +
647 +        FrameRender();
648 +      }
649 +
650 +      Pvm_Slave_Exit();
651 +
652 +      Terminate_POV(0);
653 +
654 +      MAIN_RETURN_STATEMENT
655 +  }
656 +#endif
657 +
658    /* Execute the first shell-out command */
659    Pre_Scene_Result=(POV_SHELLOUT_CAST)POV_SHELLOUT(PRE_SCENE_SHL);
660  
661 @@ -314,6 +376,26 @@
662    if (Pre_Scene_Result != ALL_SKIP_RET)
663    {
664       if (Pre_Scene_Result != SKIP_ONCE_RET)
665 +#ifdef USE_PVM
666 +       if(!PvmSlave && PvmTasks) {
667 +           START_TIME
668 +           Pvm_Master_Control();     /* distribute work,
669 +                                        and collect results,
670 +                                        call shellout commands */
671 +           STOP_TIME
672 +           trender = TIME_ELAPSED
673 +
674 +           PRINT_STATS(totalstats);
675 +       } else {
676 +         for (opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame,
677 +              opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock;
678 +
679 +              opts.FrameSeq.FrameNumber <= opts.FrameSeq.FinalFrame;
680 +
681 +              opts.FrameSeq.FrameNumber++,
682 +              opts.FrameSeq.Clock_Value += Clock_Delta)
683 +       {
684 +#else
685       {
686         for (opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame,
687              opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock;
688 @@ -323,6 +405,7 @@
689              opts.FrameSeq.FrameNumber++,
690              opts.FrameSeq.Clock_Value += Clock_Delta)
691         {
692 +#endif
693           setup_output_file_name();
694  
695           /* Execute a shell-out command before tracing */
696 @@ -348,7 +431,6 @@
697             }
698           }
699         }
700 -
701         /* Print total stats ... */
702   
703         if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME)
704 @@ -399,6 +481,8 @@
705  * CHANGES
706  *
707  *   Feb 1996: Make sure we are displaying when doing a mosaic preview [AED]
708 +*   Oct 1996: Added PVM support [Deischi]
709 +*   Jun 2001: Added conditional build for PVM Support [agaran]
710  *
711  ******************************************************************************/
712  
713 @@ -483,6 +567,30 @@
714    /* Save variable values. */
715    variable_store(STORE);
716  
717 +#ifdef USE_PVM
718 +  if( !PvmSlave) {
719 +
720 +  /* Open output file and if we are continuing an interrupted trace,
721 +   * read in the previous file settings and any data there.  This has to
722 +   * be done before any image-size related allocations, since the settings
723 +   * in a resumed file take precedence over that specified by the user. [AED]
724 +   */
725 +    open_output_file();
726 +
727 +    /* Start the display. */
728 +    if (opts.Options & DISPLAY)
729 +    {
730 +      Status_Info ("\nDisplaying...");
731 +
732 +      POV_DISPLAY_INIT(Frame.Screen_Width, Frame.Screen_Height);
733 +
734 +      Display_Started = TRUE;
735 +
736 +      /* Display vista tree. */
737 +      Draw_Vista_Buffer();
738 +    }
739 +  } /* !PvmTasks */
740 +#else
741    /* Open output file and if we are continuing an interrupted trace,
742     * read in the previous file settings and any data there.  This has to
743     * be done before any image-size related allocations, since the settings
744 @@ -502,15 +610,45 @@
745      /* Display vista tree. */
746      Draw_Vista_Buffer();
747    }
748 -
749 +#endif
750    /* Get things ready for ray tracing (misc init, mem alloc) */
751    Initialize_Renderer();
752 +#ifdef USE_PVM
753 +  /* If a PVM slave, re-assign Write_Line to PVM */
754 +  if (PvmSlave) {
755 +      Output_File_Handle->Write_Line_p = Pvm_Write_Line;
756 +  }
757 +#endif
758  
759    /* This had to be taken out of open_output_file() because we don't have
760     * the final image size until the output file has been opened, so we can't
761     * initialize the display until we know this, which in turn means we can't
762     * read the rendered part before the display is initialized. [AED]
763     */
764 +#ifdef USE_PVM
765 +  if (!PvmSlave) {
766 +    if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE))
767 +    {
768 +      Read_Rendered_Part(Actual_Output_Name);
769 +
770 +      if (opts.Last_Line > Frame.Screen_Height)
771 +        opts.Last_Line = Frame.Screen_Height;
772 +
773 +      if (opts.Last_Column > Frame.Screen_Width)
774 +        opts.Last_Column = Frame.Screen_Width;
775 +    }
776 +  } /* !PvmSlave */
777 +  if(PvmSlave || !PvmTasks) {
778 +    /* Get parsing time. */
779 +    STOP_TIME
780 +    tparse = TIME_ELAPSED
781 +
782 +    /* Get total parsing time. */
783 +    tparse_total += tparse;
784 +
785 +  } /* PvmSlave || !PvmTasks */
786 +
787 +#else
788    if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE))
789    {
790      Read_Rendered_Part(Actual_Output_Name);
791 @@ -529,7 +667,7 @@
792  
793    /* Get total parsing time. */
794    tparse_total += tparse;
795 -
796 +#endif
797    /* Store start time for trace. */
798    START_TIME
799  
800 @@ -547,7 +685,65 @@
801    POV_PRE_RENDER
802  
803    Status_Info ("\nRendering...\r");
804 +#ifdef USE_PVM
805 +  do {
806  
807 +    /* Macro for setting up any special FP options */
808 +    CONFIG_MATH
809 +
810 +    /* Ok, go for it - trace the picture. */
811 +
812 +    /* If radiosity preview has been done, we are continuing a trace, so it
813 +     * is important NOT to do the preview, even if the user requests it, as it
814 +     * will cause discontinuities in radiosity shading by (probably) calculating
815 +     * a few more radiosity values.
816 +     */
817 +    if ( !opts.Radiosity_Preview_Done )
818 +    {
819 +      if ( opts.Options & RADIOSITY )
820 +      {
821 +        /* Note that radiosity REQUIRES a mosaic preview prior to main scan */
822 +
823 +        Start_Tracing_Mosaic_Smooth(opts.PreviewGridSize_Start, opts.PreviewGridSize_End);
824 +      }
825 +      else
826 +      {
827 +        if (opts.Options & PREVIEW && opts.Options & DISPLAY)
828 +        {
829 +          Start_Tracing_Mosaic_Preview(opts.PreviewGridSize_Start, opts.PreviewGridSize_End);
830 +        }
831 +      }
832 +    }
833 +
834 +    switch (opts.Tracing_Method)
835 +    {
836 +      case 2 :
837 +
838 +        Start_Adaptive_Tracing();
839 +
840 +        break;
841 +
842 +      case 1 :
843 +      default:
844 +
845 +        Start_Non_Adaptive_Tracing();
846 +    }
847 +  } while(PvmSlave ? Pvm_Slave_Control() : 0);        /* ask for more work */
848 +
849 +  /* We're done. */
850 +
851 +  /* Record time so well spent before file close so it can be in comments  */
852 +  STOP_TIME
853 +  trender = TIME_ELAPSED
854 +
855 +  if(!PvmSlave) {
856 +      /* Close out our file */
857 +      if (Output_File_Handle)
858 +      {
859 +        Close_File(Output_File_Handle);
860 +      }
861 +  }
862 +#else
863    /* Macro for setting up any special FP options */
864    CONFIG_MATH
865  
866 @@ -600,7 +796,7 @@
867    {
868       Close_File(Output_File_Handle);
869    }
870 -
871 +#endif
872    Stage = STAGE_SHUTDOWN;
873  
874    POV_PRE_SHUTDOWN
875 @@ -626,6 +822,27 @@
876    /* Get total render time. */
877    trender_total += trender;
878  
879 +#ifdef USE_PVM
880 +  if(!PvmSlave) {
881 +    POV_DISPLAY_FINISHED
882 +
883 +    if ((opts.Options & DISPLAY) && Display_Started)
884 +    {
885 +      POV_DISPLAY_CLOSE
886 +
887 +      Display_Started = FALSE;
888 +    }
889 +
890 +    if (opts.histogram_on)
891 +      write_histogram (opts.Histogram_File_Name) ;
892 +  }
893 +  Status_Info("\nDone Tracing");
894 +
895 +  /* Print stats ... */
896 +  if(!PvmSlave)
897 +    PRINT_STATS(stats);
898 +
899 +#else
900    POV_DISPLAY_FINISHED
901  
902    if ((opts.Options & DISPLAY) && Display_Started)
903 @@ -642,7 +859,7 @@
904  
905    /* Print stats ... */
906    PRINT_STATS(stats);
907 -
908 +#endif
909    if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME)
910    {
911      /* Add them up */
912 @@ -1030,8 +1247,11 @@
913  *          NULL function pointer.
914  *
915  ******************************************************************************/
916 -
917 +#ifdef USE_PVM
918 +void set_output_file_handle()
919 +#else
920  static void set_output_file_handle()
921 +#endif
922  {
923    char *def_ext = NULL;
924    char temp[FILE_NAME_LENGTH];
925 @@ -1110,7 +1330,11 @@
926  *                  function appends a path separator on output.
927  *
928  ******************************************************************************/
929 +#ifdef USE_PVM
930 +void setup_output_file_name()
931 +#else
932  static void setup_output_file_name()
933 +#endif
934  {
935    char number_string[10];
936    char separator_string[2] = {FILENAME_SEPARATOR, 0} ;
937 @@ -1219,8 +1443,11 @@
938  *   -
939  *
940  ******************************************************************************/
941 -
942 +#ifdef USE_PVM
943 +void open_output_file()
944 +#else
945  static void open_output_file()
946 +#endif
947  {
948    int Buffer_Size;
949    
950 @@ -1378,12 +1605,18 @@
951    opts.Radiosity_Nearest_Count = 6;
952    opts.Radiosity_Recursion_Limit = 1;
953    opts.Radiosity_Quality = 6;     /* Q-flag value for light gathering */
954 +#ifdef USE_PVM
955 +  opts.Radiosity_File_ReadOnContinue = PvmSlave ? 0 : 1;
956 +  opts.Radiosity_File_SaveWhileRendering = PvmSlave ? 0 : 1; /* Don't save radiostiry cache with PVM */
957 +  opts.Radiosity_File_AlwaysReadAtStart = 0;
958 +  opts.Radiosity_File_KeepOnAbort = PvmSlave ? 0 : 1;
959 +#else
960    opts.Radiosity_File_ReadOnContinue = 1;
961    opts.Radiosity_File_SaveWhileRendering = 1;
962    opts.Radiosity_File_AlwaysReadAtStart = 0;
963    opts.Radiosity_File_KeepOnAbort = 1;
964 +#endif
965    opts.Radiosity_File_KeepAlways = 0;
966 -
967  
968    init_statistics(stats);
969    init_statistics(totalstats);
970 diff -Naur source.ori/pvm/PVMPOV.Changelog source/pvm/PVMPOV.Changelog
971 --- source.ori/pvm/PVMPOV.Changelog     Thu Jan  1 01:00:00 1970
972 +++ source/pvm/PVMPOV.Changelog Sun Sep 12 00:25:35 1999
973 @@ -0,0 +1,17 @@
974 + * 3.1e.2 [Jakob Flierl]
975 +  - fixed problem with the statistics collection in line 1331 of "pvm.c"
976 +  - minor changes in "sources/pvm/Makefile.aimk"
977 +  - updated documentation
978 +  - added "PVMPOV.Changelog" and "PVMPOV.benchmark"
979 + * 3.1e.1 [Jakob Flierl]
980 +  - applied the patch to POV-Ray version 3.1e
981 +  - fixed at least partially a memory bug in "render.c". Thanks to Michael
982 +    Eilers for solving this problem at least partially.
983 + * 3.0x [Harald Deischinger]
984 +  - applied the patch to POV-Ray 3.01 and 3.01
985 +  - several command line enhancements.
986 + * 2.2 to 2.9 [Andreas Dilger]
987 +  - changes in optin.h, optin.c, optout.h, optout.c,
988 +               povray.c, render.h, render.c
989 +  - added pvm/Makefile.aimk, pvm/pvm.h, pvm/pvm.c
990 + * Initial Version [Brad Kline, Cray Inc.]
991 diff -Naur source.ori/pvm/PVMPOV.benchmark source/pvm/PVMPOV.benchmark
992 --- source.ori/pvm/PVMPOV.benchmark     Thu Jan  1 01:00:00 1970
993 +++ source/pvm/PVMPOV.benchmark Sun Sep 12 00:25:35 1999
994 @@ -0,0 +1 @@
995 +Surf to http://www.haveland.com/povbench/ to look at some render statistics.
996 diff -Naur source.ori/pvm/PVMPOV.example source/pvm/PVMPOV.example
997 --- source.ori/pvm/PVMPOV.example       Thu Jan  1 01:00:00 1970
998 +++ source/pvm/PVMPOV.example   Sun Sep 12 00:25:35 1999
999 @@ -0,0 +1,283 @@
1000 +This file describes the command line options of PVMPOV, as well as the general
1001 +theory behind how it operates.
1002 +
1003 +Theory of Operation
1004 +-------------------
1005 +Using the PVM model, there is one master and many slave tasks. The master has 
1006 +the responsibility of issuing the work sections to the slaves, and receiving 
1007 +portions of the rendered sections back.  The master does not render anything
1008 +by itself.  The PVM component is only active if the user gives the "+N" option
1009 +to POV.  Otherwise, PVMPOV behaves the same as regular POV-Ray and runs a
1010 +single task only on the local machine.
1011 +
1012 +Valid POV-Ray command-line options relating to PVM are:
1013 +
1014 +    pvm=on
1015 +    +N      This is the default for starting PVMPOV.  One slave will be
1016 +           started on each available host, regardless of architecture, and
1017 +           the blocks will be 32x32 pixels in size.  The slaves will be
1018 +           started with a nice value of 5, which means they will run at a
1019 +           lower priority than other user jobs. 
1020 +    pvm=off
1021 +    -N      Turns of PVM support. PVMPOV now runs exactly as normal POV-Ray. 
1022 +            You should do this when there are still errors in your pov-file. 
1023 +            PVMPOV will not display error message otherwise.
1024 +
1025 +    pvm_tasks=xx
1026 +    +NTxx   Start xx tasks on the available PVM hosts.  This is usually only
1027 +            useful if debugging on a single machine, or for starting more
1028 +           than 1 task on multi-processor hosts.  If, for example, you have
1029 +           10 machines with 4 CPUs each, you could specify +nt40 to start 4
1030 +           processes on each host (and the OS will hopefully run 1 on each
1031 +           CPU).  
1032 +
1033 +            Note that PVM is stupid in the way it starts tasks, so if,
1034 +           in the previous example, one of the hosts has only one CPU, it will
1035 +           still have 4 slaves started on it. You can use the "pvm_hosts"
1036 +            option (see below) to control on which machines the tasks are 
1037 +            started.
1038 +
1039 +            Starting multiple tasks on a single processor will always be less 
1040 +            efficient than a single task because of context switching and extra 
1041 +            message passing.
1042 +
1043 +    pvm_arch=arch
1044 +    +NAarch Start the tasks only on the PVM architecture "arch". If +NT is not
1045 +           given, one task will be started on each of the hosts of the given
1046 +           architecture.
1047 +
1048 +    pvm_nice=xx
1049 +    +NNxx   Run the slaves at a niceness factor of xx.  The default niceness
1050 +           is 5.  In general, changing the niceness value will not affect
1051 +           performance very much, but may get others upset with you.  The
1052 +           nicest setting for pvmpov is 20, while the least nice setting is
1053 +           0.  Note that these values are always used even on systems that
1054 +           use nice values from 20-40.  See the installation document and
1055 +           the man page for nice for more information.
1056 +
1057 +    pvm_width=xx
1058 +    +NWxx   Change the width of the blocks to xx pixels.  The default width
1059 +           is 32 pixels.
1060 +
1061 +    pvm_height=xx
1062 +    +NHxx   Change the height of the blocks to xx pixels.  The default height
1063 +           is 32 pixels.
1064 +
1065 +            It is important to note that by varying the size of the grid
1066 +           sections, you can affect the performance of the rendering.  If you
1067 +           have particular renderings that are very complex in a small portion
1068 +           of the display, then a finer grain may help.  In this way, more of
1069 +           the tasks are able to migrate towards the grid sections that are
1070 +           more complex.  Conversely, if you have a shorter render or a 
1071 +           slower network, it may be advantageous to have larger blocks to
1072 +           reduce network overhead, as well as ensure the slaves are not idle
1073 +           waiting for blocks to render.
1074 +
1075 +           You must also consider overhead if using anti-aliasing.  Anti-
1076 +           aliasing requires the line segment above and below the grid section
1077 +           to be traced so that super-sampling may occur.  If the height of the
1078 +           grid is reduced in size, and anti-aliasing is turned on, your
1079 +           percentage of overhead goes up.  For example, setting a height of
1080 +           four (-NH4) using anti-aliasing would have more than 25% overhead.
1081 +           If the image size is not an integer multiple of the grid size, the
1082 +           edge blocks are smaller (ie extra pixels aren't rendered), so it
1083 +           is not necessary to evenly divide the image into blocks.
1084 +
1085 +     pvm_slave=slave
1086 +     +NSslave  Uses slave as filename for the slave tasks. If you do not 
1087 +            specify this option PVMPOV will use the current executable name
1088 +            also for the slaves. 
1089 +
1090 +            Using this option you can for example run the X11 version
1091 +            (x-pvmpov) as master (to display the results) and a version
1092 +            without any display support (pvmpov) as slaves.
1093 +
1094 +     pvm_wd=dir
1095 +     +NDdir Set the working directory for the slaves. By default PVMPOV
1096 +            tries to run the slaves in the same directory, as the master.
1097 +            But sometimes 'getcwd' gives misleading output (when automounting
1098 +            is used), or you simply want to run the slaves in some other
1099 +            directory, then you can use this option.
1100 +
1101 +     pvm_hosts=name1,name2,...
1102 +            Set the names of the hosts to use for slaves. Note, that there are
1103 +            not spaces allowed between the names!
1104 +         
1105 +            By default PVM distributes the processes in some order to the
1106 +            available machines. Sometimes the choice of PVM is not the best,
1107 +            so you can specify explicitly which machines to use. 
1108 +            
1109 +            You can use more tasks, then you specify here. You can use the
1110 +            options in this way: pvm_hosts=darkstar,darkstar,baby +nt6
1111 +            This will start 6 tasks (+nt6 must come after the pvm_hosts),
1112 +            4 on darkstar and 2 on baby.
1113 +   
1114 +
1115 +For example, if I wanted to distribute an 1024x768 rendering and use eight PVM 
1116 +tasks to do the work, I would use the +NT8 option, and let the PVM master 
1117 +define 768 32x32 sections.  Eight slave tasks would be launched, and when ready,
1118 +they would request work to do from the master.  The master then issues a column
1119 +and row range back to the requesting slave.
1120 +
1121 +% pvmpov +nt8 +w1024 +h768 +iskyvase.pov +oskyvase.tga
1122 +
1123 +As each quarter of a grid is completed, the slave sends it back to the
1124 +master, which buffers the incoming blocks until an entire line recieved, at
1125 +which time it writes the line to disk with the specified file format.  If
1126 +all slaves did perfectly equal work in this example, they would be issued 96
1127 +sections of work, and would have returned 384 messages of 32x8 pixels each.
1128 +
1129 +Note that the work issues are done essentially one at a time.  As each slave
1130 +starts up it requests a single block, and as it recieves a work request, it 
1131 +requests the next block.  In this way, effective load balancing can occur.
1132 +Tasks rendering the "easy" sections will eventually all migrate towards the
1133 +harder sections.  Seriously imbalanced distributions will be seen by widely
1134 +varying percentages shown at the end of the rendering, assuming all of the
1135 +hosts are identical.  Since each slave always has a block to be rendered, it
1136 +will be kept busy without waiting for the master to recieve its work request
1137 +and reply with a new block assignment.
1138 +
1139 +If for some reason any of the slaves are very slow, or they are interrupted
1140 +during their operation, their blocks are reassigned to other slaves after
1141 +all of the blocks have been assigned a first time.  This means that the render
1142 +can be completed quickly even if some of the slaves have problems, or if some
1143 +blocks have been assigned to slower slaves while the faster slaves are idle.
1144 +This will show up as some percentage of late blocks for that machine in the
1145 +statistics at the end.  Note that blocks will NOT be reassigned to slaves that
1146 +are significantly slower than average, in preference to reassigning it to a
1147 +faster slave when it becomes available.
1148 +
1149 +Since only complete lines are written out to disk, interrupted traces will
1150 +be restarted at the last complete line that was written to disk, regardless
1151 +of how many blocks were buffered by the master at the time.  However, it is
1152 +possible to re-start an interrupted trace in the same method as POV-Ray.
1153 +
1154 +Known bugs (and other limitations)
1155 +-------------------------------------
1156 +All of the slaves must to share the same file system as the master process,
1157 +and the source file must be mounted in the same location on each one.  This
1158 +may limit the number of hosts that can be used in some circumstances.
1159 +
1160 +The command line arguments for specifying hosts is not cumulative, so
1161 +
1162 +% pvmpov +naSUNMP +nt24 +n +iskyvase.pov +oskyvase.tga
1163 +
1164 +will not start 24 slaves on the multi-processor SUN system(s) (which may have
1165 +4 CPUs each), and then start 1 slave on each of the remaining systems.
1166 +
1167 +The statistics for the image being rendered may not be accurate if any of the
1168 +slaves is too slow, or stops for some reason.  As well, since some sections
1169 +may be rendered twice if the block is reassigned, the statistics will not be
1170 +exactly the same as if it were rendered on a single host.  The master only
1171 +waits a few seconds for statistics to arrive before printing them.
1172 +
1173 +The master does not parse the input file. Because of that it displays
1174 +no error messages concerning the input file. As long as your input file
1175 +still contains error you should disable PVM support (-N or pvm=off)
1176 +
1177 +Execution example (from version 2.9):
1178 +-------------------------------------
1179 +You first must have a PVM daemon launched on each machine that will be 
1180 +participating in the rendering.  Refer to the PVM 3.3 documentation.  The 
1181 +following is an example is from Jason Hough, and was generated on a group
1182 +of six Solaris based 4-processor SPARCstation 20s.  His home directory is
1183 +auto-mounted to all of these hosts.
1184 +
1185 +He keeps the pvm daemon installed in a directory called "bin", given by
1186 +"dx=./bin/pvmd3" relative to his home directory, and pvmpov is in various
1187 +subdirectories under "bin" (ie bin/SUN4, bin/SUNMP, bin/LINUX, etc.), given
1188 +by the executable path "ex=./bin", so his pvm.hosts file looks like:
1189 +
1190 +% cat pvm.hosts
1191 +glee    dx=./bin/pvmd3 ep=./bin
1192 +elation dx=./bin/pvmd3 ep=./bin
1193 +ecstasy dx=./bin/pvmd3 ep=./bin
1194 +bliss   dx=./bin/pvmd3 ep=./bin
1195 +delight dx=./bin/pvmd3 ep=./bin
1196 +rapture dx=./bin/pvmd3 ep=./bin
1197 +
1198 +Note that, by default, PVM looks for executables in $HOME/pvm3/bin/$PVM_ARCH,
1199 +and pvmd should be in $PVM_ROOT/lib, so if this is the case on your systems,
1200 +you don't need to have anything in your pvm.hosts file except the hostnames,
1201 +one per line.  An exception is RS6K, which needs the dx= no matter what.  See
1202 +the PVM documentation and/or the pvmd3 man page for more information on what
1203 +all of this means if you don't understand it.
1204 +
1205 +The following command launches the PVM daemons.
1206 +
1207 +% pvm pvm.hosts
1208 +3.3.7
1209 +t40001
1210 +pvm> conf
1211 +6 hosts, 1 data format
1212 +                   HOST     DTID     ARCH   SPEED
1213 +                   glee    40000    SUNMP    1000
1214 +                elation    80000    SUNMP    1000
1215 +                ecstasy    c0000    SUNMP    1000
1216 +                  bliss   100000    SUNMP    1000
1217 +                delight   140000    SUNMP    1000
1218 +                rapture   180000    SUNMP    1000
1219 +pvm> quit
1220 +
1221 +pvmd still running.
1222 +
1223 +Now that the PVM daemons are up and waiting for work to do, we can render.
1224 +Note that for these MP machines he forces pvmpov to start more tasks than
1225 +the default 1 per host, and uses a 64x64 block size:
1226 +
1227 +% pvmpov -Iskyvase.pov -Oskyvase.tga +nt24 +nw64 +nh64 +v
1228 +
1229 +POV-Ray Options in effect: +v1 +ft +mb25 +nt24 +nn5 +nw64 +nh64 +a0.300
1230 ++j1.000 +b999 +r3 -q9 -w1024 -h768 -s1 -e768
1231 +-k0.000 -mv2.0 -iskyvase.pov -oskyvase.tga 
1232 +   ...at least 13 tasks successfully spawned in time.
1233 +   ...Don't worry, more are on the way, I'm just not waiting
1234 +PVM Task Distribution: Tasks-24  Grid width-64  Grid height-64  Sections-192
1235 +
1236 +Waiting for slave stats.
1237 +
1238 +PVM Task Distribution Statistics:
1239 +           host name  [ done ] [ late ]           host name  [ done ] [ late ]
1240 +                glee  [ 4.17%] [ 0.00%]                glee  [ 4.17%] [ 0.00%]
1241 +                glee  [ 4.17%] [ 0.00%]                glee  [ 4.17%] [ 0.00%]
1242 +             elation  [ 4.69%] [ 0.00%]             elation  [ 4.17%] [ 0.00%]
1243 +             elation  [ 4.17%] [ 0.00%]             elation  [ 4.17%] [ 0.00%]
1244 +             ecstasy  [ 3.65%] [ 0.00%]             ecstasy  [ 4.69%] [ 0.00%]
1245 +             ecstasy  [ 4.69%] [ 0.00%]             ecstasy  [ 4.17%] [ 0.00%]
1246 +               bliss  [ 3.65%] [ 0.00%]               bliss  [ 4.17%] [ 0.00%]
1247 +               bliss  [ 4.69%] [ 0.00%]               bliss  [ 3.65%] [ 0.00%]
1248 +             delight  [ 3.65%] [ 0.00%]             delight  [ 4.17%] [ 0.00%]
1249 +             delight  [ 4.17%] [ 0.00%]             delight  [ 4.17%] [ 0.00%]
1250 +             rapture  [ 4.69%] [ 0.00%]             rapture  [ 4.17%] [ 0.00%]
1251 +             rapture  [ 4.17%] [ 0.00%]             rapture  [ 3.65%] [ 0.00%]
1252 +
1253 +
1254 +skyvase.pov statistics
1255 +--------------------------------------
1256 +Resolution 1024 x 768
1257 +# Rays:     3773743    # Pixels:      798720  # Pixels supersampled:      17381
1258 +  Ray->Shape Intersection Tests:
1259 +   Type             Tests    Succeeded   Percentage
1260 +  -----------------------------------------------------------
1261 +  Sphere          6304452     1170727       18.57
1262 +  Plane          63822062    35385552       55.44
1263 +  Quadric         6304452     2770858       43.95
1264 +  Cone            5918163     4839298       81.77
1265 +  Bounds          5918163     3152226       53.26
1266 +  Calls to Noise:      4327871
1267 +  Calls to DNoise:     5141872
1268 +  Shadow Ray Tests:   10498615     Blocking Objects Found:      254807
1269 +  Reflected Rays:      2818594
1270 +  Time For Trace:    0 hours  0 minutes 47.00 seconds
1271 +
1272 +------
1273 +NB: Note that for comparison purposes with other skyvase benchmarks that this
1274 +    is rendered at 1024x768 instead of the usual 640x480!
1275 +
1276 +Enjoy!
1277 +
1278 +Andreas Dilger
1279 +adilger@enel.ucalgary.ca
1280 +
1281 +Harald Deischinger
1282 +k3096e5@c210.edvz.uni-linz.ac.at
1283 diff -Naur source.ori/pvm/PVMPOV.general source/pvm/PVMPOV.general
1284 --- source.ori/pvm/PVMPOV.general       Thu Jan  1 01:00:00 1970
1285 +++ source/pvm/PVMPOV.general   Sun Sep 12 00:25:35 1999
1286 @@ -0,0 +1,98 @@
1287 +
1288 + - PVMPOV -                             written by Andreas Dilger, June 1 1995
1289 +                                                  and Harald Deischinger, 1997
1290 +                                                modified by Jakob Flierl, 1999
1291 +
1292 +
1293 +*****      NOTE - This is an UNOFFICIAL modification to POV-Ray 3.1e       *****
1294 +
1295 +** DO NOT SEND PROBLEM REPORTS TO THE POV TEAM REGARDING THESE MODIFICATIONS. **
1296 +
1297 +The author disclaims all warranties with regard to this software, including 
1298 +all implied warranties of merchant-ability and fitness.  The code is simply 
1299 +distributed as it is. 
1300 +
1301 +
1302 +General information
1303 +-------------------
1304 +
1305 +"I only ask that credit (or blame) is attributed to me for the original work."
1306 +                                                             - Brad Kline
1307 +
1308 +The original author of the PVM POV-Ray patch on which this is based is Brad
1309 +Kline, of Cray Research, Inc.  Because of problems running the original code at
1310 +my site, and a desire to learn more about PVM for my Master's work, I have
1311 +changed large portions to not only be more user-friendly about reporting
1312 +errors, but also hopefully more robust and faster.
1313 +                                                         - Andreas Dilger
1314 +
1315 +Because Andreas has other things to do, I have taken over the part of
1316 +PVMing POV-Ray 3.1. If you have problems with this program, don't be afraid
1317 +to ask me for help. 
1318 +
1319 +Please send me a mail, if you're using PVMPOV Version 3.1e.2. 
1320 +                                                           - Jakob Flierl
1321 +Contact
1322 +-------
1323 +email    : flierl@luga.de
1324 +
1325 +Important information/Problems
1326 +------------------------------
1327 +
1328 +* This version is not tested very vell, so it is very likely, that you
1329 +  find some errors - please tell me about them.
1330 +
1331 +  Especially the very time consuming new features (radiosity) are not
1332 +  really tested.
1333 +
1334 +* Shellout commands are always done by the master process.
1335 +
1336 +* Now PVMPOV also supports animations. PVMPOV computes multiply frames
1337 +  simultaniously, so it is not possible to do "recursive animations"
1338 +  (like the desk example in povscn/level3). You have to run PVMPOV extra
1339 +  for each frame.
1340 +
1341 +  All the pre-scene shellouts are done in the correct order, and the same
1342 +  for the post-scene shellouts. BUT for example the pre-scene shellout for 
1343 +  frame 2, will be executed before the post-scene shellout for frame 1!
1344 +
1345 +  Field Rendering (+UF) is not working yet.
1346 +
1347 +* The X11 display now displays everything. 
1348 +  There are no longer "forgotten blocks".
1349 +
1350 +* The master process of PVMPOV does not parse the input file. So you will
1351 +  NOT see errors in the .pov file - the slaves will simply not start.
1352 +  So you should turn off PVM support (pvm=off or -N) while developing your
1353 +  scene file.
1354 +
1355 +  You will also get no warning, if the slave can not find the input file.
1356 +  The slave will simply never ask for work. Check "/tmp/pvml.<uid>" for
1357 +  errors with the slaves.
1358 +
1359 +* You might get errors, that pvm can not find the executables for the slaves.
1360 +  You can solve this in lot's of ways. 
1361 +  - Start pvmpov with an absolute filename,
1362 +    e.g. '/usr/bin/pvmpov ...'
1363 +  - Specify the absolute path for the slaves, 
1364 +    e.g. 'pvmpov -NS/usr/bin/pvmpov ...'
1365 +    You can set this option in you '.povrayrc' file.
1366 +  - Move your executables into ~/pvm3/bin/ARCH
1367 +  - Use the 'ep=PATH' option in your hostfile 
1368 +  Read the PVM documentation for more information.
1369 +
1370 +* When using automount you might have the problem, that the slaves can't
1371 +  change to the working directory. Use the +ND (pvm_wd) option.
1372 +  Calling pvmpov with "+ND$PWD" should solve the problem.
1373 +
1374 +* For more information see "PVMPOV.1st_scene"
1375 +
1376 +Changed files
1377 +-------------
1378 +   optin.c             Accept new options for PVMPOV
1379 +   optin.h
1380 +   optout.c            Print new options and help texts for PVMPOV
1381 +   optout.h            
1382 +   povray.c            Major changes
1383 +   render.c            Minor changes
1384 +   render.h
1385 diff -Naur source.ori/pvm/PVMPOV.install source/pvm/PVMPOV.install
1386 --- source.ori/pvm/PVMPOV.install       Thu Jan  1 01:00:00 1970
1387 +++ source/pvm/PVMPOV.install   Sun Sep 12 00:25:35 1999
1388 @@ -0,0 +1,39 @@
1389 +How to compile and install PVMPOV. 
1390 +
1391 +COMPILE
1392 +-------
1393 +Before compiling PVMPOV you must me sure to have PVM installed correctly.
1394 +PVM is not included with this package. You have to download and install it
1395 +manually: http://www.epm.ornl.gov/pvm/pvm_home.html
1396 +
1397 +After that you can compile and install PVMPOV:
1398 +
1399 +  tar xvfz pvmpov-3.1e.?.tgz <- unpack the PVMPOV distfiles
1400 +  cd pvmpov3_1e_?
1401 +  tar xvfz ~/povuni_s.tgz    <- unpack the POV source from ftp://ftp.povray.org/
1402 +[POV-Ray versions 3.1e - 3.1g are reported to work fine with PVMPOV 3.e1.2.]
1403 +
1404 +  ./inst-pvm                 <- apply the PVMPOV patch
1405 +
1406 +[This script applies the patch and searches for any rejected files.
1407 +If there are any .rej-files the changes are not done correctly - 
1408 +you can try to do the changes by hand.]
1409 +
1410 +  cd pvmpov3_1e_?/povray31/source/pvm
1411 +
1412 +[You can choose:]
1413 +  aimk newunix               <- to create the UNIX text only binaries
1414 +  aimk newsvga               <- to create binaries for svgalib (Linux only)
1415 +  aimk newxwin               <- to create binaries using X11 to display
1416 +
1417 +This should create the executables 'pvmpov', 's-pvmpov' or 'x-pvmpov'.
1418 +
1419 +INSTALL
1420 +------
1421 +If your are running PVMPOV on a homogenous cluster, you can copy the
1422 +executables to "/usr/bin" and "/usr/X11R6/bin".
1423 +
1424 +Read "PVMPOV.example" to get started.
1425 +
1426 +Jakob Flierl, flierl@luga.de
1427 +May 1999
1428 diff -Naur source.ori/pvm/PVMPOV.radiosity source/pvm/PVMPOV.radiosity
1429 --- source.ori/pvm/PVMPOV.radiosity     Thu Jan  1 01:00:00 1970
1430 +++ source/pvm/PVMPOV.radiosity Sun Sep 12 00:25:35 1999
1431 @@ -0,0 +1,39 @@
1432 +[...] PVMPOV and radiosity:
1433 +
1434 +Radiosity is currently not working with PVMPOV; the resulting images look like
1435 +mosaics. There's a currently only a workaround suggested by Andreas Dilger:
1436 +
1437 +You must create a .rca file for the whole image [when rendering with the
1438 +radiosity option turned on], which I did manually by running
1439 +"pvmpov -n +qr +d +i <scene>.pov" and stopping the rendering when the mosaic
1440 +preview is complete, to give me <scene>.rca. Then I started a new
1441 +"pvmpov +c +qr +d +i <scene>.pov +nt2" on my 2 CPU system, and it rendered
1442 +the same image as letting "pvmpov -n +qr +d +i <scene>.pov" finish on 1 CPU.
1443 +The <scene>.rca file was readable by both slave systems because they were local,
1444 +but it would also be possible to use NFS for this, like normal PVMPOV.
1445 +This is some work to do manually, but it will ensure that the radiosity
1446 +will work properly with PVMPOV.
1447 +
1448 +[for programmers only:]
1449 +What needs to be done now is to have the PVMPOV master run the mosaic
1450 +preview for radiosity before the slave tasks start.  It looks like this
1451 +could be done in pvm.c:PvmStartFrame(), but the current design of the
1452 +master doesn't allow it to do any rendering because it does not parse
1453 +the scene, so it would need to be reworked to do this.
1454 +
1455 +In the old PVMPOV 2.2 design, the master did the parsing of the scene
1456 +file to ensure that the syntax was correct.  I think this is the better
1457 +design.  If radiosity is used, the master will render the preview before
1458 +the rendering is started on the slaves, so the .rca file is available.
1459 +If the master does the parsing, then it can also send the data to the
1460 +slaves via the POB binary file format through PVM (no NFS needed) so we
1461 +don't waste the time spent parsing the scene at the master.
1462 +
1463 +I think what needs to be done is modify povray.c so it doesn't call
1464 +Pvm_Master_Control() instead of FrameRender() in povray.c:398.  Then
1465 +FrameRender() should be modified to work with PVMPOV code, replacing
1466 +PvmStartFrame() entirely.  This will mean that PVMPOV will render one
1467 +frame at a time, which is OK I think, because it means that some of
1468 +the problems with PVMPOV 3.x will be fixed, like post-scene shellouts.
1469 +I think it will also make PVMPOV less complex also, because it only
1470 +has to work on 1 frame at a time.
1471 diff -Naur source.ori/pvm.c source/pvm.c
1472 --- source.ori/pvm.c    Thu Jan  1 01:00:00 1970
1473 +++ source/pvm.c        Sun Sep 12 00:25:35 1999
1474 @@ -0,0 +1,1556 @@
1475 +/****************************************************************************
1476 +*  pvm.c
1477 +*
1478 +*  This module implements the PVM control routines for PVM'd POVRAY.
1479 +*
1480 +*  This file was written by Brad Kline.  April 1994.
1481 +*                modified by Andreas Dilger Jan - May 1995
1482 +*                modified by Harald Deischinger, 1996 - 1997
1483 +*
1484 +*  NOTE - PVM is not supplied here.
1485 +*
1486 +*  You need the PVM 3.x libraries, include files, and PVMD daemons.
1487 +*  
1488 +*  PVM is available from the University of Tennessee, Knoxville, TN.
1489 +*
1490 +*  The author disclaims all warranties with regard to this software, 
1491 +*  including all implied warranties of merchant-ability and fitness. 
1492 +*  The code is simply distributed as it is.
1493 +*
1494 +* 970610 - New option PVM_WD. To specify a working directory for
1495 +*          the slaves. [Deischi]
1496 +*          New option PVM_Hosts. To give names for hosts to use
1497 +*          as slaves. [Deischi]
1498 +*
1499 +* 9704.. - changed to to animations, lots of changes
1500 +*          simplifications to the whole thing [Deischi]
1501 +*
1502 +* 96.... - Changed code to work with POVRAY 3.0 [Deischi]
1503 +*
1504 +* 950508 - Changed code that allocates blocks to be more robust.
1505 +*          Changed the write_line routines to hook into the existing routines.
1506 +*          Changed the slave startup processes to be more informative.
1507 +*
1508 +* 940511 - Remove code that tried to fit grid sections into whole parts. The
1509 +*          code now supports odd sized images.
1510 +*
1511 +*****************************************************************************/
1512 +#include <sys/time.h>
1513 +#include <sys/resource.h>
1514 +#include "frame.h"
1515 +#include "vector.h"
1516 +#include "povproto.h"
1517 +#include "frame.h"
1518 +#include "povray.h"
1519 +#include "render.h"
1520 +#include "optout.h"
1521 +#include "pvm3.h"
1522 +#include "pvm.h"
1523 +
1524 +
1525 +/* This distribution scheme breaks down the image into to two dimensional
1526 + * areas.  Each area has a designated grid control point.  The grid area
1527 + * is up to PvmChunkWidth (-NWxx) pixels wide by PvmChunkHeight (-NHxx)
1528 + * high. If one uses the default, then a grid section would be 32x32, or
1529 + * 1024 pixels.  In a 640x480 image, this would create 300 grid control
1530 + * points, and therefore 300 different sections to do work on (not lines.).
1531 + */
1532 +
1533 +/*
1534 + * clock value in shellout command is not working correctly
1535 + * timings are not displayed (and done) correctly
1536 + * statistics can be wrong
1537 + * continue trace might produce wrong results -- needs testing
1538 + */
1539 +
1540 +/*
1541 + * Global variables
1542 + */
1543 +char    PvmArch[20] = { 0 };
1544 +int     PvmChunkHeight = PVM_DEFAULT_GRID_HEIGHT;      /* height of a block */
1545 +int     PvmChunkWidth  = PVM_DEFAULT_GRID_WIDTH;       /* widht of a block */
1546 +int     PvmRowsToSend = 1;
1547 +int     PvmSlave = 0;
1548 +int     PvmTasks = 9999;
1549 +int     PvmNice = PVM_DEFAULT_NICE;
1550 +int     PvmMTid;
1551 +int     PvmBlockNum;
1552 +char *  PvmSlavename = NULL;
1553 +int    PvmNextFrame = 0;
1554 +char   PvmWorkingDir[PATH_MAX+1] = "";                 /* PVM Working Directory */
1555 +char ** PvmHosts = NULL;
1556 +int    PvmHostsN = 0;
1557 +
1558 +/*
1559 + * local functions
1560 + */
1561 +static void PvmSpawnError PARAMS((int));
1562 +static void PvmSpawnTidError PARAMS((int));
1563 +static void PvmSpawn PARAMS((void));
1564 +static void PvmCheckFirst PARAMS((void));
1565 +static void PvmInitSlaveStat PARAMS((void));
1566 +static void PvmInitFrameStat PARAMS((void));
1567 +
1568 +static int PvmMasterReceive PARAMS((void));
1569 +static void PvmIdentifySlave PARAMS((void));
1570 +static void PvmSendWork PARAMS((int block));
1571 +static void PvmReassignWork PARAMS((int block));
1572 +static void PvmAssignWork PARAMS((void));
1573 +static void PvmMasterEnd PARAMS((void));
1574 +static int PvmStartFrame PARAMS((void));
1575 +static void PvmFinishFrame PARAMS((void));
1576 +static void PvmReceiveData PARAMS((void));
1577 +static void PvmWrite PARAMS((void));
1578 +
1579 +static void PvmUnpackStats PARAMS((void));
1580 +
1581 +
1582 +static int grid_points;                /* number of grid blocks for one frame */
1583 +static int grid_ppline;                /* Number of grid blocks in a row */
1584 +static int frames;             /* num. of frames to do */
1585 +static int frame = -1;         /* the current frame, start with 0 to count */
1586 +static int next_frame_finish;  
1587 +static int frame_display;      /* the frame that is displayed */
1588 +
1589 +static int grid_lines_done = 0;        /* num. of PvmCthunkWidth lines done (only statistics) */
1590 +
1591 +static int npixels_done = 0;    /* Number of pixels done, by all processors */
1592 +
1593 +static int                row_start;           /* First row in the block */
1594 +static int                row_end;             /* Last row in the block */
1595 +static int                col_start;           /* First column in the block */
1596 +static int                col_end;             /* Last column in the block */
1597 +static int msgtag; 
1598 +
1599 +static   struct timeval     wait_time;           /* Time to wait for slave stats */
1600 +static   struct pvmhostinfo *hostinfo;           /* Info on each PVM host */
1601 +static   int                minions;             /* Number of slave tasks */
1602 +static   int                nhost;               /* Number of available pvm hosts */
1603 +static   pvm_slave_stat     *slave_stat;         /* Info on the slaves */
1604 +static   pvm_frame_stat     *frame_stat;
1605 +static   int                rtid;                /* tid of the message sender */
1606 +static   int                *tids;               /* tids of all the slaves */
1607 +static   int                slave_num;           /* Relative host number of sender */
1608 +static   char               *slave_name;         /* Hostname of sending slave */
1609 +static   int                nstat = 0;           /* Number of slaves returning stats */
1610 +
1611 +static   int                bitmask;             /* Start tasks on a specific arch */
1612 +static   int                bufid;               /* pvm recieve buffer id */
1613 +static   int                bytesin;             /* Size of message */
1614 +static   char               **sargs;             /* argv for the slaves */
1615 +static   char               slave_option[PATH_MAX+4]; /* the directory argument */
1616 +
1617 +
1618 +/* in povray.c */
1619 +extern char Actual_Output_Name[FILE_NAME_LENGTH];
1620 +void setup_output_file_name PARAMS((void));
1621 +void open_output_file PARAMS((void));
1622 +void set_output_file_handle();
1623 +
1624 +
1625 +
1626 +/********************************************************************************
1627 + * Initialize Master Process
1628 + *******************************************************************************/
1629 +
1630 +
1631 +/*
1632 + * Spawn the slaves, and check for errors 
1633 + */
1634 +
1635 +/* handle an error from pvm_spawn */
1636 +static void PvmSpawnError(m) 
1637 +    int m; 
1638 +{
1639 +    /* Only quit if we can't start many tasks, or an error condition. */
1640 +    Error_Line( "...error spawning tasks because \n");
1641 +    switch (m) {
1642 +    case PvmBadParam:
1643 +       Error_Line("of bad parameter.\n");
1644 +       break;
1645 +    case PvmNoHost:
1646 +       Error_Line("host not in PVM.\n");
1647 +       break;
1648 +    case PvmNoFile:
1649 +       Error_Line("executable not found.\n");
1650 +       break;
1651 +    case PvmNoMem:
1652 +       Error_Line("no memory on host.\n");
1653 +       break;
1654 +    case PvmSysErr:
1655 +       Error_Line("pvmd not responding.\n");
1656 +       break;
1657 +    case PvmOutOfRes:
1658 +       Error_Line("lack of resources.\n");
1659 +       break;
1660 +    default:
1661 +       Error_Line("of unknown error.\n");
1662 +    }
1663 +    pvm_perror("");
1664 +    pvm_exit();
1665 +    close_all();
1666 +    exit(1);
1667 +}
1668 +
1669 +static void PvmSpawnTidError(tid) 
1670 +    int tid; 
1671 +{
1672 +
1673 +    Warning(0.0, "...spawn failure because ");
1674 +    switch (tid) {
1675 +    case PvmBadParam:
1676 +       Warning(0.0, "of bad parameter.\n");
1677 +       break;
1678 +    case PvmNoHost:
1679 +       Warning(0.0, "host not in PVM.\n");
1680 +       break;
1681 +    case PvmNoFile:
1682 +       Warning(0.0, "executable not found.\n");
1683 +       break;
1684 +    case PvmNoMem:
1685 +       Warning(0.0, "no memory on host.\n");
1686 +       break;
1687 +    case PvmSysErr:
1688 +       Warning(0.0, "pvmd not responding.\n");
1689 +       break;
1690 +    case PvmOutOfRes:
1691 +       Warning(0.0, "lack of resources.\n");
1692 +       break;
1693 +    default:
1694 +       Warning(0.0, "of unknown error.\n");
1695 +    }
1696 +}
1697 +
1698 +static void PvmSpawn() {
1699 +    int i;
1700 +
1701 +    /* Start up the slave processes */
1702 +    if (PvmArch[0] != '\0') {
1703 +       Status_Info("  Spawning %s with %d PVM tasks on arch %s...\n",
1704 +                   PvmSlavename, PvmTasks,PvmArch);
1705 +    } else {
1706 +       Status_Info("  Spawning %s with %d PVM tasks on %d hosts...\n",
1707 +                   PvmSlavename, PvmTasks,nhost);
1708 +    }
1709 +
1710 +    if(PvmHosts) {                     /* start at specified hosts */
1711 +       int m;
1712 +       minions = 0;
1713 +       for(i=0; i < PvmTasks; i++) {   /* start one by one */
1714 +           m = pvm_spawn(PvmSlavename, sargs, PvmTaskHost, PvmHosts[i % PvmHostsN], 
1715 +                         1, tids+minions);
1716 +           if( m < 0) {                        /* spawn failed */
1717 +               PvmSpawnError(m);
1718 +           } else if (m==0) {                  /* failed a little bit */
1719 +               PvmSpawnTidError(tids[minions]);
1720 +           }
1721 +           minions += m;
1722 +       }
1723 +
1724 +    } else {                           /* start all at once somwhere */
1725 +       minions = pvm_spawn(PvmSlavename, sargs, bitmask, PvmArch, PvmTasks, tids);
1726 +
1727 +       if(minions < 0)                 /* check for total failure */
1728 +           PvmSpawnError(minions);
1729 +       for (i = minions; i < PvmTasks; i++)    /* errors/process */
1730 +           PvmSpawnTidError(tids[i]);
1731 +    }
1732 +
1733 +    /* Check if "few" tasks could be started */
1734 +    if (minions < (PvmTasks + 1) / 2)  {
1735 +       if(minions==0) {
1736 +           Error_Line("...No tasks");
1737 +        } else {
1738 +           Error_Line("...only %d of %d tasks", minions, PvmTasks);
1739 +       }
1740 +       Error_Line(" spawned!  Quitting.\n");
1741 +       pvm_exit();
1742 +       close_all();
1743 +       exit(1);
1744 +    } else {
1745 +       Status_Info("  ...%d PVM tasks successfully spawned.\n", minions);
1746 +    }
1747 +
1748 +    PvmTasks = minions;
1749 +}
1750 +
1751 +
1752 +/*
1753 + * Wait up to 120 seconds for the first to check in
1754 + */
1755 +static void PvmCheckFirst() {
1756 +    wait_time.tv_sec = 120;
1757 +    wait_time.tv_usec = 0;
1758 +
1759 +    Status_Info("  Waiting up to %lds for first slave to start...\n",
1760 +               wait_time.tv_sec);
1761 +    minions = 0;
1762 +
1763 +    if( pvm_trecv(-1, PVM_INIT_SLAVE, &wait_time) <= 0 ) {
1764 +       /* No slave checked in. Something is wrong */
1765 +       Error_Line("First slave did not start in time!  Quitting.\n");
1766 +       Error_Line("See /tmp/pvml.<your uid> on the master PVM host for\n");
1767 +       Error_Line("more info on why the slave didn't start correctly.\n");
1768 +       pvm_exit();
1769 +       close_all();
1770 +       exit(1);
1771 +    }  else {
1772 +       minions++;
1773 +    }
1774 +
1775 +    if (opts.Options & VERBOSE) {
1776 +       Status_Info("  Slave 0 successfully started.\n");
1777 +    }
1778 +}
1779 +
1780 +
1781 +/* 
1782 + * Get a status struct for each slave 
1783 + */
1784 +static void PvmInitSlaveStat() {
1785 +    
1786 +    slave_stat = (pvm_slave_stat *)POV_CALLOC(PvmTasks, sizeof(pvm_slave_stat), "slave_stat");
1787 +    
1788 +    /* Set up pointers to all the host names and the slave status */
1789 +    for (slave_num = 0; slave_num < PvmTasks; slave_num++) {
1790 +       int j;
1791 +       int dtid;
1792 +
1793 +       dtid = pvm_tidtohost(tids[slave_num]);
1794 +       slave_stat[slave_num].name = "unknown";
1795 +
1796 +       for (j = 0; j < nhost; j++) {
1797 +           if (dtid == hostinfo[j].hi_tid) {
1798 +               slave_stat[slave_num].name = (char*)POV_CALLOC(strlen(hostinfo[j].hi_name)+1, 
1799 +                                                              sizeof(char), "hostnames");
1800 +               strcpy(slave_stat[slave_num].name,hostinfo[j].hi_name);
1801 +               break;
1802 +           }
1803 +       }
1804 +       slave_stat[slave_num].frame_assigned = PVM_SLAVE_FREE;
1805 +       slave_stat[slave_num].block_reassigned = PVM_SLAVE_FREE;
1806 +    }
1807 +}
1808 +
1809 +/* 
1810 + * Get a status struct for each frame
1811 + */
1812 +static void PvmInitFrameStat() {
1813 +    int i,j;
1814 +
1815 +    frames = (opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME) ? 
1816 +       opts.FrameSeq.FinalFrame - opts.FrameSeq.InitialFrame + 1 :
1817 +       1;
1818 +    frame_stat = (pvm_frame_stat *)POV_CALLOC(frames, sizeof(pvm_frame_stat), "frame_stat");
1819 +    frame_display = -1;
1820 +
1821 +    for(i=0; i < frames; i++) {
1822 +       frame_stat[i].block_to_assign = 0;
1823 +       frame_stat[i].block_to_reassign = 0;
1824 +
1825 +       frame_stat[i].block_to_write = 0;
1826 +
1827 +       frame_stat[i].row_to_write  = opts.First_Line;
1828 +       frame_stat[i].row_to_malloc = opts.First_Line;
1829 +
1830 +       frame_stat[i].block_stat = 
1831 +           (pvm_block_stat *)POV_CALLOC(grid_points, sizeof(pvm_block_stat), "block_stat");
1832 +
1833 +       for(j=0; j < MaxStat; j++)
1834 +           Init_Counter(frame_stat[i].stats[j]);
1835 +    }
1836 +}
1837 +
1838 +/*
1839 + * Initialize PVM Master
1840 + */
1841 +void 
1842 +Pvm_Master_Init(argc, argv)
1843 +    int     argc;
1844 +    char    **argv;
1845 +{
1846 +    int                i;
1847 +
1848 +    Status_Info("Initializing PVMPOV\n");
1849 +
1850 +    /* Get a table for the TIDs */
1851 +    tids = (int *)POV_CALLOC(PvmTasks, sizeof(int), "tids");
1852 +
1853 +    /* Build a new arg list for the sub-tasks - add -ni in front */
1854 +    sargs = (char **)POV_CALLOC(argc + 1, sizeof(char *), "sargs");
1855 +
1856 +    /* Move argument pointers to new list array, keep position 0 free for -ni option */
1857 +    for (i = 1; i < argc; i++) {
1858 +       sargs[i] = argv[i];
1859 +    }
1860 +
1861 +    /* Get current directory for the slave tasks */
1862 +    if(PvmWorkingDir[0] == '\0')
1863 +       if ( GETCWD(PvmWorkingDir) == NULL) {
1864 +           Error("PVM Master cannot get current directory.\n");
1865 +           return;
1866 +       }
1867 +
1868 +    /* Add slave flag */
1869 +    sprintf(slave_option, "-nI%s", PvmWorkingDir);
1870 +    sargs[0] = slave_option;
1871 +
1872 +    /* Enroll in PVM */
1873 +    if (pvm_mytid() < 0) {
1874 +       Error("Error starting master task.\n");
1875 +    }
1876 +
1877 +    if (pvm_config(&nhost, (int *)NULL, &hostinfo) < 0) {
1878 +       pvm_exit();
1879 +       Error("Error getting PVM machine status.\n");
1880 +    }
1881 +           
1882 +    bitmask = PvmTaskDefault;
1883 +
1884 +    /* If PvmArch is specified, use that architecture */
1885 +    if (PvmArch[0] != '\0') {
1886 +       bitmask = PvmTaskArch;
1887 +
1888 +       /* If arch is psecified, but not the number of tasks, go and
1889 +        * count how many hosts of that type there are.
1890 +        */
1891 +       if (PvmTasks >= 9999) {
1892 +           PvmTasks = 0;
1893 +           
1894 +           for (i = 0; i < nhost; i++) {
1895 +               if (strcmp(PvmArch,hostinfo[i].hi_arch) == 0)
1896 +                   PvmTasks++;
1897 +           }
1898 +       }    
1899 +    }
1900 +
1901 +    /* If PvmTasks is specified, use that many tasks, otherwise use
1902 +     * as many hosts as possible.
1903 +     */
1904 +    if (PvmTasks >= 9999) {
1905 +       PvmTasks = nhost;
1906 +    }
1907 +
1908 +    /* if no slavename was given, use name of current executable */
1909 +    if(PvmSlavename == NULL)
1910 +       PvmSlavename = argv[0];
1911 +
1912 +    PvmSpawn();                                                /* spawn the slaves */
1913 +    PvmCheckFirst();                                   /* wait for first slave */
1914 +
1915 +    pvm_setopt(PvmRoute, PvmRouteDirect);
1916 +
1917 +    /* Max # of pixels in a grid row */
1918 +    PvmChunkWidth = min(PvmChunkWidth, opts.Last_Column - opts.First_Column);
1919 +
1920 +    /* Grid points per line - rounded up */
1921 +    grid_ppline = (opts.Last_Column  - opts.First_Column + PvmChunkWidth - 1) / PvmChunkWidth;
1922 +
1923 +    /* Establish grid section height */
1924 +    PvmChunkHeight = min(PvmChunkHeight, opts.Last_Line - opts.First_Line);
1925 +
1926 +    /* Total grid points in the image - round up PvmChunkHeight */
1927 +    grid_points = ((opts.Last_Line - opts.First_Line + PvmChunkHeight - 1) / PvmChunkHeight) * 
1928 +       grid_ppline;
1929 +    
1930 +    PvmInitSlaveStat();
1931 +    PvmInitFrameStat();
1932 +
1933 +    /* initialize total stats */
1934 +    for(i=0; i < MaxStat; i++) {
1935 +       Init_Counter(totalstats[i]);
1936 +    }
1937 +}
1938 +
1939 +
1940 +
1941 +
1942 +
1943 +/********************************************************************************
1944 + * Master Control
1945 + ********************************************************************************/
1946 +
1947 +/*
1948 + * Receive a message
1949 + */
1950 +static int PvmMasterReceive() {
1951 +
1952 +    /* wait for a message from the slaves */
1953 +    if ((bufid = pvm_trecv(-1, -1, &wait_time)) < 0) {
1954 +       Error_Line( "PVM Master cannot receive.\n");
1955 +       pvm_perror("");
1956 +       pvm_exit();
1957 +       exit(1);
1958 +    }
1959 +
1960 +    /* We timed out waiting for any messages */
1961 +    if (bufid == 0) {
1962 +       Status_Info(".");
1963 +       fflush(stderr);
1964 +       
1965 +       return 1;
1966 +    }
1967 +    
1968 +    return 0;
1969 +}
1970 +
1971 +/*
1972 + * Find name and number of slave, of current message
1973 + */
1974 +static void PvmIdentifySlave() {
1975 +
1976 +    /* get info about this msg. */
1977 +    if (pvm_bufinfo(bufid, &bytesin, &msgtag, &rtid) < 0) {
1978 +       Error_Line( "PVM Master cannot bufinfo.\n");
1979 +       pvm_perror("");
1980 +       pvm_exit();
1981 +       return;
1982 +    }
1983 +
1984 +    /* find the name of the slave, sending the msg. */
1985 +    slave_name = "unknown";
1986 +    for (slave_num = 0; slave_num < PvmTasks; slave_num++) {
1987 +       if (tids[slave_num] == rtid) {
1988 +           slave_name = slave_stat[slave_num].name;
1989 +           break;
1990 +       }
1991 +    }
1992 +}
1993 +
1994 +/*
1995 + * Send a PVM_WORK message
1996 + * Set block to PVM_GRID_POINT_ASSIGNED
1997 + */
1998 +static void PvmSendWork(block) 
1999 +    int block;
2000 +{
2001 +    int row_start, row_end, col_start, col_end;
2002 +#ifdef DEBUG
2003 +    Status_Info("Assigning block: %d, frame: %d of %d to %s.\n", block, frame, frames, slave_name);
2004 +#endif /* DEBUG */
2005 +
2006 +    frame_stat[frame].block_stat[block].status = PVM_GRID_POINT_ASSIGNED;
2007 +    frame_stat[frame].block_stat[block].assigned_tid = rtid;
2008 +    
2009 +    row_start = (block/grid_ppline) * PvmChunkHeight + opts.First_Line;
2010 +    row_end   = (row_start + PvmChunkHeight) - 1;
2011 +           
2012 +    if (row_end >= opts.Last_Line)
2013 +       row_end = opts.Last_Line - 1;
2014 +    
2015 +    col_start = (block%grid_ppline) * PvmChunkWidth + opts.First_Column;
2016 +    col_end   = (col_start + PvmChunkWidth) - 1;
2017 +    
2018 +    if (col_end >= opts.Last_Column)
2019 +       col_end = opts.Last_Column - 1;
2020 +    
2021 +    pvm_initsend(PvmDataDefault);
2022 +    pvm_pkint(&frame,1,1);
2023 +    pvm_pkint(&block,1,1);
2024 +    pvm_pkint(&row_start,1,1);
2025 +    pvm_pkint(&row_end,1,1);
2026 +    pvm_pkint(&col_start,1,1);
2027 +    pvm_pkint(&col_end,1,1);
2028 +    if (pvm_send(rtid, PVM_WORK) < 0) {
2029 +       Error_Line( "PVM Master can't send to slave on %s.\n",slave_name);
2030 +       pvm_perror("");
2031 +       pvm_exit();
2032 +       exit(1);
2033 +    }
2034 +
2035 +    frame_stat[frame].block_to_assign ++;
2036 +}
2037 +
2038 +/*
2039 + * Send a PVM_WORK message
2040 + * Set block to PVM_GRID_POINT_REASSIGNED
2041 + */
2042 +static void PvmReassignWork(block) 
2043 +    int block;
2044 +{
2045 +#ifdef DEBUG
2046 +    Status_Info("Reassigning %d to %s.\n", block,
2047 +               slave_name);
2048 +#endif /* DEBUG */
2049 +    
2050 +    frame_stat[frame].block_stat[block].status=PVM_GRID_POINT_REASSIGNED;
2051 +    frame_stat[frame].block_stat[block].reassigned_tid = rtid;
2052 +    slave_stat[slave_num].block_reassigned = block;
2053 +                       
2054 +    if (frame_stat[frame].block_stat[block].wr_line == 0) {
2055 +       row_start = (block / grid_ppline)*PvmChunkHeight +  opts.First_Line;
2056 +    } else {
2057 +       row_start = frame_stat[frame].block_stat[block].wr_line;
2058 +    }
2059 +    row_end = (block/grid_ppline + 1) * PvmChunkHeight - 1;
2060 +    
2061 +    if (row_end >= opts.Last_Line)
2062 +       row_end = opts.Last_Line - 1;
2063 +                       
2064 +    col_start = (block % grid_ppline) * PvmChunkWidth +
2065 +       opts.First_Column;
2066 +    col_end   = (col_start + PvmChunkWidth) - 1;
2067 +    
2068 +    if (col_end >= opts.Last_Column)
2069 +       col_end = opts.Last_Column - 1;
2070 +    
2071 +    pvm_initsend(PvmDataDefault);
2072 +    pvm_pkint(&frame,1,1);
2073 +    pvm_pkint(&block,1,1);
2074 +    pvm_pkint(&row_start,1,1);
2075 +    pvm_pkint(&row_end,1,1);
2076 +    pvm_pkint(&col_start,1,1);
2077 +    pvm_pkint(&col_end,1,1);
2078 +    if (pvm_send(rtid, PVM_WORK) < 0) {
2079 +       Error_Line( "PVM Master can't send to slave on %s.\n",slave_name);
2080 +       pvm_perror("");
2081 +       pvm_exit();
2082 +       exit(1);
2083 +    }
2084 +
2085 +    frame_stat[frame].block_to_reassign++;
2086 +}
2087 +
2088 +
2089 +/*      
2090 + * Do all the stuff, that is necessary for a new frame 
2091 + * This is called before the PVM_WORK is sent
2092 + *
2093 + * A lot of this is taken from 'FrameRender' 
2094 + *
2095 + * ret: 0 .. OK send the PVMWOR 
2096 + *      1 .. Shellout gave SKIP_ONCE_RET -> this frame is done
2097 + */
2098 +static int PvmStartFrame() {
2099 +    int Frame_Result;
2100 +
2101 +    if(frame_stat[frame].status != PVM_FRAME_FREE) {
2102 +       Warning(0.0, "Frame %d already started.\n", frame);
2103 +       return 1;
2104 +    }
2105 +
2106 +    if(opts.Options & VERBOSE)
2107 +       Status_Info("\nStarting frame %d...", opts.FrameSeq.InitialFrame + frame);
2108 +    
2109 +    frame_stat[frame].status = PVM_FRAME_WORKING;
2110 +
2111 +    /* allocate row pointers */
2112 +    frame_stat[frame].row_ptr = (COLOUR **)POV_CALLOC(opts.Last_Line, sizeof(COLOUR *), "row_ptr");
2113 +
2114 +    opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame + frame;
2115 +    setup_output_file_name();
2116 +    
2117 +    /* Execute a shell-out command before tracing */
2118 +    Frame_Result = POV_SHELLOUT(PRE_FRAME_SHL);
2119 +    
2120 +    if (Frame_Result == ALL_SKIP_RET) {
2121 +       /* stop completely */
2122 +       int i;
2123 +       for(i=frame; i < frames; i++) {
2124 +           frame_stat[i].block_to_assign = grid_points;
2125 +           frame_stat[i].block_to_reassign = grid_points;
2126 +           frame_stat[i].status = PVM_FRAME_DONE_SHELLOUT;
2127 +       }
2128 +       /* continue searching, frames before this one, should be finished */
2129 +       return 1;               
2130 +    }
2131 +    
2132 +    if (Frame_Result == SKIP_ONCE_RET) {
2133 +       /* mark frame as done */
2134 +       frame_stat[frame].block_to_assign = grid_points;
2135 +       frame_stat[frame].block_to_reassign = grid_points;
2136 +       frame_stat[frame].status = PVM_FRAME_DONE_SHELLOUT;
2137 +
2138 +       /* continue searching */
2139 +       return 1;
2140 +    }
2141 +
2142 +    /*
2143 +     * open output file
2144 +     */
2145 +    set_output_file_handle();
2146 +    open_output_file();
2147 +
2148 +    Initialize_Renderer(); 
2149 +
2150 +    /*
2151 +     * Start displaying
2152 +     */
2153 +    if( (opts.Options & DISPLAY) && !Display_Started)  {
2154 +       Status_Info("\nDisplaying frame %d...", opts.FrameSeq.InitialFrame + frame);
2155 +       POV_DISPLAY_INIT(Frame.Screen_Width, Frame.Screen_Height);
2156 +       Display_Started = TRUE;
2157 +       frame_display = frame;
2158 +       Status_Info("\n");
2159 +    }
2160 +    
2161 +    
2162 +    /*
2163 +     * read already rendered parts
2164 +     */
2165 +    if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE)) {
2166 +       int i;
2167 +       int fl = opts.First_Line;                       /* remember start of image */
2168 +       
2169 +       Read_Rendered_Part(Actual_Output_Name);         /* read -> changes opts.First_line */
2170 +
2171 +       frame_stat[frame].row_to_write = 
2172 +           frame_stat[frame].row_to_malloc = opts.First_Line;
2173 +
2174 +       frame_stat[frame].block_to_write = 
2175 +           frame_stat[frame].block_to_assign = (opts.First_Line/PvmChunkHeight)*grid_ppline;
2176 +       /* blocks above the new start are already finished */
2177 +       for(i=0; i < frame_stat[frame].block_to_assign; i++) {
2178 +           frame_stat[frame].block_stat[i].status = PVM_GRID_POINT_WRITTEN;
2179 +       }
2180 +       if(opts.Options & VERBOSE)
2181 +           Status_Info("Continuing with block %d in frame %d\n", 
2182 +                       frame_stat[frame].block_to_assign, frame);
2183 +
2184 +       opts.First_Line = fl;                           /* set back the old value */
2185 +
2186 +
2187 +       /* this should not be necessary */
2188 +       if (opts.Last_Line > Frame.Screen_Height)
2189 +           opts.Last_Line = Frame.Screen_Height;
2190 +       
2191 +       if (opts.Last_Column > Frame.Screen_Width)
2192 +           opts.Last_Column = Frame.Screen_Width;      
2193 +    }
2194 +
2195 +    /*
2196 +     *  make a copy of the Output_File_Handle 
2197 +     */
2198 +    frame_stat[frame].output_file = Output_File_Handle;
2199 +    if(Output_File_Handle->filename) {
2200 +       char * n = POV_MALLOC(strlen(Output_File_Handle->filename)+1, "filename");
2201 +       strcpy(n, Output_File_Handle->filename);
2202 +       frame_stat[frame].output_file->filename = n;
2203 +    }
2204 +
2205 +    if(opts.Options & VERBOSE)
2206 +       Status_Info("\n");
2207 +
2208 +    return 0;
2209 +}
2210 +
2211 +
2212 +/*
2213 + * test, if the next frame in the sequence finished,
2214 + * do all the necessary stuff to close the frame (shellout, ...)
2215 + */
2216 +static void PvmFinishFrame() {
2217 +
2218 +    /* check, if frame has really finished */
2219 +    if( frame_stat[frame].row_to_write < opts.Last_Line)
2220 +       return;
2221 +
2222 +    /* if not already closed */
2223 +    if( frame_stat[frame].status < PVM_FRAME_DONE) {
2224 +       
2225 +       if(opts.Options & VERBOSE)
2226 +           Status_Info("\nFinishing frame %d...", opts.FrameSeq.InitialFrame + frame);
2227 +       Status_Info("rtw. %d\n", frame_stat[frame].row_to_write);
2228 +
2229 +       frame_stat[frame].status = PVM_FRAME_DONE;
2230 +       
2231 +       POV_FREE(frame_stat[frame].row_ptr);
2232 +       
2233 +       /* Close output file */
2234 +       if (frame_stat[frame].output_file) {
2235 +           Output_File_Handle = frame_stat[frame].output_file;
2236 +           Close_File(frame_stat[frame].output_file);
2237 +       }
2238 +       
2239 +       if( frame == frame_display) {
2240 +           POV_DISPLAY_FINISHED
2241 +               
2242 +               if ((opts.Options & DISPLAY) && Display_Started)  {
2243 +                   POV_DISPLAY_CLOSE
2244 +           
2245 +                       Display_Started = FALSE;
2246 +               }
2247 +           
2248 +           frame_display = -1;
2249 +       }
2250 +       
2251 +       if (opts.histogram_on)
2252 +           write_histogram (opts.Histogram_File_Name);
2253 +    }
2254 +
2255 +    if( frame_stat[frame].status < PVM_FRAME_DONE_SHELLOUT) {
2256 +       /* the shellouts are done in the correct order */
2257 +       if( frame == next_frame_finish) {
2258 +           int Frame_Result;
2259 +
2260 +           frame_stat[frame].status = PVM_FRAME_DONE_SHELLOUT;
2261 +
2262 +           opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame + frame;
2263 +           setup_output_file_name();
2264 +           
2265 +           Frame_Result = POV_SHELLOUT(POST_FRAME_SHL);
2266 +           
2267 +           if ((Frame_Result==SKIP_ONCE_RET) || (Frame_Result==ALL_SKIP_RET)) {
2268 +               next_frame_finish = frames;
2269 +               return;
2270 +           }
2271 +           next_frame_finish ++;       /* one more frame finished */
2272 +           
2273 +           frame ++;           /* check next frame (might have finished earlier) */
2274 +           if( frame < frames)
2275 +               PvmFinishFrame();
2276 +       }
2277 +    }
2278 +    if(opts.Options & VERBOSE)
2279 +       Status_Info("\n");      
2280 +}
2281 +
2282 +
2283 +/*
2284 + * Assign Work
2285 + *
2286 + * A slaved requested work, now find free block (or a block to reassign)
2287 + */
2288 +static void PvmAssignWork() {
2289 +    int min_assigned;
2290 +    int found;
2291 +    int f;
2292 +    
2293 +    /* The slave wants work, but has already been reassigned something,
2294 +     * then tell it to ask again when it really wants work.
2295 +     */
2296 +    if( slave_stat[slave_num].block_reassigned != PVM_SLAVE_FREE) {
2297 +#ifdef DEBUG
2298 +       Status_Info("%s already assigned on %d.  Not reassigning.\n",
2299 +                   slave_name,
2300 +                   slave_stat[slave_num].block_reassigned);
2301 +#endif /* DEBUG */
2302 +       pvm_initsend(PvmDataDefault);
2303 +       pvm_send(rtid, PVM_INIT_SLAVE);
2304 +       
2305 +       return;
2306 +    }
2307 +
2308 +
2309 +    /*
2310 +     * search for a free block, take a frame with minimal
2311 +     * number of assigned blocks
2312 +     */
2313 +    found = 0;
2314 +    min_assigned = grid_points;
2315 +
2316 +    frame = slave_stat[slave_num].frame_assigned;
2317 +    /* if slave was already assigned and that frame has still free blocks */
2318 +    if ( (frame >= 0) &&
2319 +        (frame_stat[frame].block_to_assign < grid_points) ) {
2320 +       
2321 +       min_assigned = 0;
2322 +       found = 1;
2323 +    }
2324 +    
2325 +    /* find free frame with minimal number of assigned frames */
2326 +    for(f = 0; (f < frames) && (min_assigned > 0); f ++) {
2327 +       if( (frame_stat[f].block_to_assign < min_assigned) &&
2328 +           (frame_stat[f].block_to_assign < grid_points) ) {
2329 +           
2330 +#ifdef DEBUG
2331 +           Status_Info("\nfound: frame %d, ass: %d, min: %d\n", 
2332 +                       f, frame_stat[f].block_to_assign,
2333 +                       min_assigned);
2334 +#endif
2335 +
2336 +           min_assigned = frame_stat[f].block_to_assign;
2337 +           frame = f;
2338 +           found = 1;
2339 +
2340 +       }
2341 +    }
2342 +
2343 +    if( found ) {
2344 +       /* first block for that frame */
2345 +       if( frame_stat[frame].block_to_assign == 0) {   
2346 +           /* Do the necessary preparations for a new frame */
2347 +           if( PvmStartFrame() ) {
2348 +               /* Shellout gave SKIP_ONCE_REt -> search next block */
2349 +               PvmAssignWork();
2350 +               return;
2351 +           }
2352 +       }
2353 +
2354 +       slave_stat[slave_num].frame_assigned = frame;
2355 +       PvmSendWork(frame_stat[frame].block_to_assign);
2356 +       return;
2357 +    }
2358 +
2359 +
2360 +    /*
2361 +     * found no free block
2362 +     * search for a block to reassign
2363 +     */
2364 +
2365 +    /* if this slave was slow, and there are enough other slaves left,
2366 +       don't use this anymore */
2367 +    if ( (slave_stat[slave_num].pixels_done < npixels_done*9/10/PvmTasks) &&
2368 +        (minions >= (PvmTasks + 3) / 4) ) {
2369 +    
2370 +       Status_Info("Not using %s for reassignment (%d%%)\n", slave_name,
2371 +                   100*slave_stat[slave_num].pixels_done*PvmTasks/npixels_done);
2372 +
2373 +       /* tell slave to finish work */
2374 +       pvm_initsend(PvmDataDefault);
2375 +       pvm_send(rtid, PVM_STOP_SLAVE);
2376 +    }
2377 +
2378 +    found = 0;
2379 +
2380 +    frame = slave_stat[slave_num].frame_assigned;
2381 +    /* if slave was already assigned and that frame has free blocks */
2382 +    if ( (frame >= 0) &&
2383 +        (frame_stat[frame].block_to_reassign < grid_points) ) {
2384 +       
2385 +       min_assigned = 0;
2386 +       found = 1;
2387 +    }
2388 +       
2389 +    /* find first frame with minimal number of reassigned frames */
2390 +    min_assigned = grid_points + 1;
2391 +    for(f = 0; (f < frames) && (min_assigned > 0); f ++) {
2392 +       if( frame_stat[f].block_to_reassign < min_assigned) {
2393 +           
2394 +           min_assigned = frame_stat[frame].block_to_reassign;
2395 +           frame = f;
2396 +           found = 1;
2397 +       }
2398 +    }
2399 +    
2400 +    if( found ) {
2401 +       /* find block in frame */
2402 +       int block;
2403 +       for(block = 0; block < grid_points; block ++) {
2404 +           if( frame_stat[frame].block_stat[block].status < PVM_GRID_POINT_DONE) {
2405 +               slave_stat[slave_num].frame_reassigned = frame;
2406 +               PvmReassignWork(block);
2407 +               return;
2408 +           }
2409 +       }
2410 +    }
2411 +
2412 +    /* 
2413 +     * there is nothing left to reassign
2414 +     */
2415 +    Status_Info("All blocks are assigned. Stopping %s.\n", slave_name);
2416 +
2417 +    /* tell slave to finish work */
2418 +    pvm_initsend(PvmDataDefault);
2419 +    pvm_send(rtid, PVM_STOP_SLAVE);
2420 +
2421 +}
2422 +
2423 +/*
2424 + * display a part from one line
2425 + */
2426 +static void PvmDisplayPlot(row_ptr, row, col, ncols) 
2427 +    COLOUR * row_ptr;
2428 +    int row, col, ncols;
2429 +{
2430 +    unsigned char Red, Green, Blue, Alpha;
2431 +    DBL grey;
2432 +    int i;
2433 +    
2434 +    /* draw line */
2435 +    for (i = col; i < col+ncols; i++) {
2436 +       extract_colors(row_ptr[i], &Red, &Green, &Blue, &Alpha, &grey);
2437 +       POV_DISPLAY_PLOT(i, row, Red, Green, Blue, Alpha);
2438 +    }
2439 +    /* force draw of the whole line (with X11) */
2440 +    i = opts.Last_Column - 1;
2441 +    extract_colors(row_ptr[i], &Red, &Green, &Blue, &Alpha, &grey);
2442 +    POV_DISPLAY_PLOT(i, row, Red, Green, Blue, Alpha);
2443 +}
2444 +
2445 +
2446 +/*
2447 + * one of the slaves sends a part of it's computed data
2448 + */
2449 +static void PvmReceiveData() {
2450 +    int ncols;
2451 +    int i;
2452 +    int block;
2453 +    
2454 +    pvm_upkint(&frame, 1, 1);
2455 +    pvm_upkint(&block, 1, 1);
2456 +    pvm_upkint(&row_start, 1, 1);
2457 +    pvm_upkint(&col_start, 1, 1);
2458 +    pvm_upkint(&ncols, 1, 1);
2459 +
2460 +    row_end = row_start + (bytesin - 3*sizeof(int))/(5*ncols*sizeof(COLC));
2461 +    col_end = col_start + ncols;
2462 +
2463 +#ifdef DEBUG
2464 +    Status_Info("receiving frame: %d, row: %d-%d, col: %d-%d\n", 
2465 +               frame, row_start, row_end, col_start, col_end);
2466 +#endif
2467 +
2468 +    /* Make some checks to see if the data is not corrupted or invalid */
2469 +    if( (row_start < opts.First_Line) || (col_start < opts.First_Column) ||
2470 +       (row_end   > opts.Last_Line)  || (col_end   > opts.Last_Column) ||
2471 +       (frame     < 0)               || (frame     >= frames) ||
2472 +       (ncols     > PvmChunkWidth)   || (row_end - row_start > PvmChunkHeight) ) {
2473 +       
2474 +       Warning(0.0, "Bad block recieved from %s\n",slave_name);
2475 +       Warning(0.0, "Frame %d, Row %d - %d, Column %d - %d.\n", frame, row_start, row_end,
2476 +               col_start, col_end);
2477 +       
2478 +       return;
2479 +    }
2480 +    
2481 +    /* get one row after the other */
2482 +    for (i = row_start; i < row_end; i++) {
2483 +       if (i >= frame_stat[frame].block_stat[block].wr_line) {  /* Is incoming data current? */
2484 +
2485 +           /* allocate memory, to receive data */
2486 +           if (frame_stat[frame].row_ptr[i] == NULL) { /* Starting a new row */
2487 +               
2488 +               frame_stat[frame].row_ptr[i] = (COLOUR *)POV_MALLOC(opts.Last_Column*sizeof(COLOUR), 
2489 +                                                                   "row_ptr");
2490 +               
2491 +               while(frame_stat[frame].row_ptr[frame_stat[frame].row_to_malloc] != NULL && 
2492 +                     frame_stat[frame].row_to_malloc < opts.Last_Line) {
2493 +                   frame_stat[frame].row_to_malloc++;
2494 +               }
2495 +           }
2496 +           
2497 +           /* get color data */
2498 +           pvm_upkCOL(&(frame_stat[frame].row_ptr[i][col_start][0]),5*ncols,1);
2499 +           
2500 +           frame_stat[frame].block_stat[block].wr_line = i + 1;
2501 +
2502 +           if (frame == frame_display) {
2503 +               PvmDisplayPlot(frame_stat[frame].row_ptr[i], i, col_start, ncols);
2504 +           }
2505 +
2506 +           /* Statistics - Attribute this grid section  */
2507 +           grid_lines_done++;
2508 +           slave_stat[slave_num].pixels_done += ncols;
2509 +
2510 +           npixels_done += ncols;
2511 +       } else {  
2512 +           /* another slave already sent this data */
2513 +
2514 +           COLOUR *dummy = (COLOUR *)POV_MALLOC(ncols * sizeof(COLOUR), "dummy row");
2515 +           pvm_upkCOL(&(dummy[0][0]),5*ncols,1);
2516 +           
2517 +           /* Statistics - Attribute this grid section  */
2518 +           slave_stat[slave_num].pixels_late += ncols;
2519 +           POV_FREE(dummy);
2520 +       }
2521 +    }
2522 +    /* Has this entire block been rendered? */
2523 +    if (frame_stat[frame].block_stat[block].wr_line >= 
2524 +       (block/grid_ppline + 1)*PvmChunkHeight + opts.First_Line - 1 ||
2525 +       frame_stat[frame].block_stat[block].wr_line >= opts.Last_Line)  {
2526 +#ifdef DEBUG
2527 +       Status_Info("Block completed by %s\n", slave_name);
2528 +#endif /* DEBUG */
2529 +       frame_stat[frame].block_stat[block].status = PVM_GRID_POINT_DONE;
2530 +       if (slave_stat[slave_num].block_reassigned == block) {
2531 +#ifdef DEBUG
2532 +               Status_Info("   reassigned block cleared.\n");
2533 +#endif /* DEBUG */
2534 +               slave_stat[slave_num].block_reassigned = PVM_SLAVE_FREE;
2535 +       }
2536 +#ifdef DEBUG
2537 +       else
2538 +       {
2539 +           Status_Info("   reassigned block is %d.\n",
2540 +                       slave_stat[slave_num].block_reassigned);
2541 +       }
2542 +#endif /* DEBUG */
2543 +    }
2544 +    
2545 +    if ((opts.Options & VERBOSE) && (grid_lines_done % PvmChunkHeight) == 0) {
2546 +       Status_Info("\r%5.2f of blocks complete.",
2547 +                   (float)100*grid_lines_done/PvmChunkHeight/grid_points/frames);
2548 +    }
2549 +}
2550 +
2551 +/*
2552 + * Write out us many lines as possible 
2553 + */
2554 +static void PvmWrite() {
2555 +    int i;
2556 +
2557 +    do { 
2558 +       /* check, if there is a complete line to write */
2559 +       for (i = frame_stat[frame].block_to_write; 
2560 +            i < frame_stat[frame].block_to_write + grid_ppline; i++)   {
2561 +           if (frame_stat[frame].block_stat[i].wr_line <= frame_stat[frame].row_to_write) {
2562 +#ifdef DEBUG
2563 +               Status_Info("needing block %d in frame %d\n", i, frame); 
2564 +#endif
2565 +               return;
2566 +           }
2567 +       }
2568 +
2569 +       /* OK, we can write a whole line */
2570 +       if (opts.Options & DISKWRITE) {
2571 +#ifdef DEBUG
2572 +           Status_Info("write: %d %d\n", frame, frame_stat[frame].row_to_write);
2573 +#endif
2574 +           Write_Line(frame_stat[frame].output_file,
2575 +                      frame_stat[frame].row_ptr[frame_stat[frame].row_to_write],
2576 +                      frame_stat[frame].row_to_write);
2577 +       }
2578 +
2579 +       /* Still lines to allocate so */
2580 +       if (frame_stat[frame].row_to_malloc < opts.Last_Line)  {
2581 +           /* move this row buffer down, so we avaoid one malloc/free  */
2582 +           frame_stat[frame].row_ptr[frame_stat[frame].row_to_malloc] = 
2583 +               frame_stat[frame].row_ptr[frame_stat[frame].row_to_write];
2584 +           frame_stat[frame].row_ptr[frame_stat[frame].row_to_write] = NULL;
2585 +           frame_stat[frame].row_to_malloc++;
2586 +       } else {                        /* Otherwise free the row buffer */
2587 +           POV_FREE(frame_stat[frame].row_ptr[frame_stat[frame].row_to_write]);
2588 +           frame_stat[frame].row_ptr[frame_stat[frame].row_to_write]= NULL;
2589 +       }
2590 +       
2591 +       frame_stat[frame].row_to_write++;
2592 +       
2593 +#ifndef DEBUG
2594 +       if ((opts.Options & VERBOSE) && (frame_stat[frame].row_to_write % 8) == 0) {
2595 +           Status_Info("\r%5.2f of blocks complete.",
2596 +                       (float)100*grid_lines_done/PvmChunkHeight/grid_points/frames);
2597 +           Status_Info("  %4d of %4d lines finished (in frame %d).",
2598 +                       frame_stat[frame].row_to_write - opts.First_Line, 
2599 +                       opts.Last_Line - opts.First_Line, frame);
2600 +       }       
2601 +#endif /* not DEBUG */
2602 +       
2603 +       /* Finished a whole row  of blocks */
2604 +       if ((frame_stat[frame].row_to_write - opts.First_Line) % PvmChunkHeight == 0) {
2605 +           for (i = frame_stat[frame].block_to_write; 
2606 +                i < frame_stat[frame].block_to_write + grid_ppline; i++) {
2607 +               frame_stat[frame].block_stat[i].status = PVM_GRID_POINT_WRITTEN;
2608 +           }
2609 +           frame_stat[frame].block_to_write += grid_ppline;
2610 +       }
2611 +       
2612 +    } while(frame_stat[frame].block_to_write < grid_points);
2613 +}
2614 +
2615 +/*
2616 + * Handle slave requests, distribute and collect work
2617 + */
2618 +void Pvm_Master_Control() {
2619 +
2620 +    /* Wait five minutes at a time between messages */
2621 +    wait_time.tv_sec = 300;
2622 +
2623 +    next_frame_finish = 0;             /* next frame that finishes */
2624 +
2625 +    /* There are incomplete frames and/or incoming messages, and there are any slaves left*/
2626 +    while ( (next_frame_finish < frames) || 
2627 +           ((pvm_probe(-1, -1) > 0) && (minions > 0))) {
2628 +
2629 +       /* check for user abort */
2630 +       TEST_ABORT;
2631 +       if (Stop_Flag)  {
2632 +           Render_Info("\nAborting render...\n");
2633 +           
2634 +           PvmMasterEnd();
2635 +
2636 +           if ((opts.Options & DISPLAY) && Display_Started) {
2637 +               POV_DISPLAY_CLOSE;
2638 +           }       
2639 +           if (opts.Do_Stats) {
2640 +               PRINT_STATS(stats);
2641 +           }
2642 +           Error("User abort.\n");
2643 +
2644 +           return;
2645 +       }
2646 +
2647 +       /* receive a request from a slave */
2648 +       if(PvmMasterReceive())
2649 +           continue;
2650 +
2651 +       PvmIdentifySlave();
2652 +
2653 +#ifdef DEBUG
2654 +       Status_Info("Received msg %d from %s\n", msgtag, slave_name);
2655 +#endif
2656 +
2657 +       /* a slaves requests work */
2658 +       switch(msgtag) {
2659 +       case PVM_INIT_SLAVE:            /* Another slave started ok */
2660 +           if (opts.Options & VERBOSE) {
2661 +               Status_Info(" Slave %d at %s successfully started.\n", minions, slave_name);
2662 +           }
2663 +           minions++;
2664 +           break;
2665 +
2666 +       case PVM_NEED_WORK:             /* a slave wants work */
2667 +           PvmAssignWork();
2668 +           break;
2669 +           
2670 +       case PVM_SLAVE_RESULTS:         /* slaves sends us some data */
2671 +           PvmReceiveData();
2672 +           PvmWrite();
2673 +           PvmFinishFrame();
2674 +           break;
2675 +           
2676 +       case PVM_SLAVE_STATS:           /* Too many stats, eh? */
2677 +#ifdef DEBUG
2678 +           Status_Info("Getting stats from %s.\n", slave_name);
2679 +#endif /* DEBUG */
2680 +           PvmUnpackStats();
2681 +           nstat++;
2682 +           break;
2683 +
2684 +       case PVM_SLAVE_EXIT:            /* Slave has exited. */
2685 +           Status_Info("\nSlave at %s has exited.\n",slave_name);
2686 +           
2687 +           if (--minions <= 0)  {
2688 +               Error_Line( "Error - All slave tasks have exited!\n");
2689 +               pvm_exit();
2690 +               return;
2691 +           }
2692 +           break;
2693 +
2694 +       default:                        /* something strange happend */
2695 +           Warning(0.0, "Bad block recieved from %s - message type %4X.\n",
2696 +                       slave_name, msgtag);
2697 +       }
2698 +    } /* incomplete frames */
2699 +
2700 +    /* Finished calculating everything */
2701 +    PvmMasterEnd();
2702 +}
2703 +
2704 +/*
2705 + * Stop PvmMaster
2706 + */
2707 +static void PvmMasterEnd() {
2708 +    int i;
2709 +
2710 +    /* tell all slave to stop work */
2711 +    for(i=0; i < PvmTasks; i++) {
2712 +       pvm_initsend(PvmDataDefault);
2713 +       pvm_send(tids[i], PVM_STOP_SLAVE);
2714 +    }
2715 +
2716 +    /* Wait a few seconds for lingering stats */
2717 +    wait_time.tv_sec  = 4;
2718 +    wait_time.tv_usec = 0;
2719 +
2720 +    if (opts.Options & VERBOSE)
2721 +       Status_Info("\nWaiting for remaining slave stats.\n");
2722 +
2723 +    /* some incoming stats */
2724 +    while ((bufid = pvm_trecv(-1, PVM_SLAVE_STATS, &wait_time)) > 0)  {
2725 +#ifdef DEBUG
2726 +       int msgtag;
2727 +       if (pvm_bufinfo(bufid, &bytesin, &msgtag, &rtid) < 0) {
2728 +           Error_Line( "PVM Master cannot bufinfo.\n");
2729 +           pvm_perror("");
2730 +           pvm_exit();
2731 +           return;
2732 +       }
2733 +
2734 +       PvmIdentifySlave();
2735 +
2736 +       Status_Info("Getting stats from %s.\n", slave_name);
2737 +#endif /* DEBUG */
2738 +
2739 +       PvmUnpackStats();
2740 +       nstat++;
2741 +    }
2742 +
2743 +    /* Dump stats for the tasks */
2744 +    Statistics( "\n\nPVM Task Distribution Statistics:\n");
2745 +    Statistics( "%20s  [ done ] [ late ]","host name");
2746 +    Statistics( "%20s  [ done ] [ late ]\n","host name");
2747 +
2748 +    for (i = 0; i < PvmTasks; i++) {
2749 +       int dtid;
2750 +       int j;
2751 +
2752 +       dtid = pvm_tidtohost(tids[i]);
2753 +
2754 +       for (j = 0; j < PvmTasks; j++)  {
2755 +           if (dtid == hostinfo[j].hi_tid)
2756 +               break;
2757 +       }
2758 +
2759 +       Statistics("%20s  [%5.2f%%] [%5.2f%%]", hostinfo[j].hi_name,
2760 +                  (DBL)slave_stat[i].pixels_done * 100 / npixels_done / frames,
2761 +                  (DBL)slave_stat[i].pixels_late * 100 / npixels_done / frames);
2762 +
2763 +       if (i % 2 == 1)
2764 +           Statistics("\n");
2765 +    }
2766 +
2767 +    pvm_exit();
2768 +
2769 +    Statistics("\n\nPOV-Ray statistics for finished frames:");
2770 +    if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME) {
2771 +       for(i=0; i < next_frame_finish; i++) {
2772 +           Statistics("\nFrame %d:\n", opts.FrameSeq.InitialFrame + i);
2773 +           PRINT_STATS(frame_stat[i].stats);
2774 +       }
2775 +       if (opts.Do_Stats) {
2776 +           Statistics("\n\nTotal statistics:");
2777 +       }
2778 +    }
2779 +
2780 +}
2781 +
2782 +/*
2783 + * A slave sent some stats
2784 + */
2785 +static void PvmUnpackStats() {
2786 +    COUNTER tmpStat[MaxStat];
2787 +
2788 +    pvm_upkint(&frame, 1, 1);
2789 +
2790 +    if( pvm_upkSTAT((long*)tmpStat, MaxStat*sizeof(COUNTER)/sizeof(long), 1) >= 0) {
2791 +       int i;
2792 +       COUNTER tmp;
2793 +
2794 +       for(i=0; i < MaxStat; i++) {
2795 +           /* stats per frame */
2796 +           Add_Counter(tmp,tmpStat[i],frame_stat[frame].stats[i]);
2797 +           frame_stat[frame].stats[i] = tmp;
2798 +
2799 +           /* total stats */
2800 +           Add_Counter(tmp,tmpStat[i],totalstats[i]);
2801 +           totalstats[i] = tmp;
2802 +
2803 +           if(opts.FrameSeq.FrameType != FT_MULTIPLE_FRAME) {
2804 +               Add_Counter(tmp,tmpStat[i],stats[i]);
2805 +               stats[i] = tmp;
2806 +           }
2807 +       }
2808 +    } else {
2809 +       Error_Line("Unpack Stats.\n");
2810 +       pvm_perror("");
2811 +    }
2812 +}
2813 +
2814 +
2815 +
2816 +/********************************************************************************
2817 + * Slave Intialization
2818 + ********************************************************************************/
2819 +
2820 +int Pvm_Slave_Init() {
2821 +    /* Get master TID */
2822 +    PvmMTid = pvm_parent();
2823 +
2824 +    /* Have PVM notify us if the host POV process is killed
2825 +     * or the local PVM daemon dies */
2826 +    pvm_notify(PvmTaskExit, PVM_KILL_SLAVE, 1, &PvmMTid);
2827 +    pvm_setopt(PvmAutoErr, 2);
2828 +    
2829 +    /* Set direct routing */
2830 +    pvm_setopt(PvmRoute, PvmRouteDirect);
2831 +    
2832 +    /* Tell the master we started successfully */
2833 +    pvm_initsend(PvmDataDefault);
2834 +    pvm_send(PvmMTid, PVM_INIT_SLAVE);
2835 +    
2836 +    /* Send an initial work request to the master, so that there is always
2837 +     * an outstanding block assignment, and we don't have to wait for the
2838 +     * master to respond to our request.
2839 +     */
2840 +    pvm_initsend(PvmDataDefault);
2841 +    pvm_send(PvmMTid, PVM_NEED_WORK);
2842 +    
2843 +    NICE(PvmNice);
2844 +    
2845 +    return 0;
2846 +}
2847 +
2848 +
2849 +/********************************************************************************
2850 + * Slave Control
2851 + ********************************************************************************/
2852 +
2853 +static void PvmSendStats() {
2854 +    pvm_initsend(PvmDataDefault);
2855 +    pvm_pkint( &frame, 1, 1);
2856 +    pvm_pkSTAT( (long*)stats, MaxStat*sizeof(COUNTER)/sizeof(long), 1);
2857 +    pvm_send(PvmMTid, PVM_SLAVE_STATS);
2858 +}
2859 +
2860 +/*
2861 + * Request a new block from the master,
2862 + * handle all messages sent by the master
2863 + * ret: 0 .. continue with new frame (or exit)
2864 + *      1 .. continue with this frame (but new region)
2865 + */
2866 +int Pvm_Slave_Control() {
2867 +
2868 +    struct timeval wait_time;
2869 +    int bufid;
2870 +    unsigned int msgtag;
2871 +    int f;
2872 +    static int first = 1;
2873 +
2874 +    /* Wait up to 5 minutes for a message, otherwise exit */
2875 +    wait_time.tv_sec  = 300;
2876 +    wait_time.tv_usec = 0;
2877 +
2878 +    if((bufid = pvm_trecv(PvmMTid, -1, &wait_time)) == 0) {
2879 +       Error_Line( "Slave timed out waiting for master\n");
2880 +       pvm_exit();
2881 +       exit(1);
2882 +    } else if (bufid < 0) {
2883 +       Error_Line( "Cannot receive message from master.");
2884 +       pvm_perror("");
2885 +       pvm_exit();
2886 +       exit(1);
2887 +    }
2888 +
2889 +    /* We have a block assignment from the master - IGOR SERVES! */
2890 +    if(pvm_bufinfo(bufid, (int *)0, &msgtag, &PvmMTid) < 0) {
2891 +       Error_Line("Cannot get PVM bufinfo\n");
2892 +       pvm_perror("");
2893 +       pvm_exit();
2894 +       exit(1);
2895 +    }
2896 +    
2897 +    switch( msgtag) {
2898 +    case PVM_INIT_SLAVE:
2899 +       pvm_initsend(PvmDataDefault);
2900 +       pvm_send(PvmMTid, PVM_NEED_WORK);
2901 +       break;
2902 +
2903 +    case PVM_WORK:
2904 +       /* Ask master for some more block assignments in advance
2905 +        * to avoid waiting for them to be sent later
2906 +        */
2907 +       pvm_initsend(PvmDataDefault);
2908 +       pvm_send(PvmMTid, PVM_NEED_WORK);
2909 +
2910 +       /* Unpack the message */
2911 +       pvm_upkint(&f, 1, 1);
2912 +       pvm_upkint(&PvmBlockNum, 1, 1);
2913 +       pvm_upkint(&opts.First_Line, 1, 1);
2914 +       pvm_upkint(&opts.Last_Line, 1, 1);
2915 +       pvm_upkint(&opts.First_Column, 1, 1);
2916 +       pvm_upkint(&opts.Last_Column, 1, 1);
2917 +
2918 +       /* Last_Line is really "number of lines to do" */
2919 +       opts.Last_Line++;
2920 +
2921 +       /* Send the data every 1/4 of a block */
2922 +       PvmRowsToSend = (opts.Last_Line - opts.First_Line + 3) / 4;
2923 +
2924 +       /* Last_Column is really "number of columns to do" */
2925 +       opts.Last_Column++;
2926 +       
2927 +       /* check, if a new frame starts */
2928 +       if(frame != f) {
2929 +           if(!first)
2930 +               PvmSendStats();
2931 +           first = 0;
2932 +           PvmNextFrame = opts.FrameSeq.InitialFrame + f;
2933 +           frame = f;
2934 +           return 0;           /* stop with this frame */
2935 +       }
2936 +       
2937 +       /* We need to do this for every block */
2938 +       Initialize_Renderer();
2939 +       
2940 +       return 1;               /* still the same frame */
2941 +
2942 +    case PVM_STOP_SLAVE:       /* Everything is done, send stats and exit */
2943 +       PvmSendStats();
2944 +       PvmNextFrame = opts.FrameSeq.FinalFrame + 1;
2945 +       return 0;
2946 +
2947 +    case PVM_KILL_SLAVE:
2948 +       Error_Line("\nSlave killed because of dead master.\n");
2949 +       pvm_exit();
2950 +       exit(1);
2951 +
2952 +    default: /* Unknown message */
2953 +       Error_Line("\nUnknown control message from master - %X\n",msgtag);
2954 +       pvm_initsend(PvmDataDefault);
2955 +       pvm_send(PvmMTid,PVM_NEED_WORK);  /* Request work again */
2956 +    }
2957 +    return 0;
2958 +}
2959 +
2960 +void Pvm_Slave_Exit() {
2961 +    pvm_initsend(PvmDataDefault);
2962 +    pvm_send(PvmMTid, PVM_SLAVE_EXIT);
2963 +    pvm_exit();
2964 +}
2965 +
2966 +void Pvm_Write_Line(handle, line_data, line_number)
2967 +    FILE_HANDLE     *handle;
2968 +    COLOUR          *line_data;
2969 +    int             line_number;
2970 +{
2971 +    static int in_buffer = 0;
2972 +    static int ncols;
2973 +
2974 +    if (in_buffer == 0) /* No lines written yet. Initialize buffer */
2975 +    {
2976 +       ncols = opts.Last_Column - opts.First_Column;
2977 +       pvm_initsend(PvmDataDefault);
2978 +
2979 +       /* Insert block info into message */
2980 +       pvm_pkint(&frame, 1, 1);
2981 +       pvm_pkint(&PvmBlockNum, 1, 1);
2982 +       pvm_pkint(&line_number, 1, 1);
2983 +       pvm_pkint(&opts.First_Column, 1, 1);
2984 +       pvm_pkint(&ncols, 1, 1);
2985 +    }
2986 +
2987 +    if (pvm_pkCOL(&(line_data[opts.First_Column][0]),5*ncols, 1) < 0) {
2988 +       Error_Line( "Cannot pack in Pvm_Write_Line\n");
2989 +       pvm_perror("");
2990 +       if (in_buffer > 0) {
2991 +           pvm_send(PvmMTid, PvmBlockNum);  /* Send any lines we have done. */
2992 +       }
2993 +       pvm_initsend(PvmDataDefault);
2994 +       pvm_send(PvmMTid, PVM_SLAVE_EXIT); /* Tell the master we're dying */
2995 +       pvm_exit();
2996 +       return;
2997 +    }
2998 +
2999 +    in_buffer++;
3000 +    
3001 +    if (in_buffer >= PvmRowsToSend || line_number >= opts.Last_Line - 1) {
3002 +       if (pvm_send(PvmMTid, PVM_SLAVE_RESULTS) < 0) { 
3003 +           Error_Line( "Cannot send block in Pvm_Write_Line\n");
3004 +           pvm_perror("");
3005 +           pvm_exit();
3006 +           return;
3007 +       }
3008 +
3009 +       in_buffer = 0;
3010 +    }
3011 +} 
3012 +
3013 +
3014 +
3015 +
3016 +
3017 +
3018 +
3019 +
3020 +
3021 +
3022 +
3023 +
3024 +
3025 +
3026 +
3027 +
3028 +
3029 +
3030 +
3031 diff -Naur source.ori/pvm.h source/pvm.h
3032 --- source.ori/pvm.h    Thu Jan  1 01:00:00 1970
3033 +++ source/pvm.h        Sun Sep 12 00:25:35 1999
3034 @@ -0,0 +1,164 @@
3035 +/****************************************************************************
3036 +*  pvm.h
3037 +*
3038 +*  This include module is used by PVM control routines in the PVM'd PovRAY.
3039 +*
3040 +*  This file was written by Brad Kline.  April 1994.
3041 +*                modified by Andreas Dilger,  Feb 1995.
3042 +*                modified by Harald Deischinger, 1996 - April 1997
3043 +*                modified by Jakob Flierl, May 1999
3044 +* 
3045 +*  All the defines that need modification are at the top.
3046 +*
3047 +*  The author disclaims all warranties with regard to this software, 
3048 +*  including all implied warranties of merchant-ability and fitness. 
3049 +*  The code is simply distributed as it is.
3050 +*
3051 +*
3052 +*****************************************************************************/
3053 +
3054 +/* If setpriority() doesn't exist on your system, you should change 
3055 + * "your_pvm_arch" on the following line to whatever your actual PVM_ARCH
3056 + * is (ie ALPHA or SCO), and please email me to tell me about it, so I can
3057 + * add it in permanently.
3058 + */
3059 +
3060 +#include <features.h>
3061 +
3062 +#if defined(SUN4SOL2) || defined(your_pvm_arch)
3063 +
3064 +#define NICE(x) nice(x)
3065 +extern int nice PARAMS((int prio));
3066 +
3067 +#else
3068 +
3069 +/* This should work for the majority of systems */
3070 +
3071 +#define NICE(x) setpriority(PRIO_PROCESS,0,getpriority(PRIO_PROCESS,0)+(x))
3072 +
3073 +#if !(defined __GLIBC__ && __GLIBC__ >= 2)
3074 +extern int setpriority PARAMS((int which, int who, int prio));
3075 +extern int getpriority PARAMS((int which, int who));
3076 +#endif
3077 +#endif
3078 +
3079 +/* How nice to be by default. 0 is the regular job priority, while is 20 very
3080 + * nice.  The nice value can be changed on the command line, so there is
3081 + * probably little reason to change it here.
3082 + */
3083 +#define PVM_DEFAULT_NICE 5
3084 +
3085 +/* On BSD systems, use getwd instead of getcwd.  Change "your_pvm_arch" on
3086 + * the following line to whatever your actual PVM_ARCH is (ie MIPS or CRAY),
3087 + * and please email me to tell me about it, so I can add it in permanently.
3088 + */
3089 +#if defined(NEXT) || defined(your_pvm_arch)
3090 +
3091 +#define GETCWD(path) getwd(path)
3092 +extern char *getwd PARAMS((char *));
3093 +
3094 +#else
3095 +
3096 +#define GETCWD(path) getcwd(path,PATH_MAX+1)
3097 +extern char *getcwd PARAMS((char *, size_t ));
3098 +
3099 +#endif
3100 +
3101 +extern int  chdir PARAMS((const char *path));
3102 +
3103 +/* Grid decomposition defaults */
3104 +#define PVM_DEFAULT_GRID_HEIGHT     32
3105 +#define PVM_DEFAULT_GRID_WIDTH      32
3106 +
3107 +/* what type of encoding to use whan sending pixels */
3108 +#define pvm_upkCOL pvm_upkfloat
3109 +#define pvm_pkCOL pvm_pkfloat
3110 +#define pvm_upkSTAT pvm_upklong
3111 +#define pvm_pkSTAT pvm_pklong
3112 +
3113 +
3114 +/* The maximum path length. _POSIX_PATH_MAX_ = 255 in my limits.h file, but
3115 + * not all systems have this defined, and my base SUN4 install didn't have
3116 + * PATH_MAX in <limits.h>.*/
3117 +#ifndef PATH_MAX
3118 +#ifdef _POSIX_PATH_MAX
3119 +#define PATH_MAX _POSIX_PATH_MAX
3120 +#else  /* _POSIX_PATH_MAX doesn't exist.  A safe guess. */
3121 +#define PATH_MAX 1024
3122 +#endif  /* _POSIX_PATH_MAX */ 
3123 +#endif  /* PATH_MAX */ 
3124 +
3125 +/* Structure to hold info about each slave process */
3126 +typedef struct {
3127 +    char *name;
3128 +    int pixels_done;           /* Number of pixels completed */
3129 +    int pixels_late;           /* Number of pixels finished after another slave did it */
3130 +    int block_reassigned;      /* Block number reassigned to this slave */
3131 +    int frame_assigned;                /* assigned to that frame */
3132 +    int frame_reassigned;      /* reassigned to that frame */
3133 +} pvm_slave_stat;
3134 +#define PVM_SLAVE_FREE           -1
3135 +
3136 +/* Structure to hold info about each grid section */
3137 +typedef struct {
3138 +    int status;          /* Current status of block */
3139 +    int wr_line;         /* Line to be written next */
3140 +    int assigned_tid;    /* Tid of the machine assigned to this block */
3141 +    int reassigned_tid;  /* Tid of the machine reassigned to this block */
3142 +} pvm_block_stat;
3143 +/* Status indicators */
3144 +#define PVM_GRID_POINT_FREE       0
3145 +#define PVM_GRID_POINT_ASSIGNED   1
3146 +#define PVM_GRID_POINT_REASSIGNED 2
3147 +#define PVM_GRID_POINT_DONE       3
3148 +#define PVM_GRID_POINT_WRITTEN    4
3149 +
3150 +
3151 +/* Structure to hold info about each frame */
3152 +typedef struct {
3153 +    int status;
3154 +    COLOUR ** row_ptr;
3155 +    int row_to_write;
3156 +    int row_to_malloc;
3157 +    int block_to_assign;
3158 +    int block_to_reassign;
3159 +    int block_to_write;
3160 +    COUNTER stats[MaxStat];            /* PovRay Status */
3161 +    pvm_block_stat * block_stat;
3162 +    FILE_HANDLE* output_file;
3163 +} pvm_frame_stat;
3164 +#define PVM_FRAME_FREE         0
3165 +#define PVM_FRAME_WORKING      1
3166 +#define PVM_FRAME_DONE         2
3167 +#define PVM_FRAME_DONE_SHELLOUT                3
3168 +
3169 +/* Define some message IDs to be used */
3170 +#define PVM_INIT_SLAVE  1
3171 +#define PVM_STOP_SLAVE  2
3172 +#define PVM_KILL_SLAVE  3
3173 +#define PVM_NEED_WORK   4
3174 +#define PVM_SLAVE_EXIT  5
3175 +#define PVM_SLAVE_STATS 6
3176 +#define PVM_SLAVE_RESULTS 7
3177 +#define PVM_WORK       8
3178 +
3179 +/* Prototypes for public functions defined in pvm.c */
3180 +void Pvm_Master_Init PARAMS((int argc, char **argv));
3181 +void Pvm_Master_Control PARAMS((void));
3182 +void Pvm_Write_Line PARAMS((FILE_HANDLE *handle, COLOUR *line, int row));
3183 +int  Pvm_Slave_Init PARAMS((void));
3184 +int  Pvm_Slave_Control PARAMS((void));
3185 +void Pvm_Slave_Exit PARAMS((void));
3186 +
3187 +extern char     PvmArch[];
3188 +extern int      PvmChunkWidth;
3189 +extern int      PvmChunkHeight;
3190 +extern int      PvmSlave;
3191 +extern int      PvmTasks;
3192 +extern int      PvmNice;
3193 +extern char *  PvmSlavename;
3194 +extern int     PvmNextFrame;
3195 +extern int     PvmBlockNum;
3196 +extern char    PvmWorkingDir[];
3197 +extern char **  PvmHosts;
3198 +extern int     PvmHostsN;
3199 diff -Naur source.ori/render.c source/render.c
3200 --- source.ori/render.c Sat Jun 30 01:49:21 2001
3201 +++ source/render.c     Sat Jun 30 10:08:01 2001
3202 @@ -46,7 +46,9 @@
3203  #include "texture.h"
3204  #include "vbuffer.h"
3205  #include "userio.h"
3206 -
3207 +#ifdef USE_PVM
3208 +#include "pvm.h"
3209 +#endif
3210  
3211  /*****************************************************************************
3212  * Local preprocessor defines
3213 @@ -65,6 +67,10 @@
3214  
3215  #define SUB_PIXEL_GRID_SIZE 16
3216  
3217 +#ifdef USE_PVM
3218 +DBL maxclr;
3219 +#endif
3220 +
3221  /*****************************************************************************
3222  * Local typedefs
3223  ******************************************************************************/
3224 @@ -104,7 +110,9 @@
3225  
3226  static int SuperSampleCount, RadiosityCount;
3227  
3228 +#ifndef USE_PVM
3229  static DBL maxclr;
3230 +#endif
3231  
3232  /* Jitter values are taken from [-0.5*JitterScale, 0.5*JitterScale]. */
3233  
3234 @@ -314,7 +322,9 @@
3235  static int  create_ray (RAY *ray, DBL x, DBL y, int ray_number);
3236  static void supersample (COLOUR result, int x, int y);
3237  static void gamma_correct (COLOUR Colour);
3238 +#ifndef USE_PVM
3239  static void extract_colors (COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey);
3240 +#endif
3241  static void trace_pixel (int x, int y, COLOUR Colour);
3242  static void initialise_histogram (void) ;
3243  static void accumulate_histogram (int x, int y, int on);
3244 @@ -349,7 +359,8 @@
3245  *
3246  * CHANGES
3247  *
3248 -*   -
3249 +*   Oct 1996: Added support for PVM [Deischi]
3250 +*   Jun 2001: Added conditional build for PVM Support [Agaran]
3251  *
3252  ******************************************************************************/
3253  
3254 @@ -368,6 +379,12 @@
3255  
3256    size = (Frame.Screen_Width + 1) * sizeof(COLOUR);
3257  
3258 +#ifdef USE_PVM
3259 +  /*  looks like normal mem leak,  maybe that should be always enabled? */
3260 +  if (Previous_Line!=NULL) POV_FREE(Previous_Line);
3261 +  if (Current_Line!=NULL) POV_FREE(Current_Line);
3262 +#endif
3263 +
3264    Previous_Line = (COLOUR *)POV_MALLOC(size, "previous line buffer");
3265    Current_Line  = (COLOUR *)POV_MALLOC(size, "current line buffer");
3266  
3267 @@ -381,6 +398,12 @@
3268    {
3269      size = (Frame.Screen_Width + 1) * sizeof(char);
3270  
3271 +#ifdef USE_PVM
3272 +    /* again looks like memleak fixup... */
3273 +    if (Previous_Line_Antialiased_Flags!=NULL) POV_FREE(Previous_Line_Antialiased_Flags);
3274 +    if (Current_Line_Antialiased_Flags!=NULL) POV_FREE(Current_Line_Antialiased_Flags);
3275 +#endif
3276 +    
3277      Previous_Line_Antialiased_Flags = (char *)POV_MALLOC(size, "previous line flags");
3278      Current_Line_Antialiased_Flags  = (char *)POV_MALLOC(size, "current line flags");
3279  
3280 @@ -390,6 +413,11 @@
3281        Current_Line_Antialiased_Flags[i]  = 0;
3282      }
3283    }
3284 +#ifdef USE_PVM
3285 +  /* If PVM, this is already enough */
3286 +  if(PvmTasks && !PvmSlave)
3287 +      return;
3288 +#endif
3289  
3290    Assign_Vector(Camera_Ray.Initial, Frame.Camera->Location);
3291  
3292 @@ -3154,8 +3182,11 @@
3293  *   Jun 1995 : Alpha channel support -CEY
3294  *
3295  ******************************************************************************/
3296 -
3297 +#ifdef USE_PVM
3298 +void extract_colors(COLOUR Colour, unsigned char *Red, unsigned char  *Green, unsigned char  *Blue, unsigned char  *Alpha, DBL *grey)
3299 +#else
3300  static void extract_colors(COLOUR Colour, unsigned char *Red, unsigned char  *Green, unsigned char  *Blue, unsigned char  *Alpha, DBL *grey)
3301 +#endif
3302  {
3303    if (opts.PaletteOption == GREY)
3304    {
3305 diff -Naur source.ori/render.h source/render.h
3306 --- source.ori/render.h Sat Jun 30 01:49:21 2001
3307 +++ source/render.h     Sat Jun 30 03:18:56 2001
3308 @@ -59,6 +59,9 @@
3309  extern unsigned long              *histogram_grid ;
3310  extern unsigned long              max_histogram_value ;
3311  extern FILE_HANDLE                *Histogram_File_Handle ;
3312 +#ifdef USE_PVM
3313 +extern DBL                        maxclr;
3314 +#endif
3315  
3316  /*****************************************************************************
3317  * Global functions
3318 @@ -74,6 +77,10 @@
3319  DBL  Trace (RAY *Ray, COLOUR Colour, DBL Weight);
3320  void Check_User_Abort (int Do_Stats);
3321  void write_histogram (char *filename);
3322 +#ifdef USE_PVM
3323 +void extract_colors (COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey);
3324 +#endif
3325 +
3326  void destroy_histogram (void);
3327  
3328  #endif
3329 diff -Naur source.ori/unix/makefile source/unix/makefile
3330 --- source.ori/unix/makefile    Sat Jun 30 03:02:03 2001
3331 +++ source/unix/makefile        Sat Jun 30 11:54:57 2001
3332 @@ -53,7 +53,7 @@
3333  #CFLAGS      = -O6 -finline-functions -ffast-math -c -ansi -m386 -DCPU=586 -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC) $(LIBPNGINC) $(ZLIBINC)
3334  
3335  # Linux compiler flags, Pentium II optimized
3336 -CFLAGS      = $(OPT_FLAGS) -finline-functions -ffast-math -c -ansi -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC)
3337 +CFLAGS      = $(OPT_FLAGS) $(PVMFLAGS) -finline-functions -ffast-math -c -ansi -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC)
3338  
3339  # HPUX compiler flags
3340  #CFLAGS      = +O2 -finline-functions -c -Aa -D_HPUX_SOURCE -DCOMPILER_VER=\".`uname`.$(CC)\" $(SRCINC) $(LIBPNGINC) $(ZLIBINC)
3341 @@ -149,12 +149,15 @@
3342  
3343  # UTARGET is the name of the text-only UNIX version
3344  UTARGET=povray
3345 +UTARGET_PVM=pvmpov
3346  
3347  # XTARGET is the name of the X-Windows executable.
3348  XTARGET=x-povray
3349 +XTARGET_PVM=x-pvmpov
3350  
3351  # STARGET is the name of the SVGA executable.
3352  STARGET=s-povray
3353 +STARGET_PVM=s-pvmpov
3354  
3355  # This is the suffix for object files.
3356  OBJ     = .o
3357 @@ -167,6 +170,13 @@
3358  
3359  SRCINC  = -I. -I$(SRCDIR)
3360  
3361 +# not needed
3362 +#PVMINC                = -I$(PVM_ROOT)/include
3363 +#PVMLIB                = /usr/lib/libpvm3.a /usr/lib/libgpvm3.a        
3364 +PVMLIB         = -lpvm3
3365 +# dunno for what that is used
3366 +XDIR           = $(HOME)/pvm3/bin/$(PVM_ARCH) 
3367 +
3368  #
3369  # End of user specific options
3370  #
3371 @@ -1526,6 +1536,12 @@
3372                            xpovmask.xbm         \
3373                            $(SRCDIR)/povproto.h
3374  
3375 +pvmDEP                  = $(SRCDIR)/pvm.c      \
3376 +                          config.h             \
3377 +                          $(SRCDIR)/pvm.h
3378 +#                          $(UNIXDIR)/unixconf.h
3379 +
3380 +
3381  config.h:
3382         @echo
3383         @echo 'You need to select which executable version you want'
3384 @@ -1549,46 +1565,89 @@
3385  unix:  $(UTARGET)
3386         @echo
3387  
3388 +unix_pvm:      $(UTARGET_PVM)
3389 +       @echo
3390 +
3391  $(UTARGET):    $(POVOBJS) $(ODIR)/unix$(OBJ)
3392         $(CC) $(POVOBJS) $(ODIR)/unix$(OBJ) $(LFLAGS) -o $(UTARGET)
3393  
3394 +$(UTARGET_PVM):        $(POVOBJS) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3395 +       $(CC) $(POVOBJS) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) -o $(UTARGET_PVM)
3396 +
3397  svga:  $(STARGET)
3398         @echo
3399  
3400 +svga_pvm:      $(STARGET_PVM)
3401 +       @echo
3402 +
3403 +
3404  $(STARGET):    $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ)
3405         $(CC) $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ) $(LFLAGS) $(SLIBLIB) -o $(STARGET)
3406  
3407 +$(STARGET_PVM):        $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3408 +       $(CC) $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) $(SLIBLIB) -o $(STARGET_PVM)
3409 +
3410  xwin:  $(XTARGET)
3411         @echo
3412  
3413 +xwin_pvm:      $(XTARGET_PVM)
3414 +       @echo
3415 +
3416  $(XTARGET):    $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ)
3417         $(CC) $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ) $(LFLAGS) $(XLIBLIB) -o $(XTARGET)
3418  
3419 +$(XTARGET_PVM):        $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3420 +       $(CC) $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) $(XLIBLIB) -o $(XTARGET_PVM)
3421 +
3422 +
3423  # Only these files need to be rebuilt if the display type was changed
3424  DISPOBJS = $(ODIR)/povray$(OBJ) $(ODIR)/render$(OBJ) \
3425             $(ODIR)/userio$(OBJ) $(ODIR)/vbuffer$(OBJ)
3426  
3427 +PVMOBJ = $(ODIR)/optin$(OBJ) $(ODIR)/optout$(OBJ) $(ODIR)/povray$(OBJ) $(ODIR)render$(OBJ)
3428 +
3429  newunix:
3430 -       -@$(RM) $(DISPOBJS)
3431 +       -@$(RM) $(DISPOBJS) $(PVMOBJ)
3432         -@cp unixconf.h config.h
3433         -@touch -c $(ODIR)/*$(OBJ)
3434         -@$(MAKE) unix
3435  
3436 +newunix_pvm:
3437 +       -@$(RM) $(DISPOBJS) $(PVMOBJ)
3438 +       -@cp unixconf.h config.h
3439 +       -@touch -c $(ODIR)/*$(OBJ)
3440 +       -@$(MAKE) PVMFLAGS="-DUSE_PVM" unix_pvm
3441 +
3442 +
3443  newsvga:
3444 -       -@$(RM) $(DISPOBJS)
3445 +       -@$(RM) $(DISPOBJS) $(PVMOBJ)
3446         -@cp svgaconf.h config.h
3447         -@touch -c $(ODIR)/*$(OBJ)
3448         -@$(MAKE) svga
3449  
3450 +newsvga_pvm:
3451 +       -@$(RM) $(DISPOBJS) $(PVMOBJ)
3452 +       -@cp svgaconf.h config.h
3453 +       -@touch -c $(ODIR)/*$(OBJ)
3454 +       -@$(MAKE) PVMFLAGS="-DUSE_PVM" svga_pvm
3455 +
3456  newxwin:
3457 -       -@$(RM) $(DISPOBJS)
3458 +       -@$(RM) $(DISPOBJS) $(PVMOBJ)
3459         -@cp xwinconf.h config.h
3460         -@touch -c $(ODIR)/*$(OBJ)
3461         -@$(MAKE) xwin
3462  
3463 +newxwin_pvm:
3464 +       -@$(RM) $(DISPOBJS) $(PVMOBJ)
3465 +       -@cp xwinconf.h config.h
3466 +       -@touch -c $(ODIR)/*$(OBJ)
3467 +       -@$(MAKE) PVMFLAGS="-DUSE_PVM" xwin_pvm
3468 +
3469 +
3470  clean:
3471 -       -@$(RM) $(POVOBJS) $(ODIR)/unix$(OBJ) $(ODIR)/xwindows$(OBJ)
3472 -       -@$(RM) $(ODIR)/svga$(OBJ) $(UTARGET) $(XTARGET) $(STARGET)
3473 +       -@$(RM) $(POVOBJS) pvm$(OBJ) $(ODIR)/unix$(OBJ) $(ODIR)/xwindows$(OBJ)
3474 +       -@$(RM) $(ODIR)/svga$(OBJ) $(UTARGET) $(XTARGET) $(STARGET) $(UTARGET_PVM) 
3475 +       -@$(RM) $(XTARGET_PVM) $(STARGET_PVM) 
3476  
3477  install:
3478         -@cp povray.1 $(POVPATH)/man/man1
3479 @@ -1821,17 +1880,7 @@
3480  $(ODIR)/xwindows$(OBJ) : $(xwindowsDEP)
3481         $(CC) $(CFLAGS) $(XLIBINC) xwindows.c
3482  
3483 -
3484 -
3485 -
3486 -
3487 -
3488 -
3489 -
3490 -
3491 -
3492 -
3493 -
3494 -
3495 +$(ODIR)/pvm$(OBJ) : $(pvmDEP)
3496 +       $(CC) $(CFLAGS) $(SRCDIR)/pvm.c
3497  
3498  
This page took 0.595027 seconds and 3 git commands to generate.