Save Project
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/12/2007 at 12:44, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 10.111
Platform: Mac ;
Language(s) : C++ ;---------
I'm checking to see if there is way to call a "save project" function from within the SDK. I couldn't find one, but maybe you guys know.I'm referring not to "save" but "save project," the command that copies all textures into a tex folder and changes all texture paths in the scene. I know that this can be done with CallCommand(), but I'm looking to bypass the FileSelector dialog, as I will be batch processing this command, and I don't want any user interaction after they call my function.
Alternately, if I have to create this function myself, I did find the GetAllTextures() function, which will give me all the scene textures to copy, but it looks like there is no easy way to change the textures' file paths in the scene from there (hopefully, I'm wrong here), as the container appears to have copies, not instances of the textures.
Is there an easy method to globally strip all texture paths, while still keeping the filename, or do I have to go through all of my channels in all of my materials and strip the file names one-by-one from there? Currently, I can do this if the texture is in the top-level of the channel, but I haven't figured out how to get textures from subchannels yet.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/12/2007 at 13:10, xxxxxxxx wrote:
There isn't a direct SDK method to do this (SaveDocument() doesn't consider this). CallCommand(12255) might work. You can get the ID of commands by opening the Command Manager (Windows:Layout:Command Manager) and selecting the command.
What I do to make textures relative is first copy them relative to the document (it MUST have been saved first to have a valid path reference to it!), then you need to do the following:
> // CMD: Copy Image Maps to Scene Folder
> //*---------------------------------------------------------------------------*
> BOOL CopyImageMaps(BaseDocument* activeDocument, AtomArray* atomArray, Filename projectPath, BOOL clearSelection)
> //*---------------------------------------------------------------------------*
> {
> if (!atomArray) return FALSE;
>
> LONG cnt = GetSelectedWithTextures(activeDocument, atomArray);
> // if nothing selected, consider entire document
> if (!cnt)
> {
> AppendPolygonObjects(activeDocument, atomArray, activeDocument->GetFirstObject());
> cnt = atomArray->GetCount();
> if (!cnt) return TRUE;
> }
>
> String* stringArray = bNew String[1024L];
> LONG index = 0L;
> Filename texpath;
> texpath = activeDocument->GetDocumentPath();
> // Get C4D Document folder or Project texture folder
> if (texpath.Content()) texpath += Filename("Tex");
> else texpath = projectPath.GetDirectory()+Filename("Tex");
> if (!GeFExist(texpath)) GeFCreateDir(texpath);
>
> BaseObject* obj;
> BaseTag* tag;
> TextureTag* ttag;
> GeData data;
> Material* mat;
> //for (LONG i = 0; i < cnt; i++)
> for (LONG i = cnt; i--; )
> {
> obj = static_cast<BaseObject*>(atomArray->GetIndex(i));
> if (!obj->IsInstanceOf(Opolygon)) continue;
> // - Copy maps for selected Object
> for (tag = obj->GetFirstTag(); tag; tag = tag->GetNext())
> {
> if (!tag->IsInstanceOf(Ttexture)) continue;
> ttag = (TextureTag* )tag;
> ttag->GetParameter(DescID(TEXTURETAG_MATERIAL), data, NULL);
> mat = static_cast<Material*>(data.GetLink(activeDocument, Mbase));
> if (!mat) continue;
> // Color
> CopyAndSetTexture(mat->GetChannel(CHANNEL_COLOR), texpath, stringArray, &index;);
> // Specular Color
> CopyAndSetTexture(mat->GetChannel(CHANNEL_SPECULARCOLOR), texpath, stringArray, &index;);
> // Bump
> CopyAndSetTexture(mat->GetChannel(CHANNEL_BUMP), texpath, stringArray, &index;);
> // Environment
> CopyAndSetTexture(mat->GetChannel(CHANNEL_ENVIRONMENT), texpath, stringArray, &index;);
> // Alpha
> CopyAndSetTexture(mat->GetChannel(CHANNEL_ALPHA), texpath, stringArray, &index;);
> // Luminance
> CopyAndSetTexture(mat->GetChannel(CHANNEL_LUMINANCE), texpath, stringArray, &index;);
> #ifdef C4D_R9
> // Displacement
> CopyAndSetTexture(mat->GetChannel(CHANNEL_DISPLACEMENT), texpath, stringArray, &index;);
> #endif
> mat->Update(TRUE, TRUE);
> mat->Message(MSG_CHANGE);
> }
> }
> if (clearSelection) DeselectObjects(atomArray);
> if (stringArray)
> {
> CopyImageMapsInfoDialog cimiDialog;
> cimiDialog.Init(stringArray, index, texpath.GetString());
> String title = GeLoadString(IPPS_COPYMAPS_DONE)+" ""+texpath.GetString()+""";
> cimiDialog.Open(-1L,-1L, SizeChr(title.GetLength())*7L, 320L);
> bDelete(stringArray);
> }
> else MessageDialog(GeLoadString(IPPS_COPYMAPS_DONE)+"\n""+texpath.GetString()+""");
> if (index) SaveDocument(activeDocument, activeDocument->GetDocumentPath()+activeDocument->GetDocumentName(), TRUE, FORMAT_C4DEXPORT);
> return TRUE;
> }
> // Copy Material image and set Texture image name
> //*---------------------------------------------------------------------------*
> void CopyAndSetTexture(BaseChannel* bchan, Filename texpath, String* stringArray, LONG* index)
> //*---------------------------------------------------------------------------*
> {
> if (!bchan) return;
> // Extract full image file path
> Filename map = bchan->GetData().GetFilename(BASECHANNEL_SUGGESTEDFOLDER)+Filename(bchan->GetData().GetString(BASECHANNEL_TEXTURE));
> /// Copy file locally
> if (!GeFExist(map)) return;
> texpath += map.GetFile();
> if (!GeFExist(texpath))
> {
> GeFCopyFile(map, texpath, TRUE);
> if (stringArray) stringArray[*index] = texpath.GetFileString();
> ++(*index);
> }
> // clear suggested folder
> BaseContainer bdata;
> bdata.SetFilename(BASECHANNEL_SUGGESTEDFOLDER, Filename());
> bchan->SetData(bdata);
> // Update Material's texture image
> bdata.SetString(BASECHANNEL_TEXTURE, map.GetFileString());
> bchan->SetData(bdata);
> }A caveat here is that this routine does not consider texture map files referenced deeper (such as in Fusion shaders). Thus, using "Save Project" is a better approach as it will rectify all texture map path references to be relative.
HTH!
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/12/2007 at 14:01, xxxxxxxx wrote:
Wow! Thanks for the speedy reply. That's similar to what I'm already doing. The caveat you mentioned is a big deal here, as many textures that my users have in their scenes are buried quite deep in complex fusion shaders or layer shaders (or plugin shaders I don't even know about), so I think I will have to figure out how to get to those buried textures.
Yes, ideally, I do want to use Save Project (or replicate its function), but I need to suppress the file-saver dialog. This is for batch submission to C4D net-render. I don't want the user to have any interaction with C4D after they've chosen their files to upload, as they could be uploading as many as 100 or more .c4d files, and each one has to copy textures over. I don't want them sitting around choosing file paths 100 times, etc.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/12/2007 at 14:53, xxxxxxxx wrote:
BaseDocument::GetAllTextures() will get all of the texture image file paths but I don't think that this updates the references in the Materials at all (which is why I don't use it).
As for avoiding the Save Project file dialog, I don't think there is any way to do that. Even if the document has already been saved, this command opens the file dialog.