Cygwin build error: ppremake wont actually run

re: patches / CVS

I guess patchfile is ok. Here’s a patchfile for src/glstuff/glGraphicsStateGuardian_src.cxx. This is necessary for Panda to build with pstats turned off.

*** glGraphicsStateGuardian_src.cxx 30 Apr 2005 00:09:08 -0000 1.121
— glGraphicsStateGuardian_src.cxx 2 May 2005 02:15:10 -0000

*** 3005,3011 ****
— 3005,3013 ----

if (gvbc->was_modified()) {
  •   #ifdef DO_PSTATS
    PStatTimer timer(_load_vertex_buffer_pcollector);
  • #endif // DO_PSTATS
    int num_bytes = gvbc->get_data()->get_data_size_bytes();
    if (GLCAT.is_spam()) {

*** 3148,3154 ****
— 3150,3158 ----

if (gibc->was_modified()) {
  •   #ifdef DO_PSTATS
    PStatTimer timer(_load_index_buffer_pcollector);
  • #endif
    int num_bytes = gibc->get_data()->get_data_size_bytes();
    if (GLCAT.is_spam()) {

*** 4759,4765 ****
— 4763,4771 ----
// Unsupported target (e.g. 3-d texturing on GL 1.1).
return false;

  • #ifdef DO_PSTATS
    PStatTimer timer(_load_texture_pcollector);

  • #endif

    if (uses_mipmaps) {
    #ifndef NDEBUG

The absolute simplest answer is to do your development on Linux, if that’s an option for you.

Yes, its not an option at all :confused: I just have access to Windows boxes.

In your new classes, you won’t use the EXPCL_PANDA prefix on the class definition, since that is used to tell the compiler which DLL the class is compiled into. Just omit the EXPCL_ prefix altogether it if is compiled directly in pview.

Yes, that works great!

Ermmm, dont suppose… any chance of describing the various functions I will need to over-ride in my new node, in order to render things correctly and in a reasonably optimized fashion?

It looks like the vertices and primitives are being created in cull_callback?

How does Panda know what should be rendered? What information does it need to know generally from the node, and how do I provide this information? in what format?


Also, I get the impression that there is a GeomVertexData object that is global across all Geoms? Is this a fair assessment?

For example, in qpGeomTristrips::decompose_impl(), it creates a new qpGeomTriangles object, and just adds in vertices (which are simply integers, vertex indices) into the new qpGeomTriangles object, and … thats it! It returns this qpGeomTriangles object directly.

Maybe something to do with the CData class thats inside each Geom?


Thanks for the patch! (And oops, on my part :blush:) I’ve enabled my email address, so you can send future patches directly to me via email, rather than cluttering up the forums; email is a more reliable way to send patchfiles anyway, since we don’t have to do cutting and pasting (which can damage the patchfiles).

There is some subtle stuff going on in the qpGeom structure. Each qpGeom has its own qpGeomVertexData, which is shared by all of the qpGeomPrimitive objects within the qpGeom. Thus, a qpGeomTristrips object (a kind of qpGeomPrimitive) can decompose itself into qpGeomTriangles (another kind of qpGeomPrimitive) simply by building a new index list, since it will still be within the same qpGeom, and will therefore be keeping the same qpGeomVertexData.

In your routine, you will probably build up a qpGeomVertexData for all of your vertices, and then one or more qpGeomPrimitives (a single qpGeomTriangles object would be fine) to index into the vertices. Then add them both to a qpGeom, and wrap that up in a CullableObject which gets stored on the CullHandler. In the OpenGL analogy, a qpGeomVertexData corresponds to a glVertexPointer() call, and each qpGeomPrimitive is a glBegin(), glDrawElements(), glEnd().

If you can cache this qpGeom object across multiple frames, so much the better, but if you don’t, that’s ok too. Also note that the qp prefix is temporary and will eventually go away.

For now, ignore the CData object you see everywhere; that’s just a placeholder for when we add multithreaded pipeline support. It’s a level of indirection that we will have to live with to support pipelining. In the meantime, just imagine that everything stored within the CData is actually stored on the class itself.

All you really need to override in your PandaNode-derived class is has_cull_callback() and cull_callback().

To fit into Panda’s run-time type system, you will also want to override init_type() and get_type(), following the examples of other nodes, and call init_type() sometime at startup. This is optional at this point.

Once you get down the road a ways, you can start to think about overriding one of xform() or safe_to_flatten() to make nodePath.flattenLight() do the right thing, and write_datagram(), fillin(), and make_from_bam() if you want to be able to save your nodes in a bam file. But I wouldn’t worry about either of these right now.


Ok, awesome! That was the insight I needed. I think this is quite close to working, as far as triangle generation goes.

For my library, basically, I’ve replaced direct calls to OpenGL with callback functions, so that the library can be used in any renderer, with a simple wrapper class, in theory.

Next scary thought: how will I specify a different texture for a different face of the prim I am rendering? For example, if this is a basic default box, there would be 6 different textures, one for each face.

Essentially, I’m looking for the Panda equivalent of

glBindTexture(GL_TEXTURE_2D, iFaceTextures[ iFaceID ] );


Since a texture change is a kind of state change, you will need to have a separate Geom for each face.

(Note that this can be relatively expensive on the high-end graphics cards, which would much rather render thousands of triangles all at once. Possible optimizations include combining any faces that happen to share the same texture, and/or using a tool similar to egg-palettize to combine all of your multiple different textures into a single texture, with different UV offsets. But that’s beside the main point.)

To render each Geom with a separate texture, you need to create a new RenderState to pass into the CullableObject constructor (I’m assuming you’re generating these things on the fly; if you are pre-generating Geoms and stuffing them in a static GeomNode, there’s a slightly different, simpler interface.)

You can see examples of the state being modified in ropeNode.cxx; it’s adding a RenderModeAttrib to specify the thickness of the line. You can do something similar to add a TextureAttrib:

PT(Texture) myTex = iFaceTextures[iFaceID];
CPT(RenderAttrib) texattrib = TextureAttrib::make(myTex);
CPT(RenderState) state = data._state->add_attrib(texattrib);
CullableObject *object = new CullableObject(geom, state, data._render_transform);


Ok, I’ll give this a shot and see how it goes.

Another important question: level of detail.

The primitives can generate different levels of detail very simply: theres just a number from 2 to 32 which specifies how many slices to do on the object. Its rather like the last two parameters in GlutSolidSphere.

So, a twisted, hollow, cut cube that youre standing inside might have hundreds of triangles, but a cube in the distance might just have 12 triangles, or maybe even fewer.

Of course, we somehow need to determine what level of detail to display for each primitive, which will basically be roughly proportional to:

  • scale
  • 1 / distance

I’d anticipate that it is probably fairly easy to obtain the scale from the nodePath, so the question in my mind is: what options are available to the node for obtaining the distance to the observer at each rendering cycle?


(btw, do you know that qpGeomVertexWriter doesnt inherit from ReferenceCount? Is this something that I can patch in?)

Progess update: triangles, normals, and lighting are being drawn correctly for FractalSpline now. Will look at textures soonish.

Current issue: extreme culling

With a largish object, the problem is less evident, but as I zoom towards the object, it suddenly vanishes, even though it was plainly in my field of view at the time.

Is there an option so the object wont be culled unless it is entirely outside of the field of view?

With smaller objects, the issue is worse: even though the object is still really tiny on my screen, it is suddenly culled.


One other question, not really critical: how to modify the sources.pp to specify additional /I include paths, /LIBPATHs, and libraries?


Lots of points at once! :slight_smile:

LOD: You have the information you need in the CullTraverser to determine the distance from the camera. See panda/src/pgraph/lodNode.cxx.

ReferenceCount: qpGeomVertexWriter doesn’t need to inherit from ReferenceCount, since the object is not intended to have a long lifespan. The intended design is that you create one locally, use it to write the vertices, and then throw it away (let it go out of scope). Keeping it around for longer is actually risky, since someone might switch the GeomVertexData out from under it, and it wouldn’t notice.

Culling: you will need to compute the bounding volume of your node correctly so that culling will work properly. Override recompute_internal_bound() to do this; there are numerous examples of this method’s definition throughout Panda. You can do nodePath.show_bounds() to draw a visible representation of your node’s bounding volume to help convince yourself that you got it right.

Libraries: there are several ways to add a new library or libraries, depending on your design requirements. Short answer:

#define WIN_SYS_LIBS foo.lib
#define EXTRA_LPATH c:/foo/bar/lib

EXTRA_LPATH requires a fix that I just committed in dtool/pptempl.


Ok, thats good info!

One other question: how do I add other include paths to the Sources.pp?

re: ReferenceCount, I do need it to be persistent across multiple function calls for the callbacks to work: … iew=markup

unprotectedpVertexWriter = new qpGeomVertexWriter(pGeomVertexDataObject, InternalName::get_vertex());
  unprotectedpNormalWriter = new qpGeomVertexWriter(pGeomVertexDataObject, InternalName::get_normal());
  unprotectedpColorWriter = new qpGeomVertexWriter (pGeomVertexDataObject, InternalName::get_color());
  unprotectedpTextureCoordWriter = new qpGeomVertexWriter (pGeomVertexDataObject, InternalName::get_texcoord());


  delete( unprotectedpVertexWriter );
  delete( unprotectedpNormalWriter );
  delete( unprotectedpColorWriter );
  delete( unprotectedpTextureCoordWriter );

What are the disadvantages of patching qpGeomVertexWriter to derive from ReferenceCount?


Well, looking through Template.gmsvc.pp, I guess EXTRA_IPATH is for include files?

To be honest, I was kindof looking for a way to do something like:


I was thinking of basically distributing FractalSpline with patchfiles for Panda, so that this variable in Config.pp would work. How much effort would this take? And what would be the steps involved in this?


please don’t hurt me for my question :slight_smile:
but can you continue your work with devcpp or codeblocks as ide?
i would like to use something non m$.

Sorry Polyveg, but I happen to agree with David here:

On a practical level, I’ve found that the ms compiler works incredibly well, meaning primarily that it builds very fast, and the code it produces is very compact.

If you can show me a non-MS compiler that builds as fast as the microsoft one, links painlessly with MySQL and so on, so ideally supports the same C++ name-mangling (unlikely), I might consider it.

In my brief benchmarking session, Cygwin ran four hundrer percent slower than cl.exe, thats five times slower. mingw ran roughly one hundred percent slower than cl.exe, so half as fast. That is a huge difference in build time.


Edit: btw, just noticed you said ide? Just so you know, I dont use an ide, I just use a text editor like SciTe.

you are right, gcc is not very fast - but the more people are using gcc the more gcc will grow up. this is a process that i wanna support. it is the idealist in me that is speaking. but i never made anything big like pand3d…

i can’t understand this low level guys :wink:


first of all a huge THX for Hugh. His post and the instructions on his wiki were an incredible help.

I stumbled across a few extra problems, though:

a) after ppremake’ing dtool in cygwin and gnumake’ing it in cmd, gnumake install wouldn’t work (gave some weird error about “test” not found"). Looking into the generated makefile, I couldn’t make out the source of the problem, so I tried running “make install” in cygwin instead, and, lo and behold, that worked.

b) now moving on to panda, after first ppremaking it in cygwin, the gnumake’ing in cmd didn’t work because the created makefile referenced files like /usr/… which cmd understandably looked for in c:\ (not knowing anything about cygwin’s mappings). So now I used junction from like that:

junction c:\usr c:\cygwin\usr

and gnumake got a good deal further

c) at some point gnumake calls interrogate and interrogate needs all kinds of dlls (3rd party stuff). so i added the paths to the bin directories of all the 3rd-party libs, too

d) now when interrogate is invoked it gives me an “The application could not be initialized correctly” error. For today, I’ll leave it at that. Tomorrow, I’ll look into makepanda because from the comments here on the forum it seems that might be the less painful route to take (let alone saving me the cygwin installation)


Max Hajek
Vienna, Austria