Chapter 5. Internals

Table of Contents

5.1. Sources
5.1.1. Understanding the POV-Ray source structure
5.1.2. Creating your own patches
5.2. Binaries
5.2.1. compiling on Windows systems
5.2.2. compiling on Macintosh systems
5.2.3. compiling on Unix systems
5.3. Parser
5.3.1. Adding tokens
5.4. Patterns
5.4.1. Reducing memory usage
5.5. Expressions
5.5.1. Polynomial solver
5.6. Multi-format Documentation with DocBook
5.6.1. Environment for DocBook documentation
5.6.2. Editing DocBook documentation
5.6.3. Converting DocBook documents

With increasing raytracing experience and knowledge about algorithms you may want to change/fix some features or add new ones to the core sources of POV-Ray™ or MegaPOV. You may also want modify sources when you want to move a slowly parsed SDL macro to faster C/C++ code within POV-Ray™.

The following section is our effort to write down the conclusions we made from our experience in writing patches compatible with POV-Ray™ architecture with portable documentation and merging those made by others. If you are new to POV-Ray™ or patch writing you should bear in mind we have a long term experience with POV-Ray™ and you probably can learn something useful from the things written here. If you are an experienced patch writer do not hesitate to vary the rules where you think this is appropriate.

5.1. Sources

Working with sources of POV-Ray™ 3.6 or MegaPOV requires some basic knowledge about:

  • POV-SDL usage
  • C and C++ programming
  • 3D math
  • raytracing terms and algorithms

Although POV-Ray™ and MegaPOV sources can be considered as a nice lesson in programming and raytracing it is not recommended for beginners in programming and computer graphics to try modifying it. There are relatively complex relations between the different parts and changing something without knowing exactly what you do is likely to cause problems, even if it compiles and works well in first tests. Please do not waste time asking for detailed explanations when answer seems obvious in the above categories. Try to find some online tutorials or just buy a comprehensive book and most important: study the source code. Below information is gathered mainly to highlight POV-Ray™ source specific aspects.

5.1.1. Understanding the POV-Ray™ source structure

Sources of MegaPOV are based on the POV-Ray™ sources distributed officially by POV-Team™. The basis for the modifications included in MegaPOV 1.1 is the source of the official 3.6.0 version. Filenames usually already give a hint on the purpose and most files contain a short description in the header on their purpose. Each *.cpp filename is delivered with appropriate *.h header file.

All files located in the /source directory in the archives can be considered as part of the following categories:

  • The patches subdirectory contains all new files for features introduced in MegaPOV:

    • patches/patches.h - this file enables the individual patches of MegaPOV
    • patches/clothray.cpp
    • patches/glow.cpp
    • patches/mechsim.cpp

  • Common structures and definitions:

    • frame.h
    • vector.h
    • [platform]/config.h - located in platform specific directory

  • Object definitions:

    • bezier.cpp
    • blob.cpp
    • boxes.cpp
    • cones.cpp
    • csg.cpp
    • discs.cpp
    • fpmetric.cpp
    • fractal.cpp
    • hcmplx.cpp
    • hfield.cpp
    • isosurf.cpp
    • lathe.cpp
    • mesh.cpp
    • objects.cpp
    • planes.cpp
    • poly.cpp
    • polygon.cpp
    • prism.cpp
    • quadrics.cpp
    • quatern.cpp
    • sor.cpp
    • spheres.cpp
    • sphsweep.cpp
    • super.cpp
    • torus.cpp
    • triangle.cpp
    • truetype.cpp

  • Lighting and other "visible" effects:

    • atmosph.cpp
    • lightgrp.cpp
    • lighting.cpp
    • media.cpp
    • photons.cpp
    • point.cpp

  • Radiosity:

    • octree.cpp
    • radiosit.cpp
    • rad_data.cpp

  • Texturing:

    • image.cpp
    • interior.cpp
    • normal.cpp
    • pattern.cpp
    • pigment.cpp
    • texture.cpp
    • txttest.cpp - place for own texturing experiments
    • warps.cpp

  • Raytracing helpers:

    • bbox.cpp
    • bcyl.cpp
    • bsphere.cpp

  • Builtin benchmark:

    • benchmark.cpp

  • Math helpers with operation on different types of data:

    • chi2.cpp
    • colour.cpp
    • colutils.cpp
    • matrices.cpp
    • polysolv.cpp
    • splines.cpp

  • Parser routines:

    • express.cpp
    • parse.cpp
    • parsestr.cpp
    • parstxtr.cpp
    • tokenize.cpp

  • IO routines for various formats:

    • file_pov.cpp
    • gif.cpp
    • gifdecod.cpp
    • histogra.cpp
    • iff.cpp
    • jpeg_pov.cpp
    • pgm.cpp
    • png_pov.cpp
    • ppm.cpp
    • targa.cpp
    • tiff_pov.cpp

  • Functions Virtual Machine implementation together with internal functions:

    • fncode.cpp
    • fnintern.cpp
    • fnpovfpu.cpp
    • fnsyntax.cpp
    • function.cpp

  • Rendering process:

    • ray.cpp
    • render.cpp
    • renderio.cpp
    • renderctrl.cpp
    • camera.cpp
    • lbuffer.cpp
    • vbuffer.cpp
    • vlbuffer.cpp

  • general program routines:

    • optout.cpp
    • povray.cpp
    • pov_mem.cpp
    • pov_util.cpp
    • statspov.cpp
    • userdisp.cpp
    • userio.cpp

  • the base subdirectory contains routines for file input/output as well as string and option handling.

    • base/configbase.h
    • base/fileinputoutput.cpp
    • base/platformbase.h
    • base/pointer.h
    • base/pov_err.h
    • base/povms.cpp
    • base/povmscpp.cpp
    • base/povmsgid.h
    • base/processoptions.cpp
    • base/stringutilities.cpp
    • base/textstream.cpp
    • base/textstreambuffer.cpp

  • the frontend subdirectory contains the default frontend:

    • frontend/configfrontend.h
    • frontend/defaultplatformbase.cpp
    • frontend/defaultrenderfrontend.cpp
    • frontend/messageoutput.cpp
    • frontend/processrenderoptions.cpp
    • frontend/renderfrontend.cpp

As mentioned above the config.h configuration file is located in a platform specific directory. This directory is usually named like the target platform (like windows, unix etc.). There are also other files located in that directory: implementation of GUI, binary resources (like icons), implementation of some (protected) IO operations and other platform specific solutions.

5.1.2. Creating your own patches

Extending POV-Ray™ with new features is something that requires significant skills (see Section 5.1, “Sources”), experience and time.

5.1.2.1. Planning a patch

There are many different reasons for modifying the POV-Ray™ source. Most important are the fixing of bugs and extending POV-Ray™ with new features.

When fixing a bug it should be considered what is the right, expected behavior of the program, the fix should establish this. In many cases patches introduced as a bugfix are in fact feature extensions or only superficial fixes that do not solve the underlying problem.

When you are planning a new feature you should first think about how it should fit into the rest of POV-Ray™ features. A good patch can be used quite universally, not only for the purpose it was originally developed for. Do not try to reinvent the wheel but make use of existing techniques that already exist in the POV-Ray™ source. For things like status output and file reading use functions existing in POV-Ray™.

5.1.2.2. Markup - key to usable patches

It is hard to describe good guidelines for the actual coding of a patch. Every programmer has own habits and methods including indention, placing of braces, inserting white spaces, favorite naming scheme. But there are some common rules POV-Ray™ patch writers usually follow. Here is our effort for a brief summary - mainly meant as a starting aid for beginning patch writers.

When coding make use of existing helper functions in POV-Ray™ like those in vector.h. Try to reduce changes in existing code to avoid damaging existing features.

Usually, people put something like #define MY_PATCH in a commonly used file:

  • patches/patches.h - for general patches (this file is introduced in MegaPOV and included within frame.h so no need to add it to the rest of the sources).
  • frame.h - for general patches in case you are patching plain POV-Ray™ and don not want to add a patches.h file.
  • [platform]/config.h - for platform specific changes (when compiler requires replacement for missed functions or needs to customize rendering engine to cooperate with shell of platform)

Now you should enclose all patch-specific code in #ifdef ... [#else ...] #endif blocks, so removing (commenting) /* #define MY_PATCH */ causes compilation without your patch, and the modifications you make are clearly visible. Optional #else ... is suggested when you are making replacement for existing code (i.e. for bug fixes).

The most common system for patch naming are uppercased words separated with underscores. Names are usually concatenated with word PATCH somehow. In world of Apple mixed case variable names without underscores like MyPatch are also popular.

Example 5.1. Typical patch markup

patches.h:

...
#define FAST_SQR_PATCH
...

some_file.cpp:

...
#ifdef FAST_SQR_PATCH
  // new code
  Value = sqr( Parameter );
#else
  // old code
  Value = Parameter * Parameter;
#endif
...

Some additions can be also compiler specific changes required by lack of some builtin C function or different naming. In such cases you can use predefined compiler specific macros together with your own markup. Each compiler delivers several predefined macros (see Section 5.2, “Binaries”).

#ifdef __DJGPP__
  // some compiler specific code
#else
  // code for other compilers
#endif

#if defined( __WATCOMC__ ) && defined( MY_PATCH)
  // code here
#end

Of course it is a little bit more work to maintain changes this way but on the other hand it is also much more readable and allows to prepare two binaries for comparison. It is also much more easier to port your changes into other compilations like MegaPOV then.

5.1.2.3. Coding - stay portable

Apart from the markup it is important to keep modifications portable. Patches using compiler specific features or functions from a proprietary library won't make it into a patch collection like MegaPOV.

When you add new elements to the POV-Ray scene description language it is a good idea to keep it consistent with the existing syntax. Even if you think a certain syntax would be much easier to use it is very likely to cause much confusion for the user when it differs from existing similar functions.

Some useful information about portability aspects can be found on http://predef.sourceforge.net/.

If you are unsure about a certain aspect of your patch implementation better ask (see Section 1.5.3, “Discussions”).

5.1.2.4. Sharing patches

Once a patch is finished you may want to share this patch with the POV-Ray™ Community. Doing this in a wise way can make your patch popular and included in other unofficial custom compilations like MegaPOV is. So before you upload your changes somewhere first check if:

  • every difference between your modified source and base source is somehow marked (with #ifdef) so other users can understand where the code is modified.
  • no line from the old source is removed.
  • all necessary headers are included in files (this is common omission when precompiled headers are used)
  • in case your sources contain more then one patch, be sure that one change does not require code from the other patch to work. If one patch depends on the other this should be clearly indicated.
  • most important: Your patch is well documented both in the source and for the user. Even if this means quite some work it is probably the most critical point for a patch to become successful on the long run or not.

When your modifications are validated then it is time to publish it. There are some common methods in publishing patches:

  • releasing differences in diff format - this is a very popular method however it works well only when changes are moved between very similar packages. It is most important to mention on what basis the modification is made. To make sure the modification can still be used some time later this is usually not the optimal solution (except for really small modifications).
  • releasing all files affected by changes for particular patch - it is very good method because everyone can easily merge it with files with own modifications.
  • releasing a snapshot of all files in your working directory - this method guarantees that you do not omit any change however it requires detailed comparison of all files for those who want to merge the patch.
  • releasing a detailed description of all changes with explanation why, what, where and how things were changed - this "do it yourself" method makes your patch highly portable because it is easy to understand and nearly independent from the source basis but it requires a larger effort.

It is hard to tell which method is the best. The choose of particular method depends on free time, complexity of changes and used sources.