Thread: Multiple include problem

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    Multiple include problem

    Before you start in and say use this:

    Code:
    #ifndef FOO
    #define FOO
    ..
    #endif
    I already have.

    Problem:
    I'm rendering a terrain scene with water that reflects the scene around it. All vectors for the water point straight up and the eventual plan is to use the Fresnel term in a shader to perturb the water. In order to do this correctly I must use cubic environment mapping. The basic idea of cubic environment mapping is that you draw the scene from 6 different directions with the camera at the center of the scene. Each view matrix represents a 90 degree field of view. You render this to a texture and then use that texture for the primtive that is supposed to reflect the geometry. But the catch is you cannot render the object that is doing the reflecting in the cube map render.

    In order to do this in my system, the CWater object requires a pointer to the CTerrainApp class which is derived from CD3DApp which is the core engine code. The message loop of CD3DApp calls the pure virtual function ScreenRender. ScreenRender is then defined to call CoreRender with bRenderWater set to true. Inside of Water::Render(), if water reflections are enabled, then I call CWater::RenderCubeMap(). Inside of RenderCubeMap() I must call CTerrainApp::CoreRender with bRenderWater set to false.

    So as you see CWater must include CTerrainApp.h and CTerrainApp.h must include CWater.h. MSVC .NET is telling me that CTerrainApp is an undefined identifier and thus spits out several more errors pointing to the fact that it does not know what CTerrainApp is in CWater file scope. Even though I'm including CTerrainApp.h, it is not including the file.

    How do I fix this? I must call the render for the core engine in order to render the scene to the cube map texture, but it won't allow me to pass a pointer to it because it says it's undefined.

    Quite odd.
    Code:
    #include "CD3DApp.h"
    #include "CCamera.h"        //Camera
    #include "CTerrain.h"       //Terrain
    //#include "CSky.h"           //Sky plane
    #include "CWater.h"         //Water plane w/ cubic environ mapping
    //#include "CSun.h"           //Sun billboard
    #include "CFrustrum.h"      //Frustum
    #include "CSkyBox.h"        //Skybox
    
    //For fonts
    #include "dxutil.h"
    #include "d3dutil.h"
    #include "d3dfont.h"
    
    class CTerrainApp:public CD3DApp
    {
      CCamera          *TheCamera;
    ...
    ...
    Code:
    #ifndef CWATER
    #define CWATER
    
    #include "d3dx9.h"
    #include "dxutil.h"
    #include "d3dutil.h"
    
    #include "CTerrainApp.h"
    
    
    struct WaterVertex
    {
      D3DXVECTOR3 Pos;
      D3DXVECTOR3 Normal;
      D3DCOLOR    Color;
      float u1,v1;
      float u2,v2;
        
      static const DWORD FVF;
    
      WaterVertex(void):Pos(D3DXVECTOR3(0.0f,0.0f,0.0f)),Color(0),
                    Normal(D3DXVECTOR3(0.0f,0.0f,0.0f)),
                    u1(0.0f),v1(0.0f),u2(0.0f),v2(0.0f) {}
      
      WaterVertex(D3DXVECTOR3 _Pos,float _u,float _v):Pos(_Pos),u1(_u),v1(_v) {}
      WaterVertex(float x,float y,float z,float u,float v):
                  Pos(D3DXVECTOR3(x,y,z)),u1(u),v1(v) {}
    
    };
    
    
    
    class CWater
    {
      IDirect3DDevice9       *m_pDevice;
      IDirect3DCubeTexture9  *m_pCubeMap;
      WaterVertex             Vertices[4];
      CTerrainApp             *m_pApp;
    ...
    Results:
    d:\msvc .net 05\terrain -.net 05\cwater.h(38) : error C2143: syntax error : missing ';' before '*'
    d:\msvc .net 05\terrain -.net 05\cwater.h(38) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    d:\msvc .net 05\terrain -.net 05\cwater.h(38) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    d:\msvc .net 05\terrain -.net 05\cwater.h(51) : error C2061: syntax error : identifier 'CTerrainApp'

    d:\msvc .net 05\terrain -.net 05\cterrainapp.h(32) : error C2143: syntax error : missing ';' before '*'
    d:\msvc .net 05\terrain -.net 05\cterrainapp.h(32) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    d:\msvc .net 05\terrain -.net 05\cterrainapp.h(32) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > #ifndef FOO
    > #define FOO
    But have you checked for uniqueness.
    If something else accicentally defines the same symbol, then your file won't be included because it thinks it already has been included.

    I don't know about your compiler, but gcc has this handy option to stop after the pre-processor step.
    g++ -E prog.cpp
    Produces prog.i, which is the output of the pre-processor, that is all the #includes and #defines have been expanded (.i files are very long if you have lots of includes). If you have such a feature, try to see if the expected include is actually happening.

    Also, if all you need is the class name (as a pointer), then a test of
    // #include "CTerrainApp.h"
    class CTerrainApp;

    Should at least make it compile, if it's just a visibility problem.

  3. #3
    Registered User
    Join Date
    Mar 2002
    Posts
    203
    does a forward reference have any effect?

  4. #4
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Pre-declare classes, use pointers and include files as late as possible
    Code:
    class B;
    
    class A
    {
      public:
        B* PointerToB;
    };
    
    #include "B.h"
    Code:
    class A;
    
    class B
    {
      public:
        A* PointerToA;
    };
    
    #include "A.h"
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Thanks Magos that fixed it. Kind of feels like a hack but I guess there isn't any other way. I really thought that the #ifndef #define #endif mechanism solved this issue, but I guess it doesn't.

    Any other standard way to do this?

  6. #6
    ---
    Join Date
    May 2004
    Posts
    1,379
    You use Visual Studio right?
    Does using '#pragma once' make a difference?

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Dunno. Haven't tried it yet.

    I'm using VS .NET 05 Express for now and was using MSVC 6.

  8. #8
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    The problem is if you have "include A.h" in B.h and "include B.h" in A.h A will depend on B and B will depend on A which in an infinite recursion, no inclusion guards will ever solve that .
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well it appears to be a flaw in my design but I don't know any other way to do it. In order for RenderCubeMap() to actually re-render the scene from 6 different views it must call CTerrainApp::CoreRender(). The only other way would be to delegate the water cube map render to the app class which doesn't seem quite the way to go.

  10. #10
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    Do you manually render the scene from 6 different views or do you let DX do the work? I know OpenGL has cube mapping support, I'd imagine DX does too.

  11. #11
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    The problem is if you have "include A.h" in B.h and "include B.h" in A.h A will depend on B and B will depend on A which in an infinite recursion, no inclusion guards will ever solve that .
    You're thinking of this:
    Code:
    /* A.h */
    #include <B.h>
    
    #ifndef A_H
    #define A_H 1
    
    /* ... */
    
    #endif
    Code:
    /* A.h */
    #include <A.h>
    
    #ifndef B_H
    #define B_H 1
    
    /* ... */
    
    #endif
    Which is infinite. But if you put the headers in the inclusion guards it shouldn't be:
    Code:
    /* A.h */
    #ifndef A_H
    #define A_H 1
    
    #include <B.h>
    
    /* ... */
    
    #endif
    Code:
    /* A.h */
    
    #ifndef B_H
    #define B_H 1
    
    #include <A.h>
    
    /* ... */
    
    #endif
    Why won't that work?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  12. #12
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    dwks: That's not what I meant, I didn't mean infinite inclusion.

    I meant A needs to know B's definition, and B needs to know A's definition, thus A needs to be defined before B, which needs to be defined before A, which needs to be defined before B, which needs to be defined before A, which needs... see a pattern here?

    The solution, as explained, is to use pointers as they're always of constant size (4 bytes on a 32-bit machine) and usually needs no pre-definition until the body (cpp file).
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  13. #13
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by Bubba
    Well it appears to be a flaw in my design but I don't know any other way to do it.
    The flaw is in C++. It really needs a concept of modules. Text inclusion with the preprocessor doesn't really belong in languages like C++.

    By the way, have you never encountered this problem before?
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Some in MFC code where everyone needs to know about everyone else, yet still be sep classes. ::

    I thought it was something I was doing MFC-side that it didn't like. At least it works now - but yes something does need to be done about the issue...which I imagine is pretty common.

    Most of my code is designed so that each class can do everything it needs by itself. Usually I use pointers to one class from another if it needs to know about it's existence. However, I rarely come across situations where A needs B and B needs A in my designs.

    As I said I could work around it, but it wouldn't add anything to the code and IMHO would cause CD3DApp::Render() to do too much that doesn't pertain to it's purpose.

    Water should draw it's own cube maps utilizing the core render function of the engine in my opinion. Perhaps I'm wrong but I don't like to have extraneous classes doing tasks that don't pertain to it's purpose.

    Soon my classes will only be submitting vertex and texture data back to BuildRenderList() so I can render all this crapola in one indexed vertex buffer, but that's some time in the future.
    Last edited by VirtualAce; 02-04-2006 at 06:14 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with simple socket client/server program
    By spencer88 in forum C Programming
    Replies: 6
    Last Post: 05-05-2009, 11:05 PM
  2. #include problem
    By rwmarsh in forum C++ Programming
    Replies: 4
    Last Post: 07-07-2006, 03:00 PM
  3. C: include files problem
    By threahdead in forum Linux Programming
    Replies: 4
    Last Post: 05-07-2004, 08:02 AM
  4. include problem
    By sweets in forum C++ Programming
    Replies: 4
    Last Post: 05-03-2004, 08:00 PM
  5. help with finding lowest number entered
    By volk in forum C++ Programming
    Replies: 12
    Last Post: 03-22-2003, 01:21 PM