--- povray-3.6.1/source/camera.h.orig Mon Aug 2 18:11:35 2004 +++ povray-3.6.1/source/camera.h Thu Nov 1 20:13:24 2007 @@ -55,6 +55,7 @@ #define CYL_3_CAMERA 9 #define CYL_4_CAMERA 10 #define SPHERICAL_CAMERA 11 +#define STEREOSCOPIC_CAMERA 12 /***************************************************************************** @@ -82,6 +83,9 @@ DBL V_Angle; /* Spherical verticle viewing angle */ TNORMAL *Tnormal; /* Primary ray pertubation. */ TRANSFORM *Trans; /* Used only to record the user's input */ + DBL Zero_Parallax; /* Distance to zero parallax */ + DBL Eye_Separation; /* Eye separation (usually Zero_Parallax/30) */ + DBL Eye_Offset; /* Set to + or - 1/2 eye separation */ }; --- povray-3.6.1/source/parse.cpp.orig Mon Aug 2 18:11:36 2004 +++ povray-3.6.1/source/parse.cpp Thu Nov 1 20:13:24 2007 @@ -1168,6 +1168,9 @@ Make_Vector(New->Focal_Point, HUGE_VAL, HUGE_VAL, HUGE_VAL); old_angle = New->Angle; New->Angle = HUGE_VAL; + New->Zero_Parallax = 1.0; + New->Eye_Separation = 0; + New->Eye_Offset = 0; EXPECT CASE (PERSPECTIVE_TOKEN) @@ -1182,6 +1185,10 @@ New->Type = FISHEYE_CAMERA; END_CASE + CASE (STEREOSCOPIC_TOKEN) + New->Type = STEREOSCOPIC_CAMERA; + END_CASE + CASE (ULTRA_WIDE_ANGLE_TOKEN) New->Type = ULTRA_WIDE_ANGLE_CAMERA; END_CASE @@ -1238,6 +1245,28 @@ END_CASE END_EXPECT break; + + case STEREOSCOPIC_CAMERA: + EXPECT + CASE (ANGLE_TOKEN) + New->Angle = Parse_Float(); + if (New->Angle < 0.0) + Error("Negative viewing angle."); + END_CASE + + CASE5(ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN) + CASE3(PERSPECTIVE_CAMERA, SPHERICAL_TOKEN, CYLINDER_TOKEN) + Expectation_Error("stereoscopic camera modifier"); + END_CASE + + OTHERWISE + UNGET + if(Parse_Camera_Mods(New) == false) + EXIT + END_CASE + END_EXPECT + break; + case ORTHOGRAPHIC_CAMERA: EXPECT CASE (ANGLE_TOKEN) @@ -1406,7 +1435,7 @@ // apply "angle" if (New->Angle != HUGE_VAL) { - if ((New->Type == PERSPECTIVE_CAMERA) || (New->Type == ORTHOGRAPHIC_CAMERA)) + if ((New->Type == PERSPECTIVE_CAMERA) || (New->Type == ORTHOGRAPHIC_CAMERA) || (New->Type == STEREOSCOPIC_CAMERA)) { if (New->Angle >= 180.0) Error("Viewing angle has to be smaller than 180 degrees."); @@ -1534,6 +1563,10 @@ New->Type = FISHEYE_CAMERA; END_CASE + CASE (STEREOSCOPIC_TOKEN) + New->Type = STEREOSCOPIC_CAMERA; + END_CASE + CASE (ULTRA_WIDE_ANGLE_TOKEN) New->Type = ULTRA_WIDE_ANGLE_CAMERA; END_CASE @@ -1826,6 +1859,14 @@ CASE (APERTURE_TOKEN) New->Aperture = Parse_Float(); + END_CASE + + CASE (EYESEPARATION_TOKEN) + New->Eye_Separation = Parse_Float(); + END_CASE + + CASE (ZEROPARALLAX_TOKEN) + New->Zero_Parallax = Parse_Float(); END_CASE CASE (FOCAL_POINT_TOKEN) --- povray-3.6.1/source/parse.h.orig Mon Aug 2 18:11:36 2004 +++ povray-3.6.1/source/parse.h Thu Nov 1 20:13:24 2007 @@ -388,6 +388,9 @@ WIDTH_TOKEN, ARC_ANGLE_TOKEN, PERSPECTIVE_TOKEN, + STEREOSCOPIC_TOKEN, + ZEROPARALLAX_TOKEN, + EYESEPARATION_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, --- povray-3.6.1/source/povmsend.cpp.orig Mon Aug 2 18:11:37 2004 +++ povray-3.6.1/source/povmsend.cpp Thu Nov 1 20:13:24 2007 @@ -763,6 +763,9 @@ break; case kPOVList_Prog_UserAbort: break; + case kPOVList_Prog_Stereo_View: + break; + } return ret; --- povray-3.6.1/source/povmsend.h.orig Mon Aug 2 18:11:37 2004 +++ povray-3.6.1/source/povmsend.h Thu Nov 1 20:13:24 2007 @@ -71,7 +71,8 @@ PROGRESS_RENDERING = kPOVList_Prog_Rendering, PROGRESS_DONE_TRACING = kPOVList_Prog_DoneTracing, PROGRESS_ABORTING_RENDER = kPOVList_Prog_AbortingRender, - PROGRESS_USER_ABORT = kPOVList_Prog_UserAbort + PROGRESS_USER_ABORT = kPOVList_Prog_UserAbort, + PROGRESS_STEREO_VIEW = kPOVList_Prog_Stereo_View, }; --- povray-3.6.1/source/rendctrl.cpp.orig Mon Aug 2 18:11:37 2004 +++ povray-3.6.1/source/rendctrl.cpp Thu Nov 1 20:13:24 2007 @@ -209,6 +209,7 @@ int Diff_Frame; DBL Diff_Clock; SHELLRET Pre_Scene_Result, Frame_Result; + int wasStereo = 0; Diff_Clock = opts.FrameSeq.FinalClock - opts.FrameSeq.InitialClock; @@ -247,8 +248,6 @@ Send_Progress("Processing Frame", PROGRESS_PROCESSING_FRAME); } - setup_output_file_name(); - // Execute a shell-out command before tracing Frame_Result = (POV_SHELLOUT_CAST)POV_SHELLOUT(PRE_FRAME_SHL); @@ -258,7 +257,15 @@ if(Frame_Result != SKIP_ONCE_RET) { - FrameRender(); + // A stereoscopic camera generates two frames: left & right + + if((wasStereo = FrameRender(0))) + { + Send_FrameStatistics(); + + // The left stereo image is done, now do the right + (void) FrameRender(wasStereo); + } // Execute a shell-out command after tracing @@ -268,7 +275,7 @@ break; } - if(opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME) + if(opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME || wasStereo) Send_FrameStatistics(); Do_Cooperate(1); @@ -284,6 +291,10 @@ opts.FrameSeq.FrameNumber++; } + else if(wasStereo) + { + Send_RenderStatistics(true); + } } // Execute the final shell-out command @@ -298,6 +309,7 @@ * FrameRender * * INPUT +* side = 0 for stereo left frame, 1 for stereo right frame * * OUTPUT * @@ -317,8 +329,15 @@ * ******************************************************************************/ -void FrameRender() +int FrameRender(int side) { + // Let caller know if stereoscopic left frame was rendered so this routine + // can be called again to render the right frame + int return_flag = 0; + + // Was stereoscopic camera used? + int wasStereo = 0; + // Store start time for parse. START_TIME @@ -378,6 +397,37 @@ Warning(0, "Focal blur is used. Standard antialiasing is switched off."); } + // Compute stereo camera eye-offset + if(Frame.Camera->Type == STEREOSCOPIC_CAMERA) + { + wasStereo = 1; + + if(side == 0) + { + /* Setup left view */ + Frame.Camera->Eye_Offset = -0.5 * Frame.Camera->Eye_Separation; + + setup_output_file_name(-1); + + return_flag = 1; + + Send_Progress("Initializing Left Stereo View", PROGRESS_STEREO_VIEW); + } + else + { + /* Setup right view */ + Frame.Camera->Eye_Offset = 0.5 * Frame.Camera->Eye_Separation; + + setup_output_file_name(1); + + return_flag = 0; + + Send_Progress("Initializing Right Stereo View", PROGRESS_STEREO_VIEW); + } + } + else + setup_output_file_name(0); + // Create the bounding box hierarchy. Stage = STAGE_SLAB_BUILDING; @@ -407,7 +457,16 @@ // Get the parsing time. STOP_TIME tparse = TIME_ELAPSED + /* + * What does this do? It seems to just add "0K tokens" to the end of the + * last message printed. Usually, the message was the "Creating bounding + * slabs". But if that message was not printed, then the previous message + * used to be "Parsing"... is this supposed to always say "Parsing 0k + * tokens"? That does not seen reasonable. If a stereoscpoic camera is + * used, then the message "Initializing xxxxx Stereo View" gets "0K tokens" + * added to it. This does not make sense. Send_ProgressUpdate(PROGRESS_PARSING, 0); + */ // Output parsing statistics. Send_ParseStatistics(); @@ -585,7 +644,7 @@ // Print stats ... Send_RenderStatistics(); - if(opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME) + if(opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME || wasStereo) { // Add them up sum_statistics(totalstats, stats); @@ -596,6 +655,8 @@ // Restore variable values. variable_store(RESTORE); + + return return_flag; } /***************************************************************************** --- povray-3.6.1/source/rendctrl.h.orig Mon Aug 2 18:11:37 2004 +++ povray-3.6.1/source/rendctrl.h Thu Nov 1 20:13:24 2007 @@ -41,7 +41,7 @@ void fix_up_rendering_window (void); void fix_up_animation_values (void); void fix_up_scene_name (void); -void FrameRender (void); +int FrameRender (int); void FrameLoop(); void variable_store (int Flag); --- povray-3.6.1/source/render.cpp.orig Mon Aug 2 18:11:37 2004 +++ povray-3.6.1/source/render.cpp Thu Nov 1 20:13:24 2007 @@ -2707,7 +2707,7 @@ DBL x0 = 0.0, y0 = 0.0; DBL cx, sx, cy, sy, ty, rad, phi; - VECTOR V1; + VECTOR V1, tempv; TRANSFORM Trans; if ( opts.Language_Version >= 350 ) @@ -2758,6 +2758,34 @@ break; + /* + * Stereoscopic perspective camera + */ + case STEREOSCOPIC_CAMERA: + // Normalised projection plane cooredintes from -0.5 to 0.5. + x0 = x / (DBL)Frame.Screen_Width - 0.5; + y0 = ((DBL)(Frame.Screen_Height - 1) - y) / (DBL)Frame.Screen_Height - 0.5; + + // Offset ray length + x0 -= Frame.Camera->Eye_Offset / (2 * Frame.Camera->Zero_Parallax * tan(Frame.Camera->Angle * M_PI_360)); + + // Create primary ray + VLinComb3(Ray->Direction, 1.0, FCD, x0, FCR, y0, FCU); + + // Offset the camera + VNormalize(tempv,FCR); + VAddScaled(Ray->Initial,Frame.Camera->Location,Frame.Camera->Eye_Offset,tempv); + + // Do focal blurring (by Dan Farmer). + if (Focal_Blur_Is_Used) { + jitter_camera_ray(Ray, ray_number); + initialize_ray_container_state(Ray, true); + } else { + initialize_ray_container_state(Ray, Precompute_Camera_Constants); + Precompute_Camera_Constants = false; + } + break; + /* * Orthographic projection. */ @@ -2835,6 +2863,7 @@ return(false); } + // Could be replaced by phi = atan2(y0,x0); if (rad == 0.0) { phi = 0.0; --- povray-3.6.1/source/renderio.cpp.orig Mon Aug 2 18:11:38 2004 +++ povray-3.6.1/source/renderio.cpp Thu Nov 1 20:13:24 2007 @@ -317,6 +317,7 @@ * setup_output_file_name * * INPUT +* stereoview: less than 0 for left, greater than 0 for right * * OUTPUT * @@ -328,8 +329,9 @@ * * DESCRIPTION * -* Determine the file name for this frame. For an animation, the frame -* number is inserted into the file name. +* Determine the file name for this frame. For stereo, a 'L' or 'R' +* is inserted into the file name. For an animation, the frame +* number is inserted. * * CHANGES * @@ -338,7 +340,7 @@ * ******************************************************************************/ -void setup_output_file_name() +void setup_output_file_name(int stereoview) { char number_string[10]; char *plast_period; @@ -350,7 +352,57 @@ if(opts.FrameSeq.FrameType!=FT_MULTIPLE_FRAME || opts.Options & TO_STDOUT) { - strcpy(opts.Output_Numbered_Name,opts.Output_File_Name); + if (stereoview == 0) + strcpy(opts.Output_Numbered_Name,opts.Output_File_Name); + else + { + /* + * This is the maximum number of characters that can be used of the + * original filename. This will ensure that enough space is available + * for the frame number in the filename + */ + + available_characters = POV_NAME_MAX-1; + + plast_period = strrchr(opts.Output_File_Name, '.'); + + if (plast_period == NULL) + { + Error("Illegal file name %s -- no extension.", opts.Output_File_Name); + } + + ilast_period = plast_period - opts.Output_File_Name; + + fname_chars = ilast_period; + + if (fname_chars > available_characters) + { + /* Only give the warning once */ + + if (opts.FrameSeq.FrameNumber == opts.FrameSeq.InitialFrame) + { + Warning(0, "Need to cut the output filename by %d characters.", + ilast_period - available_characters); + } + + fname_chars = available_characters; + } + + /* Perform actual generation of filename */ + + strncpy(opts.Output_Numbered_Name, opts.Output_File_Name, (unsigned)fname_chars); + + /* strncpy doesn't terminate if strlen(opts.Output_File_Name) 0) + strcat(opts.Output_Numbered_Name, "R"); sprintf(number_string, "%0*d", opts.FrameSeq.FrameNumWidth, opts.FrameSeq.FrameNumber); --- povray-3.6.1/source/renderio.h.orig Mon Aug 2 18:11:38 2004 +++ povray-3.6.1/source/renderio.h Thu Nov 1 20:13:24 2007 @@ -38,7 +38,7 @@ void Read_Rendered_Part(char *New_Fname); void init_output_file_handle(); void destroy_output_file_handle(); -void setup_output_file_name(); +void setup_output_file_name(int stereo); void open_output_file(); void output_prev_image_line_and_advance(int y); void output_single_image_line_with_alpha_correction(COLOUR *Line, int y); --- povray-3.6.1/source/tokenize.cpp.orig Mon Aug 2 18:11:38 2004 +++ povray-3.6.1/source/tokenize.cpp Thu Nov 1 20:13:24 2007 @@ -598,6 +598,9 @@ {SQR_TOKEN, "sqr"}, {STAR_TOKEN, "*"}, {STATISTICS_TOKEN, "statistics"}, + {STEREOSCOPIC_TOKEN,"stereoscopic"}, + {ZEROPARALLAX_TOKEN,"zeroparallax"}, + {EYESEPARATION_TOKEN,"eyeseparation"}, {STRCMP_TOKEN, "strcmp"}, {STRENGTH_TOKEN, "strength"}, {STRING_ID_TOKEN, "string identifier"}, --- povray-3.6.1/source/base/povmsgid.h.orig Mon Aug 2 18:11:35 2004 +++ povray-3.6.1/source/base/povmsgid.h Thu Nov 1 20:13:24 2007 @@ -348,7 +348,8 @@ kPOVList_Prog_Rendering, kPOVList_Prog_DoneTracing, kPOVList_Prog_AbortingRender, - kPOVList_Prog_UserAbort + kPOVList_Prog_UserAbort, + kPOVList_Prog_Stereo_View, }; #endif /* POVMSGID_H */ --- /dev/null Thu Nov 1 20:04:38 2007 +++ povray-3.6.1/scenes/advanced/ionic5/ionic5.ini Thu Nov 1 02:03:32 2007 @@ -0,0 +1,14 @@ +Antialias=on +Antialias_Threshold=0.3 + +Input_File_Name=ionic5.pov + +Output_File_Type=N +Width=768 +Height=480 + +Display=on + +;If stereo camera was used, use ImageMagick to create an anaglyph +Post_Scene_Command="test -f %sR.png && composite -stereo %sR.png %sL.png %sA.png" +Post_Scene_Return=I --- povray-3.6.1/scenes/advanced/ionic5/ionic5.pov.orig Mon Aug 2 18:16:15 2004 +++ povray-3.6.1/scenes/advanced/ionic5/ionic5.pov Thu Nov 1 01:58:05 2007 @@ -12,7 +12,7 @@ // images have been replaced with single colors, and a third column // was added to the bottom row. // -// Three cameras are included, the original, and two for stereo. +// Two cameras are included, the original, and stereo. // gamma devised to approximate the illustration in Ray Tracing Creations II // updated for compatibility with POV-Ray v3.5 by Ken Tyler on 08-26-01 @@ -41,24 +41,21 @@ right <4/3, 0, 0> } -// Optional stereo views: -/* camera for left eye, render at 768 x 480 or similar aspect ratio */ +// Optional stereo view: +/* Render at 768 x 480 or similar aspect ratio */ /* +#declare VP = <-40, 80, -220>; +#declare ZEROP = 166; // Distance to zero parallax camera { - location <-61, 80, -220> - direction <0, 0, 1.4> - up <0, 1, 0> - right <1.6, 0, 0> -} -*/ - -/* camera for right eye, render at 768 x 480 or similar aspect ratio */ -/* -camera { - location <-39, 80, -220> - direction <0, 0, 1.4> - up <0, 1, 0> - right <1.6, 0, 0> + stereoscopic + location VP + up y + right image_width*x/image_height + angle 60 + sky <0,0,1> + look_at VP + <0,0,200> + zeroparallax ZEROP + eyeseparation ZEROP / 30 } */ --- /dev/null Thu Nov 15 17:15:23 2007 +++ povray-3.6.1/scripts/Post_Frame_Command.sh Thu Nov 15 16:23:15 2007 @@ -0,0 +1,46 @@ +#!/bin/sh + +# POV Post_Frame_Command script +# +# If using a sterescopic camera, make the anaglyph image from the left and +# right pairs. Do this whether or not an animation is being rendered. +# Requires ImageMagick's 'composite' command. +# +# Usage: From a povray .INI file: +# +# Post_Frame_Command="Post_Frame_Command.sh h=%h n=%n o='%o' s='%s' w=%w" +# + +while [ $# -gt 0 ] +do + case "$1" in + [hnosw]=*) + var=`expr "$1" : '\(.\)=.*$' | tr '[a-z]' '[A-Z]'` + val="`expr "$1" : '.=\(.*\)$'`" + eval $var=\"$val\" + ;; + *) + echo Usage: $0 h=%h n=%n o=\'%o\' s=\'%s\' w=%w + exit 1 + ;; + esac + shift +done + +sfx="`expr "$O" : '.*\.\(.*\)$'`" + +case "${N}-${O}" in + 0-${S}R.$sfx) + # Stereo, no animation + test -f "${S}L.$sfx" && + composite -depth 8 -stereo "${S}R.$sfx" "${S}L.$sfx" "${S}A.$sfx" + ;; + *-${S}R*.$sfx) + # Stereo, animation frame + digits=`expr "$O" : "${S}R\([0-9][0-9]*\)\."` + test -f "${S}L${digits}.$sfx" && + composite -depth 8 -stereo "${S}R${digits}.$sfx" "${S}L${digits}.$sfx" "${S}A${digits}.$sfx" + ;; +esac + +exit 0 --- /dev/null Thu Nov 15 17:15:23 2007 +++ povray-3.6.1/scripts/Post_Scene_Command.sh Thu Nov 15 17:19:12 2007 @@ -0,0 +1,109 @@ +#!/bin/sh + +# POV Post_Scene_Command script +# +# Run 'mencoder' after an animation has been rendered. The individual frame +# images are combined to produce an '.AVI' movie. If a stereoscopic camera +# was used, combine the anaglyph frame images to produce an anaglyph '.AVI' +# movie. Requires the 'mencoder' command. +# +# This script may not work correctly if the Subset_End_Frame (+EF) option is +# used; POV does not set %n to the final frame number plus one, but sets %n to +# the number of the final frame rendered in this run. Since this script uses +# the value of %n to verify that all frames of the video have been rendered, it +# will not detect the case when frames %n to the final frame have not yet been +# rendered. POV does not provide enough information for this script to adapt +# to this special case. +# +# Usage: From a povray .INI file: +# +# Post_Scene_Command="Post_Scene_Command.sh h=%h n=%n o='%o' s='%s' w=%w" +# + +while [ $# -gt 0 ] +do + case "$1" in + [hnosw]=*) + var=`expr "$1" : '\(.\)=.*$' | tr '[a-z]' '[A-Z]'` + val="`expr "$1" : '.=\(.*\)$'`" + eval $var=\"$val\" + ;; + *) + echo Usage: $0 h=%h n=%n o=\'%o\' s=\'%s\' w=%w + exit 1 + ;; + esac + shift +done + +sfx="`expr "$O" : '.*\.\(.*\)$'`" + +case "${N}-${O}" in + 0-*) + # No animation + ;; + *-${S}[0-9]*.$sfx) + # Plain animation (no stereo) + digits=`expr \`echo \\\`expr "${O}" : "${S}\([0-9][0-9]*\)\."\\\` | wc -c\` - 1` + + pat= + n=1 + while [ $n -le $digits ] + do + pat="$pat[0-9]" + n=`expr $n + 1` + done + + encode=true + n=1 + while [ $n -lt $N ] + do + if [ -f "${S}`printf "%0${digits}d" $n`.$sfx" ] + then + n=`expr $n + 1` + continue + fi + encode=false + break + done + + # Comment out one or the other depending on your needs. + $encode && + mencoder "mf://${S}${pat}.$sfx" -mf type="$sfx" -o "${S}.avi" -ffourcc DIVX50 -ovc lavc -lavcopts vcodec=mpeg4 + $encode && + ffmpeg -i ${S}%${digits}d.$sfx -y -b 1500 -f mp4 -vcodec mpeg4 -r 25 -bitexact -g 250 -v 5 -hq -r ntsc "${S}.mp4" + ;; + *-${S}R[0-9]*.$sfx) + # Stereo animation + digits=`expr \`echo \\\`expr "${O}" : "${S}R\([0-9][0-9]*\)\."\\\` | wc -c\` - 1` + + pat= + n=1 + while [ $n -le $digits ] + do + pat="$pat[0-9]" + n=`expr $n + 1` + done + + encode=true + n=1 + while [ $n -lt $N ] + do + if [ -f "${S}A`printf "%0${digits}d" $n`.$sfx" ] + then + n=`expr $n + 1` + continue + fi + encode=false + break + done + + # Comment out one or the other depending on your needs. + $encode && + mencoder "mf://${S}A${pat}.$sfx" -mf type="$sfx" -o "${S}A.avi" -ffourcc DIVX50 -ovc lavc -lavcopts vcodec=mpeg4 + $encode && + ffmpeg -i ${S}A%${digits}d.$sfx -y -b 1500 -f mp4 -vcodec mpeg4 -r 25 -bitexact -g 250 -v 5 -hq -r ntsc "${S}A.mp4" + ;; +esac + +exit 0