Using the bitmap load event

I have a question about loading a bitmap directly. I'm loading the bitmap and waiting for the orxDISPLAY_EVENT_LOAD_BITMAP event. I load it with orxDisplay_LoadBitmap and then check the event payload zLocation until I get the event for my bitmap. From there I'm trying to get the bitmap data with orxDisplay_GetBitmapData but it fails with a message that the bitmap is not finished loading. Am I using the wrong event? I feel like maybe this is event is firing when I start loading the bitmap, but not sure. To confuse things, the hints for LoadBitmap mention an event that doesn't seem to exist -- orxDISPLAY_EVENT_BITMAP_LOAD. Probably a typo but has me wondering if I'm using the wrong event? I've found a workaround and am able to use my bitmap data ok, but would like to understand why that event doesn't seem to be firing when I think it should.

Thanks very much for any guidance. Here is a shot of the hint I'm seeing with the typo in it:

Comments

  • What you describe should be working. Are you using the latest version from the git/hg repository?
    I think I've fixed that issue (or very similar) a few weeks ago.

    And thanks about the doxygen comment, I believe the event got renamed a long time ago but the comment never got updated.

    That being said, is there any reason why you're loading bitmap manually instead of loading textures instead?
    I see you're also using something that looks like a relative path to the executable's location, did you define your resource storage?
    If so, orxDisplay_LoadBitmap will use the Texture resource group, which should make it easier to handle this kind of paths.

  • Thanks. I'm actually still using the build you made a few months ago with the setpartialbitmapdata function in it. Does the latest have that implemented as well? I'd like to still be able to use it to update just a pixel at a time.

    So, I think there is a better way to do what I'm trying to do....I just want to use an image file to build maps that I then use with the tile mapping system you helped me get running a while ago. Earlier I was playing around with generating some tile worlds dynamically, but I'd also like to have a system where I can "draw" out a level in a bitmap and use the color channels to determine which blocks to place in my array containing the tile data. It is working right now with a workaround for the event issue. I saw the mention of using the stb_image library to load an image and get the pixel data, but I wasn't sure if I can do that through orx or if I need to setup my project to include the library, etc. I'm hoping for a system that is easy to recreate in new projects so was attracted to just doing everything through orx. Let me know if you have a better suggestion.

  • Forgot to say, I was originally loading a texture and pulling the bitmap from it, but I had trouble with it (I think I hadn't realized the bitmap wasn't loaded yet maybe?), I switched to LoadBitmap to see if it helped then figured out I needed to wait for it to load. And I think I used the relative path because I saw it in another example somewhere and just copied it..good to know that isn't necessary. This is all just a rough attempt to prove the concept of using an image to draw out a level quickly so will clean it up once I determine the right way to go about it.

  • Yep, I pushed orxDisplay_SetPartialBitmapData on march 27th, I'd recommend syncing to the latest.

    I'd recommend also doing what you were doing before: using a texture and fetching its data when you need it. This way you can easily use that texture anywhere else, including as a shader input directly from config (by simply using the same name).
    Regarding the delay for the content to be available, in addition to the orxTEXTURE_EVENT_LOAD event, you can also simply poll orxTexture_GetLoadCount and wait until it reaches 0.
    Another alternative would be to ask for a synchronous texture load instead and you can hide the small delay behind a load screen or similar.

    As for resources, https://github.com/iarwain/resource might give you a better insight of what is possible with it. Basically you can define a series of storages (aka containers) for each resource group (Texture, Config, Sound or you very own custom ones). They'll be checked in order everytime a new resource is requested.
    Then there are different resource transports that define the way those resources are accessed (orx on desktop ships with a built-in transport that can access the filesystem).
    I've written a couple of additional transports as well:

    • https://github.com/orx/orxArchive (which can now be requested when starting a new project with init), that allows a user to store resources inside a compressed archive
    • https://github.com/orx/orxRemote which is more a proof on concept allowing for resources to be accessed remotely through HTTP (meant for dev purposes and as a teaching material as well)
  • Thanks very much....very useful information. I think it will be a little more convenient for me to use synchronous loading for this texture and indeed the delay will just be part of a "loading" screen anyway.

    So this is what I tried and it seems to work fine. Please let me know if this would be an appropriate way to load just this texture synchronously? (the worldTexture is deleted later after use)

        const orxBITMAP * tmpB;
        tmpB = orxDisplay_GetTempBitmap();
        orxDisplay_SetTempBitmap(orxNULL);
        worldTexture = orxTexture_CreateFromFile("world1.png", false);
        worldBitmap = orxTexture_GetBitmap(worldTexture);
        orxDisplay_SetTempBitmap(tmpB);
    
  • edited June 2020

    That's exactly the way to do it, I have nothing to add. :)

    Just a little side note: when you say "deleted after use", you mean when you don't need to access the underlying bitmap anymore, is that correct?

  • Yes, I basically read the bitmap and build up a data array based on what I find in it, and then delete the texture since it isn't needed any longer.

    Thanks for checking over this.

  • Then you're all set. You don't use the bitmap to render your map with a shader then, I guess?

  • Nope, it is not just for tilemap information but for anything I want in a level really. In it's basic use, it indeed can be used to map a color in a pixel to which tile eventually gets into the shader bitmap. But I can also, for example, say that a specific color pixel represents a particular NPC...so when I find that color in the bitmap, I create an NPC at the world location derived from that pixel position. So anything in my level can be represented by a colored pixel in this bitmap. The idea is really to make an image in gimp with several layers, one for a tile map, one for NPC locations, one for whatever else I want, etc and export the layers as tiles.png, npc.png and read them to generate the level. It is basically a super simple level editor. So far just playing around with creating the tile map with it seems really useful.

  • I'm really sorry, I never received any notification of your post and I just stumbled upon it today.
    Using an image as the only input medium for storing maps is definitely a nice approach.
    My only concern with it would be when working with a team, as they're usually not that easy to diff/patch.

  • No problem, I've been logged off the forum for a while and hadn't noticed your response anyway :smile: Here it is exactly 1 month later and I found it!

    I hear you about the collaboration concern- at this point my "team" is just me and my kids and I don't really see a better way to be able to visually design a complicated large scene map for us--it is really useful for the specific kind of game map we're trying to get better at. We actually just used it this weekend for a ludum dare practice...I may post a quick shot of the map file and the way it looks in game to illustrate what I'm doing. In any case, thanks as always for your response and extremely helpful comments.

    By the way, I'm totally sold on using the GUIDs now. When I've got a large list of objects that are distributed throughout a level which may or may not be deleted during game play, I now keep a std::vector of the GUIDs and when the level is finished, go through and easily only kill the objects that still exist by checking by GUID.

  • I just added the email notification preference so I might notice more easily when a discussion has been replied to....I hadn't see those preferences before for some reason.

  • edited July 2020

    I'm looking forward to seeing some shots of what you've been working for. Don't hesitate to start a new thread about it or even post in the #projects section on Discord if you feel like it (https://orx-project.org/discord).

    I'm glad you find the GUIDs useful. However if it's for cleaning up all the objects, there are maybe some easier ways to do so:

    • You can loop on all existing objects and call orxObject_Delete with something like:
      orxOBJECT *pstObject;
    
      /* Gets first object */
      pstObject = orxOBJECT(orxStructure_GetFirst(orxSTRUCTURE_ID_OBJECT));
    
      /* Non empty? */
      while(pstObject != orxNULL)
      {
        /* Deletes object */
        orxObject_Delete(pstObject);
    
        /* Gets first object */
        pstObject = orxOBJECT(orxStructure_GetFirst(orxSTRUCTURE_ID_OBJECT));
      }
    
    • You can use a dummy object that "collects" all other "dangling" ones and finally delete that one at the end. Let's say you want to do the cleanup on a per level basis, you can have a Level object that is created at the beginning of your level, and you make sure to set it as the owner of all the objects you create while inside that level. When the level's over, all you have to do is delete the Level object, as it'll be the owner of everything else you've created, they'll all disappear. I usually use a simple track to set my Level object as owner of others, this way I don't do anything on the code side and I can tweak at will from the config side.
  • Good to know, I wonder if would be feasible to add a built-in function, something like orxObject_DeleteAll to make it really easy? I basically treat everything (menu, splashscreen, level) as a level and wipe everything clean upon leaving any level, so such a function would be really easy to remember. That said, I should be able to build that code into my scene base class and not have to think about any of it.

    I resisted using the owner object concept because indeed I thought that'd add another line of code I'd have to remember anywhere that I use a CreateFromConfig object creation. If you have time, could you explain how you use the track to set the Level object as owner of others?

  • edited July 2020

    The code I pasted in my last post is actually the content of orxObject_DeleteAll which is only available internally. :)
    The reason being that I didn't think it would be that useful, it's very short and the orxObject API is already quite large.

    Regarding the track approach, here's the way I would do it:

    [StoreID]
    0         = > Object.GetName ^, > Get < ID, Set Runtime < ^
    Immediate = true
    
    [BaseLevel]
    TrackList = StoreID
    ID        = Level
    
    [Level4@BaseLevel]
    
    [SetLevelOwner]
    0         = > Get Runtime Level, Object.SetOwner ^ <
    Immediate = true
    
    ; Setting the track manually
    [MyObject]
    TrackList = SetLevelOwner
    
    
    ; Using a base object + inheritance if that's more convenient for you
    [BaseObject]
    TrackList = SetLevelOwner
    
    [MyOtherObject@BaseObject]
    

    I use the StoreID idiom a lot for all objects that are unique at a given point in time, such as the current level, the current music, the current menu, etc...
    It basically retrieve the config section of the current object, look for the ID property in it, and store the object's GUID in the Runtime section using the key we just retrieved. This way one can retrieve the current level from anywhere as it's stored in the Runtime section with the Level key.

    Leveraging this information, we have SetLevelOwner, which will simply set the current level as the owner of the current object.

    One can even set TrackList = SetLevelOwner as the default for all objects using the DefaultParent property of Config, if need be.

  • Cool, I understand about the DeleteAll function...I didn't realize it existed internally...at least my naming convention was consistent with orx ! :smile:

    The config file method looks powerful. My experience has been that when I can't get something configured correctly in the config files, it is maddening for me to try to debug why it isn't doing what I expect...with my own code I can at least step through until I've found what silly mistake I've made. For me, I think the best approach, at least for the specific task of removing objects, will be to implement a removeAllObjects function in my scene base using the code you provided.

    As usual, thanks for the attention and help. I am slowly getting better at using orx...I haven't had to beg for help here in a little while :smile:

  • edited July 2020

    Always a pleasure to help you when I can. :)

    As for the config, yes, that's one of the downside of the data-driven approach without an editor. That being said, I find that more often than not checking the error logs with a debug build will provide me with the information I need or at least a lead to track down the mistake. Case sensitivity typos, for example, would be reported there.

Sign In or Register to comment.