Results 1 to 16 of 16

Thread: Resources: Unable to normalize invalid path

  1. #1

    Question Resources: Unable to normalize invalid path

    Hi everyone. This is my first question on the forums.

    I've done several searches, but I suppose I don't know the best way to describe my issue in a few words.

    I see many examples of code like this:

    Code:
    CL_Sprite mySprite;
    mySprite = CL_Sprite(gc, 100, 100);
    I think it might be because of the way I am passing around the CL_GraphicContext beforehand, but I am getting a crash when I call the CL_Sprite constructor.

    I have a singleton object called WindowManager that keeps a CL_DisplayWindow as a data member.

    Code:
    CL_DisplayWindow m_window;
    I have a public static method I use to grab the CL_GraphicContext of that window:

    Code:
    static CL_GraphicContext getGc() { return m_instance()->m_getGraphicsContext(); }
    where the instance method called is defined as

    Code:
    CL_GraphicContext WindowManager::m_getGraphicsContext()
    {
       return m_window.get_gc();
    }
    In the end, this means I am currently "able" to grab the CL_GraphicContext via

    Code:
    CL_GraphicContext gc = WindowManager::getGc();
    And I then try to construct a sprite as demonstrated in the first code portion of this post.

    I realize that this is probably due to everything "gc" is wrapped up in, involving shared pointers, but I am new to ClanLib and have very little experience (almost none) with RCSPs.

    Do I need to use a mutex?

    Note: I do not start any additional threads in my program, but I get the impression that ClanLib does some stuff with the graphics context asynchronously under the hood.

    Again, I'm sorry if this is a common post, or if you abhor the preceding text-vomit, but I hope you can help me debug this issue / steer my newbie self in the right direction.

    Thanks for taking the time to read this!

  2. #2
    ClanLib Developer
    Join Date
    May 2007
    Posts
    1,824

    Default

    This is a quick post, I have not fully read your question,

    but I noticed

    "I have a singleton object called WindowManager"
    Singleton's that are global variables do not work very well with ClanLib.

    If
    Code:
    	CL_SetupCore setup_core;
    	CL_SetupDisplay setup_display;
    	CL_Setup....
    go out of scope, ClanLib objects are undefined.

    Global variables are destroyed in an undefined order (due to a limitiation of C/C++)

    If you want to use singletons. Ensure they are destroyed via a "reset_singleton()" method or created/destroyed via a "new" alloc in the main code, and handled via a pointer.

  3. #3

    Default

    Quote Originally Posted by rombust View Post
    If
    Code:
    	CL_SetupCore setup_core;
    	CL_SetupDisplay setup_display;
    	CL_Setup....
    go out of scope, ClanLib objects are undefined.

    Global variables are destroyed in an undefined order (due to a limitiation of C/C++)

    If you want to use singletons. Ensure they are destroyed via a "reset_singleton()" method or created/destroyed via a "new" alloc in the main code, and handled via a pointer.
    Thanks for the quick response.

    I left all the "setup" instantiations alone, that is, they are in my main loop.

    However, as you know from above, my singleton contains a data member of type CL_DisplayWindow.

    Could this CL_DisplayWindow be going out of scope merely because it resides in a singleton object?

    Here is the full header of the singleton to make sure we're on the same page:

    Code:
    // WindowManager.h
    
    #ifndef WINDOWMANAGER_H
    #define WINDOWMANAGER_H
    
    #include "precomp.h"
    
    class WindowManager
    {
    public:
       static CL_DisplayWindow getWindow() { return m_instance()->m_getWindow(); }
       static CL_GraphicContext getGc() { return m_instance()->m_getGraphicsContext(); }
       static CL_InputContext getIc() { return m_instance()->m_getInputContext(); }
    
       static void swap() { m_instance()->m_swap(); }
    private:
       static WindowManager * m_instance();
    
       void m_init();
       void m_swap();
    
       CL_DisplayWindow m_getWindow();
       CL_GraphicContext m_getGraphicsContext();
       CL_InputContext m_getInputContext();
    
       void m_closeCallback();
    
       // data
       CL_DisplayWindow m_window;
       CL_Slot m_slotQuit;
    
       WindowManager();
       ~WindowManager();
       WindowManager(const WindowManager &);
       WindowManager operator = (const WindowManager &);
    };
    
    #endif
    Here is the source, as of now:

    Code:
    // WindowManager.cpp
    
    #include "precomp.h"
    #include "Game.h"
    #include "WindowManager.h"
    
    WindowManager * WindowManager::m_instance()
    {
       static WindowManager instance;
       return &instance;
    }
    
    void WindowManager::m_init()
    {
       m_slotQuit = m_window.sig_window_close().connect(this, &WindowManager::m_closeCallback);
    }
    
    void WindowManager::m_swap()
    {
       m_window.flip();
    }
    
    CL_DisplayWindow WindowManager::m_getWindow()
    {
       return m_window;
    }
    
    CL_GraphicContext WindowManager::m_getGraphicsContext()
    {
       return m_window.get_gc();
    }
    
    CL_InputContext WindowManager::m_getInputContext()
    {
       return m_window.get_ic();
    }
    
    void WindowManager::m_closeCallback()
    {
       Game::quit();
    }
    
    WindowManager::WindowManager()
       : m_window("TimeDragon", 640, 480, true)
    {
       m_init();
    }
    
    WindowManager::~WindowManager()
    {
    }
    Are you saying that the static instance of WindowManager in the body of WindowManager::m_instance() goes out of scope?

    Thanks again for the reply.

    EDIT: I forgot to mention: I have a singleton object I use to process input, as well as one for mapping it to keys. They both have instance data members and those singletons don't give me any trouble. They aren't of CL_something type, but they do need to remain in scope for the program to function.

    EDIT 2: Let me know if the code's denser than you'd prefer to parse, and I'll extract the important bits and repost.

  4. #4
    ClanLib Developer
    Join Date
    Sep 2006
    Location
    Bergen, Norway
    Posts
    588

    Default

    Sounds like you have a complex setup, but on first look it doesn't sound problematic to pass the GC around. Most ClanLib objects are handle objects, meaning we basically just pass around shared pointers internally.

    You say it crashes in the sprite constructor - can you provide a stack trace?

    Mutexes are not required - we don't do anything on separate threads in the graphic context.

    Also, try to make an example that is as minimal as possible that demonstrates your problem.

  5. #5

    Default

    Thanks for your reply.

    You say it crashes in the sprite constructor - can you provide a stack trace?
    I'm sorry, I'm not experienced with dumping the call stack to a file. I'm trying to get this working, and will post the dump here as soon as I have it. (I'm looking at StackWalker and StackWalk64 for VS 2010.)

    ...we don't do anything on separate threads in the graphic context.
    That's a relief.

    Also, try to make an example that is as minimal as possible that demonstrates your problem.
    I'll get to work on this as well.

  6. #6

    Default

    I created a test project that reproduces the issue, and I think you will agree it is quite minimal.

    Here is the code from program.cpp:

    Code:
    #include "precomp.h"
    #include "program.h"
    #include <ClanLib/application.h>
    
    CL_ClanApplication clanapp(&Program::main);
    
    int Program::main(const std::vector<CL_String> &args)
    {
       CL_SetupCore setup_core;
       CL_SetupDisplay setup_display;
       CL_SetupGL setup_gl;
       CL_SetupGUI setup_gui;
       CL_SetupSound setup_sound;
       CL_SetupVorbis setup_vorbis;
       CL_SetupMikMod setup_mikmod;
    
       CL_DisplayWindow window("ClanLibTest", 640, 480);
       CL_ResourceManager resources("resources.xml");
    
       CL_Sprite logo(window.get_gc(), "sprites/studioLogo", &resources);
    
       return 0;
    }
    Once again, it crashes on the CL_Sprite constructor.

    For reference, here is (the relevant portion of) the file resources.xml:

    Code:
    <?xml version="1.0" encoding="iso-8859-1"?>
    <resources>
    <section name="sprites">
       <sprite name="studioLogo">
          <image file="..\..\Art\Textures\b_logoTransparent.png" />
       </sprite>
    </section>
    </resources>
    I hope I've made a glaring error.

    EDIT: Forgot to mention, the filepath to the PNG in resources.xml is relative to the project directory (again, same as the solution directory).
    Last edited by Pigmess; 02-21-2012 at 05:57 PM.

  7. #7
    ClanLib Developer
    Join Date
    May 2007
    Posts
    1,824

    Default

    Your example is not catching the CL_Exceptions, so any errors (for example "file not found") will not be caught.

    Add the following in your code:

    Code:
    	try
    	{
    		CL_SetupCore setup_core;
    
    		...
    		return 0;
    	}
    	catch(CL_Exception &exception)
    	{
    		// Create a console window for text-output if not available
    		CL_ConsoleWindow console("Console", 80, 160);
    		CL_Console::write_line("Exception caught: " + exception.get_message_and_stack_trace());
    		console.display_close_message();
    
    		return -1;
    	}
    This code with also provide you with a stack trace.

    (This code is in all the ClanLib examples)

  8. #8

    Default

    Quote Originally Posted by rombust View Post
    (This code is in all the ClanLib examples)
    Sorry, my mistake.

  9. #9

    Default

    I've caught the exception as advised and am getting this message:

    Code:
    Exception caught: Unable to normalize invalid path /../../Art/Textures/b_logoTransparent.png
    Obviously, the path is wrong - notice the / at the start (not in the resource file itself). To indicate a relative path, is there a macro I need to use?

    UPDATE: it seems most likely that I am starting my path with respect to the wrong directory - I guess it doesn't start from the code/project/solution directory (mine are all the same).

    I will keep looking.

    UPDATE 2: I've gone off-rail in this thread, my apologies. I'm going to look at some examples and figure this out.

    Thanks for all your help and patience!
    Last edited by Pigmess; 02-21-2012 at 10:32 PM.

  10. #10
    ClanLib Developer
    Join Date
    Sep 2006
    Location
    Bergen, Norway
    Posts
    588

    Default

    Using resources it starts at the location of the resource file as far as i remember.

  11. #11

    Default

    Quote Originally Posted by sphair View Post
    Using resources it starts at the location of the resource file as far as i remember.
    Hm, I have the file (resources.xml) in the same location as my solution, so the path seems valid (to me, not to ClanLib).

    I just downloaded the examples, haven't had a chance to sift through them.

  12. #12

    Default

    For reference / if anyone's interested, here's the stack trace:

    Code:
    Exception caught: Unable to normalize invalid path /../../Art/Textures/b_dragonPlaceholder.png
    
    #0 CL_PathHelp::normalize (c:\development\clanlib-2.3.4\sources\core\iodata\path_help.cpp, line 416)
    
    #1 CL_PathHelp::make_absolute (c:\development\clanlib-2.3.4\sources\core\iodata\path_help.cpp, line 128)
    
    #2 CL_VirtualDirectory::make_path_absolute (c:\development\clanlib-2.3.4\sources\core\iodata\virtual_directory.cpp, line 160)
    
    #3 CL_VirtualDirectory::open_file (c:\development\clanlib-2.3.4\sources\core\iodata\virtual_directory.cpp, line 143)
    
    #4 CL_PNGProvider_Impl::init (c:\development\clanlib-2.3.4\sources\display\imageproviders\png_provider_impl.cpp, line 114)
    
    #5 CL_PNGProvider_Impl::CL_PNGProvider_Impl (c:\development\clanlib-2.3.4\sources\display\imageproviders\png_provider_impl.cpp, line 58)
    
    #6 CL_PNGProvider::load (c:\development\clanlib-2.3.4\sources\display\imageproviders\png_provider.cpp, line 75)
    
    #7 CL_ProviderType_Register<CL_PNGProvider>::load (c:\development\clanlib-2.3.4\sources\api\display\imageproviders\provider_type_register.h, line 64)
    
    #8 CL_ImageProviderFactory::load (c:\development\clanlib-2.3.4\sources\display\imageproviders\provider_factory.cpp, line 87)
    
    #9 CL_Texture::CL_Texture (c:\development\clanlib-2.3.4\sources\display\render\texture.cpp, line 191)
    
    #10 CL_SharedGCData_Impl::load_texture (c:\development\clanlib-2.3.4\sources\display\render\shared_gc_data_impl.cpp, line 76)
    
    #11 CL_SharedGCData::load_texture (c:\development\clanlib-2.3.4\sources\display\render\shared_gc_data.cpp, line 56)
    
    #12 CL_SpriteDescription::CL_SpriteDescription (c:\development\clanlib-2.3.4\sources\display\2d\sprite_description.cpp, line 119)
    
    #13 CL_Sprite_Impl::init (c:\development\clanlib-2.3.4\sources\display\2d\sprite_impl.cpp, line 82)
    
    #14 CL_Sprite::CL_Sprite (c:\development\clanlib-2.3.4\sources\display\2d\sprite.cpp, line 96)
    
    #15 Program::main (c:\users\bschnur\underbyte\salen2012winter_gam394\teams\under byte\tech\clanlibtest\program.cpp, line 25)
    
    #16 WinMain (c:\development\clanlib-2.3.4\sources\app\win32\clanapp.cpp, line 90)
    
    #17 __tmainCRTStartup (f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c, line 275)
    
    #18 WinMainCRTStartup (f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c, line 189)
    
    #19 BaseThreadInitThunk
    
    #20 RtlInitializeExceptionChain
    
    #21 RtlInitializeExceptionChain
    EDIT: Oh, and as you can see, I've been trying it with a different image file.

  13. #13

    Default

    UPDATE: The code I described below is working as it should - the issue is that when I create my CL_ResourceManager, its "base path" is "/" when I believe it should be "".

    Does anyone know why this might happen, or how I can change this?

    ~~~~~~~~~~~~~~~~~~~~~~

    As far as I can tell by stepping through the source, what's happening is that when the texture is loaded, a path is generated from the one I supplied plus a pre-pended "/". This happens on the line in CL_SharedGCData_Impl::load_texture shown below:

    Code:
    CL_Texture CL_SharedGCData_Impl::load_texture(CL_GraphicContext &gc, const CL_String &filename, const CL_VirtualDirectory &virtual_directory, const CL_ImageImportDescription &import_desc)
    {
       ...
    
       CL_String key = virtual_directory.get_identifier() + filename + alpha_code;
            
       ...
    }
    I believe this pre-pended "/" is what's causing the path to be invalid.

    Observing that virtual_directory is in fact passed into this function, I retraced my steps and found this line of code in the CL_SpriteDescription constructor:

    Code:
    CL_VirtualDirectory virtual_directory = resources->get_directory(resource);
    Is it possible that there is a problem with having the resources.xml file directly in the solution directory? If not, how can I get the pre-pended value to resolve to "" instead of "/"?

    EDIT: If it pleases, perhaps one of the admins would like to rename this thread to something like "Resources: Unable to normalize invalid path" or something similar so that it better describes the real issue being discussed.

  14. #14

    Default

    Since the first thing I am trying to draw is a static image (a logo), I switched to using a CL_Image and loading the file in directly using the same path I've specified in the resource file, and it loads and draws without a hitch.

    It seems that the issue with CL_Sprite is indeed due to the "/" being pre-pended to the path.

    I tried specifying my own base path for the CL_ResourceManager, and attempted setting it to "" and ".", with the same result - a pre-pended "/".

    The CL_Image is perfect for drawing the logo, but I would like to get some sprite sheets loaded and drawing. I would also much prefer to use an XML file to keep resource paths out of the source.

    UPDATE: I can also create a CL_Sprite with the pathname directly in the source, but I would love to keep paths out of the source as well as make use of the easy animation setup made possible by the use of a resource file.

    UPDATE 2: a call to

    Code:
    resources->get_directory(resource)
    (where resources is a CL_ResourceManager * and resource is a CL_Resource) is returning a bad ptr, and I believe this is at the root of the problem.

    The call is located in CL_SpriteDescription's constructor (sprite_description.cpp lines 85 and 118).
    Last edited by Pigmess; 02-22-2012 at 04:54 AM.

  15. #15

    Default

    I believe the slash might get added due to the combination of two things:

    (1) that call I mentioned returns a bad ptr, and this somehow results in the base path being interpreted as ""

    (2) the fix discussed in the last post of this thread adds a trailing slash to that path

    This is largely speculation based on disjoint observations.
    Last edited by Pigmess; 02-22-2012 at 05:44 AM.

  16. #16

Similar Threads

  1. path bug in 2.3
    By gpmfuchs in forum Official ClanLib SDK Forums
    Replies: 7
    Last Post: 11-25-2011, 08:22 AM
  2. CL_Angle::normalize fails with negative angles
    By genail in forum Official ClanLib SDK Forums
    Replies: 2
    Last Post: 01-08-2010, 10:15 PM
  3. CL_Exception::what() returns invalid pointer if UNICODE is #defined
    By Deewiant in forum Official ClanLib SDK Forums
    Replies: 2
    Last Post: 10-20-2009, 10:08 AM
  4. Simple Path Movement
    By Pleng in forum Novashell Game Creation System
    Replies: 11
    Last Post: 03-22-2008, 11:30 AM
  5. Relative File Path
    By Dr. Rain in forum Official ClanLib SDK Forums
    Replies: 3
    Last Post: 03-08-2008, 01:05 AM

Bookmarks

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •