Building The Persistence of Vision Raytracer Version 3.0 on OpenVMS using DEC C Carl D. Perkins (carl@gerg.tamu.edu) 1996, August, Sometime late at night. Note: As is, POVray 3.0 is Alpha only: it won't work on a VAX based system due to the requirement for IEEE floating point numbers in the file OCTREE.C. (Unless DEC C on a VAX lets you fake it, which is unlikely and which would be very slow.) The only way around this would be to figure out what OCTREE.C is doing and either make it generic to any floating point format or to make a VAX specific version that does its bitwise manipulations on the VAX floating point format you use. As far as I know no other file has anything in it that requires the numbers be in IEEE format, although a couple might require tweaking a few constants - do a "search *.c ieee" to see which files. Now, I am in favor of as much speed in processing as is reasonable (or even unreasonable) but the person who thought up doing direct bitwise operations on floating point numbers, which would presumably be Jim McElhiney since he wrote the oct-tree stuff, should probably be smacked upside the head with a moderately large semi-hard blunt object (wouldn't want to do too much damage or he won't be able to add more to POV), but I digress. When compiling, I used DEC C in the strict ANSI89 mode. This is probably not really needed, but I did it anyway. Actually, this just shows that the POV Team did a good job of producing ANSI compliant code since I never found any problems in this area. I am doing the vanilla version, not the X version. See 2B below. Building the X version should be essentially the same, under the assumption that X is X and DECwindows is too - which is mostly true. If they try to fool with the root window anywhere it probably won't work without mucho fiddling in that part though (since DECwindows uses a pseudo-root as the thing actually showing up as the background on screen). Also, this guide is somewhat conversational in tone (not to mention that it complains a lot - this version of POVray is somewhat harder to get to work on VMS than 2.2 was, largely due to added bits that make some silly, in this case, assumptions about how the OS and/or filesystem works). There are also an enormous number of parenthetical remarks explaining why specific changes are being made or for other informational purposes, plus some that are just complaining, and a few that are there for no good reason at all. Keep in mind that this was written mostly very late at night (for example, as I type this it is so late at night that it is definitely morning - the sun has been up over the horizon for more than an hour). You should read the whole thing before you try any of it - after reading it you may well decide not to try building POVray, but you would select that option only if you were a pantywaist. One more note. To some degree I attempted to avoid making changes in a way that would prevent them from being folded back into the real source distribution. Unfortunately I didn't actually completely stick to this attempt - although doing the ifdef/ifndef type thing with those bits should be easy. Oh well. OK, now lets get this thing rolling. First, get the unix distribution. Hey, VMS is unix too (since it is Posix compliant and all - almost all of the changes you need to make are with the parts that interact with the filesystem, which is somewhat unlike your typical unix filesystem). The version I got comes in two parts which are tar files compressed with gzip; this requires that you have GNU zip and a tar utility (like VMSTAR, which works great). Then, unpack the source distribution (the POVUNI_S part) somewhere with at least 20MB of disk space. I am assuming the directory structure of the tar file is preserved, and ignoring directory levels higher that the POVRAY3 level (i.e. as far as I am concerned, the thing starts at POV_ROOT:[POVRAY3]). I am not using any of the "make" compatible software available for VMS. I did, however take advantage of the MMS stuff when building Zlib and LibPNG (this should not matter - the instructions are the same without it). 1) Build Zlib - SET DEF to [POVRAY3.SOURCE.ZLIB] and do an @make_vms Yep - this package is VMS ready straight out of the box. A) Unless you have the freeware (I think it is) "xvmsutils" package installed (which I don't, I have it but have not actually built it yet) the MINIGZIP demo will not link. This is inconsequential, although you might find the fatal errors this produces a bit disconcerting. Ignore them. This is the last thing the build procedure tries to do, so everything you need done is done. Alternately, you could eliminate it from the build - if you have MMS edit the DESCRIP.MMS file and change the line "all : example.exe minigzip.exe" to "all : example.exe #minigzip.exe" which will comment out the attempt to build it; likewise you could edit it out of the non-MMS .com build thingy. B) Once this is done, you can delete all the .obj files. In fact, you can delete everything but the ZLIB.OLB file and the ZLIB.H and ZCONF.H files at this point if you really want to (or need the disk space, this is about 1.1MB), unless this violates the license in which case you should probably keep any documantation on licensing (I havn't looked). 2) Build Libpng - SET DEF to [POVRAY3.SOURCE.LIBPNG] and do an @makevms This too is VMS ready out of the box. A) Worked fine, no errors, warnings, or what have you. Once the object library is built you can delete the .OBJ files. As with Zlib, you can actually delete a bunch more than that but be sure to keep the LIBPNG.OLB file and the PNG.H and PNGCONF.H files - everything else can be deleted at this point if you want to (or need the disk space, this is about 1.4MB) 3) Prepare to build POVray. A) If you haven't already, you might want to review the COMPILE.DOC file. This explains most of what I will be doing here. B) I will not be including the X11 support - it slows the render down (even when it is turned off it slows it down a small but measurable amount). Well, I am assuming this is true - it was for version 2.2 and will certainly still be true to some degree, although perhaps not as much. (Of course, this may only be noticeable to me because I tend to do renders that take time in the range of hours rather than minutes a lot of the time.) C) SET DEF to [POVRAY3.SOURCE.UNIX] D) Do a :"copy unixconf.h config.h". Edit config.h with your favorite editor. Add a section after the initial comments: /* * include files they seem to have left out which come in real handy for VMS */ #include #include #include #include Add 5 lines after the definition of EPSILON line. I believe the gamma of 1.8 appears to be correct on my DEC 3000m600 with base graphics and VRC21-Hx monitor, you can follow the instructions in [POVRAY3.SOURCE.UNIX] GAMMA.GIF_TXT to check your display's gamma value. The main() function is supposed to return an int, not a void - lots of silly PC (and Unix, apparently) people do the void thing, which is wrong. Main is supposed to return a status value, which it can't do if'n you make it a void. POVray's file name & path parsing stuff is fairly hopeless when it comes to VMS. Best I've found is to make the FILENAME_SEPARATOR equal to "]" and modify a couple of spots in the file finding routine so that it doesn't slap an extra one in there (like it does for include files that are not in the current directory, so that if you have a library path defined to be A:[B] looking for file C.D it ends up trying to find A:[B]]C.D without the mods) ( The closest other thing I tried was to make the stinking separator a null, which worked until it tried to open the output file which ended up going from A.B to A.BA.B since the end of string null was interpreted as indicating that the entire output filespec was a path with no file name so it built a file name internally which was not what I had in mind) (another possibility would be to make the DRIVE_SEPARATOR be "]", but I never got around to trying that). And then there is the READ_FILE_STRING mode for opening files and whatnot. For some unknown reason, the POV people want to use only one mode for all reading and one mode for all writing. Frankly, this is nonsense - text files should use modes r and w and the various binary type files (image data, mostly) should use modes rb and wb. And never the twain shall meet. Except that here they do. I have changed the read mode to be "r" rather than the default "rb" - if you don't, it won't read the resource file or the POV scene file(s) correctly under VMS since in binary mode it eats the record separator info and you end up with it thinking the entire file is in one single record. The instant it hits the first comment, the rest of the file becomes part of that comment since it is all part of the same stinking single stream of bytes - which is, of course, wrong. So I do all opens for reading in "r" mode. It seems to work, although this is almost certainly a happy coincidence brought on by the reading in of all files one byte at a time, as they do, using the getc() function (which is also rather weird and inefficient, at least for the text files, if you ask me). Anyhow, it does seem to work OK doing all writing in binary mode and all reading not. Go figure. #define DELETE_FILE(name) delete(name) #define DEFAULT_DISPLAY_GAMMA 1.8 #define MAIN_RETURN_TYPE int #define FILENAME_SEPARATOR ']' #define READ_FILE_STRING "r" Change line defining PRECISION_TIMER_AVAILABLE to: #define PRECISION_TIMER_AVAILABLE 0 Change lines defining POV_NAME_MAX and FILE_NAME_MAX in default case (last two in "if" section starting "#if defined (PATH_MAX)") to: # define POV_NAME_MAX 32 # define FILE_NAME_MAX 128 Note that the instructions as to what FILE_NAME_MAX is for are not really correct, at least not for VMS. VMS uses a 32.32 max format so the expected values would be 32 and 64 if you expect them to mean what the frames.h file indicates - but the FILE_NAME_MAX needs to be big enough to hold not just the file name and extender, but all the device and directory info as well. This should be the case on other platforms too, actually. If you are in the habit of using long logical names for your devices or a lot of subdirectory levels with long names you might want to make FILE_NAME_MAX be 256 instead. E) Go down to step 8 of these instructions and look at part B thereof - if you decide to do that, you may want to do that now before it is too late. At any rate you will need to remove the leading "/" from that file name. Change: strncat(ini_name, "/.povrayrc", FILE_NAME_MAX); \ to be: strncat(ini_name, ".povrayrc", FILE_NAME_MAX); \ or whatever file name you decide to use as per 8B (with no leading "/"). F) copy config.h up into [POVRAY3.SOURCE] 4) Build Unix directory stuff. A) do this: $ CC :== CC/STAND=ANSI89/FLOAT=IEEE/PLUS/NOPREFIX/INCLUDE=([-],[]) to get the compiler to behave the way I want it to. Alternately, if you are on a system with a newer version of C than I have (old, V4.0) you can probably use: $ CC :== CC/STAND=ANSI89/FLOAT=IEEE/PLUS/PREFIX=ALL/INCLUDE=([-],[]) The difference is that the old version doesn't do IEEE floating point in a fully native manner which means that you have to use NOPREFIX on compilation and then explicitly link against a couple of object libraries. If you can get away with not doing this, you should do so since the code produced will be smaller - on the other hand linking against the shareable image could just possible be slightly slower... a) How to tell if you can get away with doing it the easy way is this: Compile this program with the PREFIX=ALL version: #include main() { float qty1; qty1 = 1.0; printf ("qty1 = %f\n", qty1); return 1; } And link it like this: LINK X (where X is what you called it). Now run it If it says "qty1 = 1.000000" then you have the new version. If it says "qty1 = 0.250000" then you have the old version like I do. This happens because the bit pattern for 1.0 in IEEE floating point (type S) is the same as the bit pattern for .25 in VAX D_FLOAT format. Any math you might do is done correctly in either case, but the printf() routine (and any other RTL routine you call) will misinterpret it as a VAX format unless you explicitly link it against the versions of the routines that understand IEEE (which is done automatically in the new version; at least, this is what I have been told by people with newer versions). (Yes, I know - I need to upgrade. The version I have is 2+ years old.) B) "CC unix.c" C) If that worked, and it should have, then things are going well so far. If it didn't work, then your system is not like my system since it worked fine and dandy on the first try for me - you're on your own. D) do a RENAME UNIX.OBJ [-]*.*/LOG to move it up into the source directory. 5) Prepare to build POVray. "Set def [-]" back up to the source directory. A) modify the CC command's include qualifier a tad: $ CC :== CC/STAND=ANSI89/FLOAT=IEEE/PLUS/NOPREFIX/INCLUDE=([.libpng],[.zlib]) (Or make the NOPREFIX a PREFIX=ALL if you can use that.) B) Edit MEM.C and "ifndef" out the pov_memmov() routine - as far as DEC C is concerned it is junk (riddled with illegal operations with pointers in mathematical expressions). Fortunately we don't need it since we have a memmove() function to use. In front of the line that says: void *pov_memmove (dest, src, length) put this line: #ifndef __DECC and after the last lines in the function, which look like this: return dest; } put this: #endif This will make DEC C skip compiling this function (not just under VMS, but under Digital Unix too, which I would expect to also have all of the problems with it that we do and which should also have a memmove() of its own). C) Edit GIFDECODE.C and put the missing "t" back at the start of the line that says: ypedef unsigned char UTINY; D) Edit OPTOUT.H so that it tells everyone something other than "FILL IN NAME HERE" when it is run (so's they'll know who to blame). Change the line that says: #define DISTRIBUTION_MESSAGE_2 "FILL IN NAME HERE........................." To be something else, like your name. I used "Carl D. Perkins, Super-Genius Extraordinaire". But if you use my name I'll have to come over and blow up your computer. Really. They'll make me. It's in the POVray license, encoded in a microdot as the last period in the file, or so they tell me. E) Edit OPTIN.C so that the section delimiter is no longer the square brackets! If you don't do this, you will never be able to read the .POVRAYRC file since the directory it is in will be parsed as a section in the file. What it does to me is it takes the generated location of the RC file of "$DISK1:[CARL].POVRAYRC" and uses "$DISK1:" as the file name with the "[CARL]" indicating that you only want to run that section of it. I am changing this delimiter to "< >" for the input to the parsing routine only - inside the RC file it will still be "[ ]". Note: this changes the behavior and is not reflected in the documentation! If at some point you try this and it doesn't work because you are still using the old "[ ]" for indicating a section since you forgot about this, it's not my fault! (It is actually the POVteam's fault for using a delimiter that is non-universally free from meaning elsewhere, although such a thing might be difficult to find; it really should be a whole separate options switch instead of concatenating it onto the filename!) Also note that technically speaking the "< >" style brackets are actually legal to use instead of the "[ ]" brackets for the directory delimiters on VMS. C'est la vie. In the parse_ini_file() routine, change the line while ((*source != '\0') && (*source != '[')) to be the lines #ifdef __VMS while ((*source != '\0') && (*source != '<')) #else while ((*source != '\0') && (*source != '[')) #endif and change the line while ((*source != '\0') && (*source != ']')) to be the lines #ifdef __VMS while ((*source != '\0') && (*source != '>')) #else while ((*source != '\0') && (*source != ']')) #endif F) Edit POVRAY.C to modify the Locate_File() routine. This is to get it to work with the VMS file system properly. Change the lines in Locate_File() that say: if (file0[strlen(file0) - 1] != DRIVE_SEPARATOR) file0[strlen(file0)] = FILENAME_SEPARATOR; To be the lines if ((file0[strlen(file0) - 1] != DRIVE_SEPARATOR) && (file0[strlen(file0) - 1] != FILENAME_SEPARATOR)) file0[strlen(file0)] = FILENAME_SEPARATOR; which will keep it from adding a second "]" between the "disk:[dir]" library paths and the name of the file you want to get that is down the path. 6) Compile POVray. This is where that "/PLUS_LIST_OPT" qualifier comes in. I have grouped some of the files together for the compiles to get better cross-file optimizations using this scheme (with CC A+B+C/PLUS_LIST_OPT each file is parsed individually, mostly, but after parsing they are treated as one entity by the code generator). Note that this can take a bit of memory, the process I did these in got up to 54MB of (virtual) memory. If you run out of memory, and can't up your account's working set and/or pagefile quota (or the relevant system parameter), you will need to break these up into smaller chunks (I think I should also point out that if you can't use enough memory to do this compile, you also will not be able to render any scenes with seriously high complexity - although this is much less true than it was in older version before the mesh object type was introduced). Note that the groupings I picked may not actually be the best choices since I am not certain what is done where - ideally the majority of the rendering loop and everything it calls most frequently would all be done together, and the parsing would likewise all be in one unit. With any luck I have at least come close. If you are feeling adventurous or have a large working set and pagefile quota you might consider grouping them together into even fewer larger groups. A command procedure that will do the compiling for you; if it works it should take a few minutes. If it doesn't work you should see some sort of an explanation, i.e. the VMS error message(s) associated with the problem. $! Compile prepared POVray source $! $! /NOPREFIX qualifier can be changed to /PREFIX=ALL if the compiler & linker $! will do the IEEE thing properly with your version of them $! $ CC := CC/STAND=ANSI89/FLOAT=IEEE/PLUS/NOPREFIX/INCLUDE=([.libpng],[.zlib]) $! $! A) Group 1, the main program, parsing routines, and routines used most $! extensively by them (i.e. MEM.C) $! $ CC POVRAY+PARSE+TOKENIZE+EXPRESS+CSG+MEM+OPTIN+OPTOUT+USERIO+CAMERA $! $! B) Group 2, the texture related stuff $! $ CC TEXTURE+PARSTXTR+COLOUR+PATTERN+PIGMENT+IMAGE+TXTTEST+WARPS $! $! C) Group 3, the image related routines $! $ CC GIF+GIFDECOD+PGM+PPM+PNG_POV+TARGA+IFF $! $! D) Group 4, object types and whatnot (this is the biggest memory user, $! about 54MB total virtual memory used) $! $ CC ATMOSPH+BEZIER+BLOB+BSPHERE+CONES+DISCS+FRACTAL+HCMPLX+LATHE+MESH+- PLANES+POLY+POLYGON+POLYSOLV+PRISM+QUADRICS+QUATERN+SOR+SPHERES+SUPER+TORUS+- TRIANGLE+TRUETYPE $! $! E) Group 5, those all important rendering, lighting, and related routines $! (a couple of object types snuck into this group - my quick peek at who $! called what seemed to indicate they had some routines that were called $! a lot in here, although I could be wrong - the object group is rather $! crowded anyway) $! $ CC RENDER+BBOX+CHI2+LIGHTING+NORMAL+OBJECTS+OCTREE+RADIOSIT+RAD_DATA+RAY+- LBUFFER+VBUFFER+VLBUFFER+BOXES+HFIELD+MATRICES+HALOS+POINT $! $ exit F) What we've got... At this point you should have these files which you have produced in this phase: ATMOSPH.OBJ GIF.OBJ POVRAY.OBJ RENDER.OBJ TEXTURE.OBJ And some from earlier phases: UNIX.OBJ [.LIBPNG]LIBPNG.OLB [.ZLIB]LIBZ.OLB Once you've gotten this far, all you need to do is... 7) Link POVray's bits'n'pieces together. A) That is done via this command: $ LINK POVRAY,TEXTURE,GIF,ATMOSPH,RENDER,UNIX,- [.LIBPNG]LIBPNG/LIB,[.ZLIB]LIBZ/LIB,- ALPHA$LIBRARY:VAXCRTLT/LIB,ALPHA$LIBRARY:VAXCRTL/LIB (the order of the libraries at the end is important, if you reverse the first two the modules in LIBPNG won't find the Zlib routines they call, which may seem strange but it is Just The Way It Works. Likewise with the rest - order counts!) If you have a compiler & linker that support the /PREFIX=ALL version of doing it, you can leave off the last two libraries from the ALPHA$LIBRARY directory. 8) Post processing. You should have probably looked at the README.UNIX file in the UNIX subdirectory long before now - if not you should look at it now, ignoring the bits covering stuff we've already covered. A) Move POVray to where you want it to live. I prefer to put it in a directory that has (or will have) all the additional include files and examples in subdirectories below it. B) Move the sample [.UNIX].povrayrc file to the same place. Note that this file is actually called "POVRAYRC." in the [.UNIX] directory for some unknown reason. On VMS it is a tad tricky to rename a file so that it has no name before the "." since the COPY and RENAME commands use the input filename's parts as defaults, so a COPY POVRAYRC. .POVRAYRC just gives you a file called POVRAYRC.POVRAYRC which is not quite what you might have in mind. You need to trick it. a) CREATE .POVRAYRC b) control-Z out of the create c) COPY/CONCAT .POVRAYRC,POVRAYRC. disk:[directory].POVRAYRC To avoid these shenanigans, you could go back in time (so as to have done it before all that compiling and linking you just did) and change the line in config.h that has the ".povrayrc" string in it to be something else, perhaps "povrayrc.dat" or "povray.rc". C) Edit your shiny new .POVRAYRC template file to have the default values you want people to use. I did the following: Make output a tad bigger (half the dimensions of my normal final output): a) Width = 400 b) Height = 300 Since we are not using X, pausing after it is done is pointless: c) Pause_when_Done = off Set the Library_Path values to be where I have put stuff: d) Library_Path=usersoft_root:[povray] e) Library_Path=usersoft_root:[povray.include] Insure the vista buffers and light buffers get used: f) Vista_Buffer = on g) Light_Buffer = on And set anything else you want to set (see the POVray documentation in the documentation package). D) Copy the .POVRAYRC file into your login directory. E) Edit your copy of .POVRAYRC to have anything else in it you want. F) Copy any other files into the POVray directory that you want from the source package. I keep the .DOC files and this one too. G) You will need to have a symbol set up to run POV with command line options (like the name of the input file). It should be something akin to this: $ povray :== $ usersoft_root:[povray]povray.exe which is from a file on my system that people can run to get various "additional" bits of semi-supported software setup. 9) You are done, go render something! See, that wasn't really all that hard, was it? Excessively verbose and downright peculiar in places, but not hard. (Feel free to redistribute this to anyone who needs it. It'd be nice if you were sure to leave in the attribution line that says I wrote it way up there at the top of the file too.)