private string GetTexture(BaseContainer data, BaseChannel matChannel) { string resultName = null; string texture = data.GetString(C4dApi.BASECHANNEL_TEXTURE); if (!string.IsNullOrEmpty(texture)) { texture = Path.GetFileNameWithoutExtension(texture); texture += ".jpg"; resultName = texture; if (!_textureFiles.Contains(texture)) { matChannel.InitTexture(new InitRenderStruct(_doc)); using (BaseBitmap bitmap = matChannel.GetBitmap()) { if (bitmap != null) { using (BaseContainer compressionContainer = new BaseContainer(C4dApi.JPGSAVER_QUALITY)) { bool bRet = bitmap.SetColorProfile(ColorProfile.GetDefaultSRGB()); compressionContainer.SetFloat(C4dApi.JPGSAVER_QUALITY, 70.0); string textureFileAbs = Path.Combine(_sceneRootDir, texture); bitmap.Save(new Filename(textureFileAbs), C4dApi.FILTER_JPG, compressionContainer, SAVEBIT.SAVEBIT_0); _textureFiles.Add(texture); } } else { resultName = null; } } matChannel.FreeTexture(); } } return(resultName); }
// Different ways how data (The...) is obtained and written. // Example 1: An override gets the baseTag/BaseObject: // // Working example from DoubleCircle: // public override retval OverrideMethod(..., BaseTag tag, ...) // { // BaseContainer di = tag.GetDataInstance(); // Get the data instance from the object // int theIntContents = di.GetInt(GENERAL_TAG_THEINT); // Retrieve the data from the data instance // Question: Would it be sufficient to simply use this.GetDataInstance() public override bool GetDDescription(GeListNode node, DDescriptionParams descparams) { // The main part of this code is taken from the "LookAtCamera.cpp" file from the original C4D API samples. // TODO: whatever this might be good for: if (!singleid || cid.IsPartOf(*singleid, NULL)) // important to check for speedup c4d! // { if (!descparams.Desc.LoadDescription("tbase")) { return(false); } // According to https://developers.maxon.net/docs/Cinema4DCPPSDK/html/class_description.html and // with #define DESCID_ROOT DescID(DescLevel(1000491, 0, 0)) as set in lib_description.h // Set the tag's name to something meaningful (other than "Base Tag" or "Basis Tag" DescID nCid = new DescID(new DescLevel(1000491, 0, 0)); // The ID of the radius value (GENERAL_TAG_THEINT) BaseContainer nBc = descparams.Desc.GetParameterI(nCid, null); // The type of the radius value (LONG) string OldName = nBc.GetString(C4dApi.DESC_NAME); nBc.SetString(C4dApi.DESC_NAME, TagName); ////////////////////////////////////////////////////////////////////////////////////// // Create an int value named TheInt on the "Base" tab's main level DescID cid = new DescID(new DescLevel(GENERAL_TAG_THEINT, C4dApi.DTYPE_LONG, 0)); // The ID of the radius value (GENERAL_TAG_THEINT) BaseContainer bc = C4dApi.GetCustomDataTypeDefault(C4dApi.DTYPE_LONG); // The type of the radius value (LONG) bc.SetString(C4dApi.DESC_NAME, "TheInt"); // The user interface name (TheInt) bc.SetInt32(C4dApi.DESC_DEFAULT, 44); // The default value (44, but overridden to 42 in the Init method) if (!descparams.Desc.SetParameter(cid, bc, new DescID(new DescLevel(C4dApi.ID_TAGPROPERTIES)))) { return(true); } ////////////////////////////////////////////////////////////////////////////////////// // Create a string value named TheName on the "Base" tab's main level cid = new DescID(new DescLevel(GENERAL_TAG_THENAME, C4dApi.DTYPE_LONG, 0)); // The ID of the radius value (GENERAL_TAG_THENAME) bc = C4dApi.GetCustomDataTypeDefault(C4dApi.DTYPE_STRING); // The type of the radius value (STRING) bc.SetString(C4dApi.DESC_NAME, "TheString"); // The user interface name (TheName) bc.SetString(C4dApi.DESC_DEFAULT, "Worscht"); // The default value (Worscht, but overridden to Horst in the Init method) if (!descparams.Desc.SetParameter(cid, bc, new DescID(new DescLevel(C4dApi.ID_TAGPROPERTIES)))) { return(true); } /* * ///////////////////////////////////////////////////////////////////////////////////// * // Create an entirely new Tab (called "Ein schöner Tab") * DescID cid = new DescID(new DescLevel(CIRCLEOBJECT_NEWTAB, C4dApi.DTYPE_GROUP, 0)); * BaseContainer bcMaingroup = C4dApi.GetCustomDataTypeDefault(C4dApi.DTYPE_GROUP); * bcMaingroup.SetString(C4dApi.DESC_NAME, "Ein schöner Tab"); * // Create the new Group on the top level (DecLevel(0)) * if (!descparams.Desc.SetParameter(cid, bcMaingroup, new DescID(new DescLevel(0)))) * return true; * * ///////////////////////////////////////////////////////////////////////////////////// * // Create an new sub group (called "Hübsches Grüppchen") * cid = new DescID(new DescLevel(CIRCLEOBJECT_SUBGROUP, C4dApi.DTYPE_GROUP, 0)); * BaseContainer bcSubgroup = C4dApi.GetCustomDataTypeDefault(C4dApi.DTYPE_GROUP); * bcSubgroup.SetString(C4dApi.DESC_NAME, "Hübsches Grüppchen"); * // Create the sub group on the "Ein schöner Tab" main tab (CIRCLEOBJECT_NEWTAB) * if (!descparams.Desc.SetParameter(cid, bcSubgroup, new DescID(new DescLevel(CIRCLEOBJECT_NEWTAB)))) * return true; * * ///////////////////////////////////////////////////////////////////////////////////// * // Create an new boolean value (as a checkbox) called "Check mich" * cid = new DescID(new DescLevel(CIRCLEOBJECT_CHECKME, C4dApi.DTYPE_BOOL, 0)); * BaseContainer bcCheckMich = C4dApi.GetCustomDataTypeDefault(C4dApi.DTYPE_BOOL); * bcCheckMich.SetString(C4dApi.DESC_NAME, "Check mich"); * bcCheckMich.SetBool(C4dApi.DESC_DEFAULT, true); * // Create the boolean check box under the previously created sub group (CIRCLEOBJECT_SUBGROUP) * if (!descparams.Desc.SetParameter(cid, bcCheckMich, new DescID(new DescLevel(CIRCLEOBJECT_SUBGROUP)))) * return true; */ descparams.Flags |= DESCFLAGS_DESC.DESCFLAGS_DESC_LOADED; return(true); // base.GetDDescription(node, descparams); }
/// <summary> /// This method tries to make the best out of C4Ds seldom relationship between objects with /// multiple materials which can or can not be restricted to polygon selections and one or more UV sets. /// But there are unhandled cases: /// Multple UV tags are not supported. Overlapping polygon selections are probably handled differently. /// The awkward side effects when changing the tags' order in C4D are not reproduced. /// </summary> /// <param name="ob"></param> /// <param name="snc"></param> private void VisitObject(BaseObject ob, SceneNodeContainer snc) { Collection <TextureTag> textureTags = new Collection <TextureTag>(); Dictionary <string, SelectionTag> selectionTags = new Dictionary <string, SelectionTag>(); UVWTag uvwTag = null; CAWeightTag weightTag = null; // SCRATCH // var targetComponent = new TargetComponent {ExtraInfo = aStr, Radius = anInt}; // snc.AddComponent(targetComponent); // Iterate over the object's tags for (BaseTag tag = ob.GetFirstTag(); tag != null; tag = tag.GetNext()) { // GeneralTag if (1036156 == tag.GetTypeC4D()) { var di = tag.GetDataInstance(); int anInt = di.GetInt32(10000); string aStr = di.GetString(10001); Logger.Debug("Found a GeneralTag with TheInt=" + anInt + " and TheString = \"" + aStr + "\""); // var targetComponent = new TargetComponent {ExtraInfo = aStr, Radius = anInt}; // snc.AddComponent(targetComponent); } // CAWeightTag - Save data to create the weight list later CAWeightTag wTag = tag as CAWeightTag; if (wTag != null) { weightTag = wTag; continue; } // TextureTag (Material - there might be more than one) TextureTag tex = tag as TextureTag; if (tex != null) { textureTags.Add(tex); continue; } // UVWTag - the texutre coordinates. We handle only one UVWTag uvw = tag as UVWTag; if (uvw != null) { if (uvwTag == null) { uvwTag = uvw; } else { Logger.Error("Object " + ob.GetName() + " contains more than one uv-coordinates-tag. Cannot handle this. Only the first texture tag will be recognized."); } continue; } // Selection tag. Only recognize the polygon selections as they might be referenced in a TextureTag SelectionTag selection = tag as SelectionTag; string selTagName = tag.GetName(); if (selection != null && selection.GetTypeC4D() == C4dApi.Tpolygonselection && !string.IsNullOrEmpty(selTagName)) // One Type and three TypeIDs - You C4D programmer guys really suck { selectionTags[selTagName] = selection; } // XPresso Tags - TBD XPressoTag xPresso = tag as XPressoTag; if (xPresso != null) { // Handle XPresso tag continue; } } TextureTag lastUnselectedTag = null; Collection <KeyValuePair <SelectionTag, TextureTag> > texSelList = new Collection <KeyValuePair <SelectionTag, TextureTag> >(); // Abused KeyValuePair. Should have been Pair... // Now iterate over the textureTags foreach (TextureTag texture in textureTags) { string selRef = ""; using (BaseContainer texData = texture.GetData()) { selRef = texData.GetString(C4dApi.TEXTURETAG_RESTRICTION); } if (string.IsNullOrEmpty(selRef)) { // This material is not restricted to any polygon selection lastUnselectedTag = texture; } else { SelectionTag sel; if (selectionTags.TryGetValue(selRef, out sel)) { texSelList.Add(new KeyValuePair <SelectionTag, TextureTag>(sel, texture)); } } } // At this point we have the last texture tag not restricted to a seletion. This will become the Material of this FuseeObjectContainer // no matter if this object contains geometry or not if (lastUnselectedTag != null) { AddComponent(snc, GetMaterial(lastUnselectedTag)); } // Further processing only needs to take place if the object contains any geometry at all. PolygonObject polyOb = ob as PolygonObject; // Check whether the object contains an unpolygonized mesh if (polyOb == null) { polyOb = ob.GetCache(null) as PolygonObject; } if (polyOb != null) { float3[] normalOb = polyOb.CreatePhongNormals(); // Initialize the polygon index set int nPolys = polyOb.GetPolygonCount(); HashSet <int> polyInxs = new HashSet <int>(); for (int i = 0; i < nPolys; i++) { polyInxs.Add(i); } foreach (KeyValuePair <SelectionTag, TextureTag> texSelItem in texSelList) { HashSet <int> polyInxsSubset = new HashSet <int>(); BaseSelect bs = texSelItem.Key.GetBaseSelect(); int nSegments = bs.GetSegments(); for (int iSeg = 0; iSeg < nSegments; iSeg++) { int from = bs.GetRangeA(iSeg); int to = bs.GetRangeB(iSeg); for (int iSel = from; iSel <= to; iSel++) { polyInxs.Remove(iSel); polyInxsSubset.Add(iSel); } } // Now generate Polygons for this subset if (polyInxsSubset.Count > 0) { if (snc.Children == null) { snc.Children = new List <SceneNodeContainer>(); } SceneNodeContainer subSnc = new SceneNodeContainer(); AddComponent(subSnc, new TransformComponent() { Translation = new float3(0, 0, 0), Rotation = new float3(0, 0, 0), Scale = new float3(1, 1, 1) }); AddComponent(subSnc, GetMaterial(texSelItem.Value)); subSnc.Name = snc.Name + "_" + texSelItem.Key.GetName(); AddComponent(subSnc, GetMesh(polyOb, normalOb, uvwTag, polyInxsSubset)); _weightManager.AddWeightData(subSnc, polyOb, weightTag, polyInxsSubset); snc.Children.Add(subSnc); } } // The remaining polygons directly go into the original mesh AddComponent(snc, GetMesh(polyOb, normalOb, uvwTag, polyInxs)); _weightManager.AddWeightData(snc, polyOb, weightTag, polyInxs); } else if (ob.GetTypeC4D() == C4dApi.Olight) { using (BaseContainer lightData = ob.GetData()) // Just for debugging purposes for (int i = 0, id = 0; -1 != (id = lightData.GetIndexId(i)); i++) { if (lightData.GetTypeC4D(id) == C4dApi.DA_LONG) { int iii = lightData.GetInt32(id); } if (lightData.GetTypeC4D(id) == C4dApi.DA_REAL) { double d = lightData.GetFloat(id); } else if (lightData.GetTypeC4D(id) == C4dApi.DA_VECTOR) { double3 v = lightData.GetVector(id); } } ; } }