Storing Images in Scene Files?
-
On 25/01/2013 at 10:47, xxxxxxxx wrote:
Originally posted by xxxxxxxx
I hope the Maxon developers are taking note of this thread. There are situations where storing images to HD files just won't work.
There are times that we need a way to store images locally in tags or objects so a dialog can use them interactively.How can you say it's not possible to save images within tags or objects plugins?
I've just seen your code and if you remove the 2 'if level' conditions in the Read(), it should work as expected.
-
On 25/01/2013 at 12:19, xxxxxxxx wrote:
Hi Yannick,
Good to know you're watching this.
Yes we can save images to the hyperfile. But it's a FIFO stack with no way if getting or changing their indexes.
In order to be able to assign specific saved hf images to specific GUI items like buttons. We need a way to index them to tell them apart. And to use those indexes to assign them to gui items.Robert is talking about writing a custom indexing system to solve this problem. Which is rather complex for the average coder like me. I don't think I can pull it off.
It would be nice to see something in future versions that would possibly make it easier for the average user trying to save things locally. Like maybe some sort of storage tag class with indexing options.-ScottA
-
On 25/01/2013 at 15:49, xxxxxxxx wrote:
Scott,
I think part of the problem I'm having is visualising exactly what it is you're trying to do. I *think* you want the user to be able to pick which images get assigned to a set of BitmapButtons, so that your hyperfile needs to be able to store a series of images. Presumably that could be a fixed number (e.g. there are always going to be n bitmaps) or it's variable so the user can add more bitmaps. It doesn't matter either way.
Now, if that's that case, it's very easy to do. What I would do is this:
* store the pointers to all the bitmaps I'm going to use in an array of pointers to BaseBitmap(s)
* I can now access each bitmap by means of its index in the array
* each BitmapButton has a value which is the index into the array of the bitmap it's going to show - it's easiest to store this as a hidden field in the description because then I don't have to worry about saving or copying this value
* I use that hidden value as an index into the bitmap pointer array to get the pointer to the bitmap I want and assign that bitmap to the buttonWhen I Write() the hyperfile, I would do this:
* first, write a LONG which is the number of bitmaps I have in total - say it's 6, for example
* then write 6 bitmaps using the 6 pointers in my arrayWhen I Read() the hyperfile, I do this:
* read the LONG which tells me the number of bitmaps I have to read
* allocate the 6 BaseBitmaps so I have somewhere to store the data
* store the pointers to those BaseBitmaps into my array of pointers
* read the 6 bitmaps from the hyperfile
* the hidden value in the button description then marries up with the correct bitmap - I'd need to check that the value was valid in case something had gone wrong, but other than that I can forget about it; when MSG_DESCRIPTION_GETBITMAP is sent for a particular button, all I'd need to do is retrieve the hidden value in its description and use that as an index into the array of pointers to bitmapsThat's basically it. I suppose I'd have to provide some method in the interface for the user to be able to select which bitmap he wanted, but that's simple. The only other thing I would have to do is implement the CopyTo() function to copy the bitmaps, array of pointers, and the value holding the total number of bitmaps I have into the cloned tag.
I just don't see the problem. It doesn't need lots of extra SDK functions to do this.
-
On 25/01/2013 at 17:48, xxxxxxxx wrote:
What I'm doing is creating something similar to the old PoseLibrary system that used to be in older versions of C4D.
The bitmap buttons are created & deleted dynamically. So there isn't a set number of them.When my "Create Pose" button is clicked in the GeDialog. A whole bunch of things happen:
- A custom StorageTag is added to the currently active object (if it doesn't already have one)
- The current Position & Rotation values of the active object are saved as UserData to the tag
- A bitmap button is dynamically spawned in the dialog that allows the user to set the object to these UserData values(poses)
- A delete checkbox option for this specific button is also dynamically spawned so it can be deleted
- The active object is rendered. And the image is placed on the bitmap button(This part is the problem) so the image is there on the buttons. Even after the scene has been saved, closed , and re-opend.The frustrating thing is I wrote this plugin in about two days after learning how to create and delete UserData with C++.
It's working fine except for the images. And it even has a tree gui in it for selecting the objects so the user never has to touch the OM. Allowing the user to do everything from inside the GeDialog.But the button images...holy mother of god...What fresh hell is this!?
I never would have believed that it would be 10x harder to figure out a way to store the button images locally in my tags. Than writing my entire plugin.-ScottA
-
On 26/01/2013 at 02:33, xxxxxxxx wrote:
If I read this correctly, an object can have multiple storage tags each holding some PSR data and one bitmap, is that correct? Then what you need to do is allow the dialog to communicate with the tag.
Once you have your rendered bitmap, I take it you can assign that to the button, yes? So now you need to point the tag to the rendered bitmap. On Write(), each tag saves its own data and bitmap. On Read(), each tag loads its own data and bitmap. When you recreate the button layout in the dialog, you iterate through all the storage tags, get the pointer to the bitmap, create a button for each one and stick the bitmap on the button.
Or have I got this completely wrong?
-
On 26/01/2013 at 09:05, xxxxxxxx wrote:
There is only one tag per object. And that tag needs to hold multiple images and multiple UserData entries. Sort of like this:
Position
Rotation
Position
Rotation
etc....The bitmap buttons (the poses) in the GeDialog automatically update and change depending on which object is selected in the scene, or with the tree gizmo.
Based on what I'm hearing from you guys. I think what I have to do is:
-Create some kind of temporary image folder structure to save the rendered images when I'm actually using the plugin. Or save them into memory instead of the HD.
-Then execute a type of "file dump" maneuver. Using the overriden Write() method to take those images and store them into each specific StoragTag so the images will load if C4D is closed and re-opened.
-Then delete the temp images when C4D closesIt sounds like a fairly simple concept. And it might be simple for you advanced C++ guys.
But it's not simple for an average user like me with a plugin that has multiple tags to keep track of. And multiple images per tag that need to go on specific buttons. Which are being dynamically added & deleted. With constantly changing index numbers.
Not to mention being made even more difficult because the hyperfile has no indexing abilities.This is why I think it would be nice to have some some sort of storage tag that can store bitmap images added to the SDK.
That way we can save images for our gizmos locally in the scene file with index numbers..live..as we create them.. into this tag. And they will always be there. Locally serving our gui's images.
Or maybe a completely new type of plugin that has the Dialog and the Tag set up to talk to each other better than what we have now. With local image storage abilities.-ScottA
-
On 27/01/2013 at 13:28, xxxxxxxx wrote:
Hey Guys.
I've been working on it some more today and now I'm very, very close!
Here's the updated plugin and Source code:https://sites.google.com/site/scottayersmedia/Dialog_StorageTag.zipIt basically all works now. I can add my storage tag to any object and save the rendered scene image of it in the GeDialog's bitmap button.
And when I select different objects the button's image changes depending on which object is selected.
I can also save the scene file and re-open it. And all the images are still there and working like they should be.
*Hooray!Only one problem though. And it's a big one.
When I add something new to the scene after I've saved it and re-opened it again. I get the crash error:Incorrect File StructureIf I can figure out how to fix this one last problem. I've think I've got it all working.
I'm almost there.
Thanks for all the help guys.-ScottA
-
On 27/01/2013 at 13:34, xxxxxxxx wrote:
Make sure that your Read() and Write() are identical. If you are looping through to get each bitmap, make sure the count and each loop iteration is identical. Without seeing your code, hard to say if that is it. I'll take a look at it here shortly.
-
On 27/01/2013 at 13:35, xxxxxxxx wrote:
Hi Scott,
Bool StorageTag::Write(GeListNode* node, HyperFile* file) { //This is where the rendered scene image gets saved as a .jpg image when the scene file is saved //if (!file->WriteBool(tagBitmap != NULL)) return FALSE; //if (tagBitmap != NULL) file->WriteImage(tagBitmap, FILTER_JPG, NULL, SAVEBIT_ALPHA); imagecount = images.GetCount(); if (!file->WriteLong(imagecount)) return FALSE; //Iterate over all bitmaps and write them to the HyperFile for (LONG i=0; i < imagecount; i++) { **tagBitmap = BaseBitmap::Alloc(); //Allocate the bitmap variable so we can use it to make an image** tagBitmap = images[i]; file->WriteImage(tagBitmap, FILTER_JPG, NULL, SAVEBIT_ALPHA); } return TRUE; }
1. tagBitmap is a class-member. Why do you use it for temporary storage?
2. You will get memory-leaks at the red marked line.
3. Isn't that actually exactly what I showed you here?Next, in your Read() method, you only read a single image. What if you've previosuly written 7
images? That is where the incorrect file-structure message comes from.Best,
Niklas -
On 27/01/2013 at 13:43, xxxxxxxx wrote:
Bool StorageTag::Read(GeListNode* node, HyperFile* file, LONG level) { //Read the tag's hyperfile to see if there is an image stored in it LONG numImages = file->ReadLong(&imagecount); GePrint(LongToString(numImages)); for (LONG i = 0L; i != numImages; ++i) { tagBitmap = BaseBitmap::Alloc(); //Allocate the bitmap variable so we can use it to make an image if (!tagBitmap) return FALSE; //Error handling if allocation fails file->ReadImage(tagBitmap); images->Push(tagBitmap); } //This code sets the Bool's value //Depending if an image is, or is not, read when the scene file is opened in C4D //Bool hasBitmap; //if (!file->ReadBool(&hasBitmap)) return FALSE; //if (hasBitmap) //{ // if (!file->ReadImage(tagBitmap)) return FALSE; // GePrint(LongToString(tagBitmap->GetBh())); //} //else tagBitmap = NULL; return TRUE; } Bool StorageTag::Write(GeListNode* node, HyperFile* file) { //This is where the rendered scene image gets saved as a .jpg image when the scene file is saved //if (!file->WriteBool(tagBitmap != NULL)) return FALSE; //if (tagBitmap != NULL) file->WriteImage(tagBitmap, FILTER_JPG, NULL, SAVEBIT_ALPHA); imagecount = images.GetCount(); if (!file->WriteLong(imagecount)) return FALSE; //Iterate over all bitmaps and write them to the HyperFile for (LONG i=0; i < imagecount; i++) { file->WriteImage(images[i], FILTER_JPG, NULL, SAVEBIT_ALPHA); } return TRUE; }
-
On 27/01/2013 at 13:47, xxxxxxxx wrote:
I haven't tried multiple buttons yet Nik.
It's quite possible I put on my party hat too soon.-ScottA
*Edit- That fixed it Robert.....Once again I'm in your debt sir.