On Tue, Jun 7, 2011 at 9:52 PM, DR0ID <dr...@bluewin.ch> wrote:

> Hi
>
> In a library, how would pygame dependent code be separated from general
> code?
>
> Let's say that I write a package named 'mygamepack'. In that package there
> are some modules that are only dependent on python (general parts) and there
> are some others using pygame (lib dependent parts). How would that package
> be split up, so that the general parts could be used by other libraries
> without adding the pygame dependent parts? I wonder if there is a general
> way of doing this.
>
> Here are some ideas (as a file layout) how to split it up:
>
> Option 1:
>
> mygamepack
>        +-module1.py                # general part
>        +-module2.py                # general part
>        +-module1pygame.py    # lib part, dependent on pygame
>        +-module2pygame.py    # lib part, dependent on pygame
>        +-module1otherlib.py    # lib part, dependent on otherlib
>        +-module2otherlib.py    # lib part, dependent on otherlib
>
> Pros:
>        -all code in one package, imports are no problem
>
> Cons:
>        -each supported lib adds bulk and overhead
>        -separation is not that clean
>
>
>
> or split it on package level:
>
> Option 2:
>
> mygamepack
>        +-module1.py                # general part
>        +-module2.py                # general part
> mygamepackpygame        # imports mygamepack!
>        +-module1.py    # lib part, dependent on pygame
>        +-module2.py    # lib part, dependent on pygame
> mygamepackotherlib        # imports mygamepack!
>        +-module1.py    # lib part, dependent on otherlib
>        +-module2.py    # lib part, dependent on otherlib
>
>
> usage if using it in a skellington:
>
> mygame
>        +-data
>        +-gamelib
>                +-mygamepackpygame        # local copy, importing mygamepack
> using relative imports
>                            +-mygamepack            # local copy
>
>
> Pros:
>        -clearly separates the general from lib dependent code
>
> Cons:
>        -if packages are not on pythonpath or site-packages, need to import
> general lib relatively
>
>
> Maybe there are other pros and cons I didn't think of!
>
> Thanks for your opinions and suggestions.
>
> ~DR0ID
>
Hi,

    Going to use real-life examples from my development of glLibPy and
glLibC.  I provide many examples, which can be safely skimmed without losing
my point.

    I think there's absolutely nothing wrong with choosing a few good,
stable libraries as "dependencies" for *all* of your code.  PyGame,
PyOpenGL, and NumPy are classics--usable, well-made, and powerful.  This
allows me to do things that a simple, per-file dependency-based model
doesn't let you do.

    Generally libraries are modular, in that components either stand alone,
or are closely related to each other.
    For instance, the graphics code in glLibPy (texturing, shading, object
loading, etc.) is all very closely related, and all depend on PyGame and
PyOpenGL.  This allows instances of my texture class to be passed to texture
units in my shader class, in a different file.  The objects load images
directly into the texture classes, so rendering from them is seamless.  The
texture class meshes perfectly with the framebuffer object class, the fluid,
light, and material classes, and so on.  Convenience functions follow
naturally, and make programming easier and more enjoyable.
    However, in the same library, the math code (matrices, quaternions,
vectors, utility functions, etc.) is all grouped together, depending only on
the math library included with Python.  The matrix class can be multiplied
against vector elements, even though they aren't in the same class.
Trigonometic rotation matrices and quaternions convert easily and integrate
nicely with numerical solvers, like conjugate gradient.

    In a sense, the graphics code and the mathematics code are unrelated.
But I think looking at it that way defeats the purpose of a library--code
should be organized by function, not by dependency; in the aforementioned
example, that the graphics source files share dependencies is a happy
coincidence--I didn't design the library that way.
    And it's fortunate that I didn't.  I soon realized that the mathematical
formulations and the graphics code *should* be completely intertwined.  It
makes *sense* to let matrices get loaded into OpenGL with
glLoadMatrixf(...).  It makes *sense* that you might want to calculate the
volume of a polygonal object.  Et cetera, and so the two were merged.  If I
had tried to keep the dependecies separate, it would have devolved into a
mess.

    As a typical consideration, does CPU extrusion of line segments into
quads fall under "graphics" or "mathematics"?  On the one hand, I'll
definitely need access to glBegin(...), glEnd(), glVertex*f(...),
glTexCoord*f(...), but on the other hand, it would be nice to have access to
my cross product, dot product, vector operation, and matrix class.  So now I
need Python's math library, and PyOpenGL.  If I want it be fast, I also need
NumPy--or maybe even a C binding layer to be built into the library later.
But then suppose I wanted to generalize to extrude lines for SDL raster
graphics?  Now I need PyGame too.  But now I want to subclass the
framebuffer class to make your lines drawable to a saveable entity, so now
I'm bringing in PIL and all my texturing code and its dependencies.  Now I
want to write this code into a shader, so I'm bringing in the SVG libraries,
reverse engineering them, and adding in OpenGL extensions and a GLSL
compiler.
    Okay, so I'm done with that--let's move on to another file for post
processing filters.  Do I want runtime Gaussian filters?  Bring in SciPy.
Add to glConvolutionFilter2D(...)?--bring in OpenGL, bring in OpenGL
extensions, bring in PyGame, and before long, you realize you're going down
the exact same path.
    I have continued this model of importing everything with other
modules--Physics, Math, AI, Graphics/Rendering, Algorithms, Light Transport,
Ray Tracing, and so on.  Each time I add a new file, I think about how it
will be used later, and how things should obviously connect.  I then make
those connections.  In my opinion, this makes robust, intuitive, readable,
and easily constructed code.

    Bottom line: in my libraries, I have a single file with *all* the
dependencies in it that I import with *all* my files.  If I someday happen
to need a math.atan2(...) in my shader class, I won't have to add "from math
import *" to that specific file and then worry about the imports being
consistent among the rest of the files.  I just import everything in one
file be done with it--it's easier, possibly faster, less-bug-prone, neater,
and less time-consuming.

Thanks,
Ian

Reply via email to