[NUI.Scene3D] Add CastShadow and ReceiveShadow for Model and ModelNode (#5987)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Scene3D / src / public / ModelComponents / ModelNode.cs
1 /*
2  * Copyright(c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.Runtime.InteropServices;
21 using System.ComponentModel;
22 using Tizen.NUI;
23 using Tizen.NUI.Binding;
24 using Tizen.NUI.BaseComponents;
25
26 namespace Tizen.NUI.Scene3D
27 {
28     /// <summary>
29     /// ModelNode is a class for representing the Node of Model in Scene3D.
30     /// </summary>
31     ///
32     /// <remarks>
33     /// ModelNode contains multiple ModelPrimitives and allows easy access and
34     /// modification of Material information that ModelPrimitive has. If a 3D
35     /// format file is loaded by Model, ModelNode is created internally to
36     /// construct the model. In addition, you can create a Custom ModelNode
37     /// using ModelPrimitive and Material directly and add it to Model.
38     ///
39     /// <code>
40     /// ModelNode modelNode = new ModelNode();
41     /// ModelPrimitive modelPrimitive = new ModelPrimitive();
42     /// modelNode.AddModelPrimitive(modelPrimitive);
43     ///
44     /// Material material = new Material;
45     /// modelPrimitive.Material = material;
46     /// </code>
47     /// </remarks>
48     [EditorBrowsable(EditorBrowsableState.Never)]
49     public class ModelNode : View
50     {
51         internal ModelNode(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
52         {
53         }
54
55         internal ModelNode(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, true, cRegister)
56         {
57         }
58
59         /// <summary>
60         /// Create an initialized ModelNode.
61         /// </summary>
62         [EditorBrowsable(EditorBrowsableState.Never)]
63         public ModelNode() : this(Interop.ModelNode.ModelNodeNew(), true)
64         {
65             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
66             this.PositionUsesPivotPoint = true;
67         }
68
69         /// <summary>
70         /// Copy constructor.
71         /// </summary>
72         /// <param name="modelNode">Source object to copy.</param>
73         [EditorBrowsable(EditorBrowsableState.Never)]
74         public ModelNode(ModelNode modelNode) : this(Interop.ModelNode.NewModelNode(ModelNode.getCPtr(modelNode)), true, false)
75         {
76             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
77         }
78
79         /// <summary>
80         /// Assignment operator.
81         /// </summary>
82         /// <param name="modelNode">Source object to be assigned.</param>
83         /// <returns>Reference to this.</returns>
84         internal ModelNode Assign(ModelNode modelNode)
85         {
86             ModelNode ret = new ModelNode(Interop.ModelNode.ModelNodeAssign(SwigCPtr, ModelNode.getCPtr(modelNode)), false);
87             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
88             ret.PositionUsesPivotPoint = modelNode.PositionUsesPivotPoint;
89             return ret;
90         }
91
92         /// <summary>
93         /// Get the number of ModelPrimitive of this ModelNode.
94         /// </summary>
95         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
96         [EditorBrowsable(EditorBrowsableState.Never)]
97         public uint ModelPrimitiveCount
98         {
99             get
100             {
101                 return GetModelPrimitiveCount();
102             }
103         }
104
105         /// <summary>
106         /// Adds a ModelPrimitive object to the ModelNode object.
107         /// </summary>
108         /// <param name="modelPrimitive">The ModelPrimitive object to add.</param>
109         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
110         [EditorBrowsable(EditorBrowsableState.Never)]
111         public void AddModelPrimitive(ModelPrimitive modelPrimitive)
112         {
113             Interop.ModelNode.AddModelPrimitive(SwigCPtr, ModelPrimitive.getCPtr(modelPrimitive));
114             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
115         }
116
117         /// <summary>
118         /// Removes a ModelPrimitive object from the ModelNode object.
119         /// </summary>
120         /// <param name="modelPrimitive">The ModelPrimitive object to remove.</param>
121         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
122         [EditorBrowsable(EditorBrowsableState.Never)]
123         public void RemoveModelPrimitive(ModelPrimitive modelPrimitive)
124         {
125             Interop.ModelNode.RemoveModelPrimitive(SwigCPtr, ModelPrimitive.getCPtr(modelPrimitive));
126             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
127         }
128
129         /// <summary>
130         /// Removes a ModelPrimitive object from the ModelNode object at the specified index.
131         /// </summary>
132         /// <param name="index">The index of the ModelPrimitive object to remove.</param>
133         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
134         [EditorBrowsable(EditorBrowsableState.Never)]
135         public void RemoveModelPrimitive(uint index)
136         {
137             Interop.ModelNode.RemoveModelPrimitive(SwigCPtr, index);
138             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
139         }
140
141         /// <summary>
142         /// Gets the ModelPrimitive object at the specified index.
143         /// </summary>
144         /// <param name="index">The index of the ModelPrimitive object to get.</param>
145         /// <returns>The ModelPrimitive object at the specified index.</returns>
146         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
147         [EditorBrowsable(EditorBrowsableState.Never)]
148         public ModelPrimitive GetModelPrimitive(uint index)
149         {
150             global::System.IntPtr cPtr = Interop.ModelNode.GetModelPrimitive(SwigCPtr, index);
151             ModelPrimitive ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as ModelPrimitive;
152             if (ret == null)
153             {
154                 // Register new animatable into Registry.
155                 ret = new ModelPrimitive(cPtr, true);
156             }
157             else
158             {
159                 // We found matched NUI animatable. Reduce cPtr reference count.
160                 HandleRef handle = new HandleRef(this, cPtr);
161                 Tizen.NUI.Interop.BaseHandle.DeleteBaseHandle(handle);
162                 handle = new HandleRef(null, IntPtr.Zero);
163             }
164             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
165             return ret;
166         }
167
168         /// <summary>
169         /// Returns a child ModelNode object with a name that matches nodeName.
170         /// </summary>
171         /// <param name="nodeName">The name of the child ModelNode object you want to find.</param>
172         /// <returns>Child ModelNode that has nodeName as name.</returns>
173         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
174         [EditorBrowsable(EditorBrowsableState.Never)]
175         public ModelNode FindChildModelNodeByName(string nodeName)
176         {
177             global::System.IntPtr cPtr = Interop.Model.FindChildModelNodeByName(SwigCPtr, nodeName);
178             ModelNode ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as ModelNode;
179             if (ret == null)
180             {
181                 // Store the value of PositionUsesAnchorPoint from dali object (Since View object automatically change PositionUsesPivotPoint value as false, we need to keep value.)
182                 HandleRef handle = new HandleRef(this, cPtr);
183
184                 // Use original value as 'true' if we got invalid ModelNode.
185                 bool originalPositionUsesAnchorPoint = (cPtr == global::System.IntPtr.Zero || !Tizen.NUI.Interop.BaseHandle.HasBody(handle)) || Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
186                 handle = new HandleRef(null, IntPtr.Zero);
187
188                 // Register new animatable into Registry.
189                 ret = new ModelNode(cPtr, true);
190                 if (ret != null)
191                 {
192                     ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
193                 }
194             }
195             else
196             {
197                 // We found matched NUI animatable. Reduce cPtr reference count.
198                 HandleRef handle = new HandleRef(this, cPtr);
199                 Tizen.NUI.Interop.BaseHandle.DeleteBaseHandle(handle);
200                 handle = new HandleRef(null, IntPtr.Zero);
201             }
202             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
203             return ret;
204         }
205         
206         /// <summary>
207         /// Sets collider mesh on current node
208         /// </summary>
209         /// <param name="vertexList">List of vertices</param>
210         /// <param name="normalList">List of vertex normals</param>
211         /// <param name="indexList">List of mesh indices</param>
212         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
213         [EditorBrowsable(EditorBrowsableState.Never)]
214         public void SetColliderMesh(List<Vector3> vertexList, List<Vector3> normalList, List<int> indexList)
215         {
216             var vertices = new Interop.ModelNode.Vec3[vertexList.Count];
217             var idx = 0;
218             foreach (var vertex in vertexList)
219             {
220                 vertices[idx].x = vertex.X;
221                 vertices[idx].y = vertex.Y;
222                 vertices[idx].z = vertex.Z;
223                 ++idx;
224             }
225             
226             var normals = new Interop.ModelNode.Vec3[normalList.Count];
227             idx = 0;
228             foreach (var normal in normalList)
229             {
230                 normals[idx].x = normal.X;
231                 normals[idx].y = normal.Y;
232                 normals[idx].z = normal.Z;
233                 ++idx;
234             }
235             
236             Interop.ModelNode.SetColliderMesh(SwigCPtr,vertices, normals, vertexList.Count, indexList.ToArray(), indexList.Count);
237             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
238         }
239
240         /// <summary>
241         /// Sets whether this Model casts shadow or not.
242         /// If it is true, this model is drawn on Shadow Map.
243         /// Note: This method affects all of the child ModelNode.
244         /// However, same property of each child ModelNode can be changed respectively and it not changes parent's property.
245         /// </summary>
246         /// <param name="castShadow">Whether this Model casts shadow or not.</param>
247         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
248         [EditorBrowsable(EditorBrowsableState.Never)]
249         public void CastShadow(bool castShadow)
250         {
251             Interop.ModelNode.CastShadow(SwigCPtr, castShadow);
252             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
253         }
254
255         /// <summary>
256         /// Retrieves whether the Model casts shadow or not for Light.
257         /// Note: IBL does not cast any shadow.
258         /// </summary>
259         /// <returns>True if this model casts shadow.</returns>
260         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
261         [EditorBrowsable(EditorBrowsableState.Never)]
262         public bool IsShadowCasting()
263         {
264             var isShadowCasting = Interop.ModelNode.IsShadowCasting(SwigCPtr);
265             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
266             return isShadowCasting;
267         }
268
269         /// <summary>
270         /// Sets whether this Model receives shadow or not.
271         /// If it is true, shadows are drawn on this model.
272         /// Note: This method affects all of the child ModelNode.
273         /// However, same property of each child ModelNode can be changed respectively and it not changes parent's property.
274         /// </summary>
275         /// <param name="receiveShadow">Whether this Model receives shadow or not.</param>
276         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
277         [EditorBrowsable(EditorBrowsableState.Never)]
278         public void ReceiveShadow(bool receiveShadow)
279         {
280             Interop.ModelNode.ReceiveShadow(SwigCPtr, receiveShadow);
281             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
282         }
283
284         /// <summary>
285         /// Retrieves whether the Model receives shadow or not for Light
286         /// If it is true, this model is drawn on Shadow Map.
287         /// </summary>
288         /// <returns>True if this model receives shadow.</returns>
289         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
290         [EditorBrowsable(EditorBrowsableState.Never)]
291         public bool IsShadowReceiving()
292         {
293             var isShadowReceiving = Interop.ModelNode.IsShadowReceiving(SwigCPtr);
294             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
295             return isShadowReceiving;
296         }
297
298         /// <summary>
299         /// Gets the number of ModelPrimitive objects in the ModelNode object.
300         /// </summary>
301         /// <returns>The number of ModelPrimitive objects in the ModelNode object.</returns>
302         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
303         [EditorBrowsable(EditorBrowsableState.Never)]
304         private uint GetModelPrimitiveCount()
305         {
306             uint ret = Interop.ModelNode.GetModelPrimitiveCount(SwigCPtr);
307             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
308             return ret;
309         }
310
311         /// <summary>
312         /// Build C# ModelNode Tree
313         /// </summary>
314         [EditorBrowsable(EditorBrowsableState.Never)]
315         internal void Build()
316         {
317             List<ModelNode> childModelNodes = new List<ModelNode>();
318             uint childModelNodeCount = GetChildModelNodeCount();
319             for (uint i = 0; i < childModelNodeCount; ++i)
320             {
321                 ModelNode modelNode = GetChildModelNodeAt(i);
322                 if (modelNode != null)
323                 {
324                     childModelNodes.Add(modelNode);
325                     modelNode.Build();
326                 }
327             }
328
329             foreach (ModelNode node in childModelNodes)
330             {
331                 this.Add(node);
332             }
333         }
334
335         /// <summary>
336         /// Gets the number of child objects in the ModelNode object.
337         /// </summary>
338         /// <returns>The number of childchild objects in the ModelNode object.</returns>
339         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
340         [EditorBrowsable(EditorBrowsableState.Never)]
341         private uint GetChildModelNodeCount()
342         {
343             uint ret = Interop.ModelNode.GetChildModelNodeCount(SwigCPtr);
344             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
345             return ret;
346         }
347
348         /// <summary>
349         /// Returns a child ModelNode object at the index.
350         /// </summary>
351         /// <param name="index">The index of child ModelNode object you want to find.</param>
352         /// <returns>Child ModelNode</returns>
353         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
354         [EditorBrowsable(EditorBrowsableState.Never)]
355         private ModelNode GetChildModelNodeAt(uint index)
356         {
357             global::System.IntPtr cPtr = Interop.ModelNode.GetChildModelNodeAt(SwigCPtr, index);
358             ModelNode ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as ModelNode;
359             if (ret == null)
360             {
361                 // Store the value of PositionUsesAnchorPoint from dali object (Since View object automatically change PositionUsesPivotPoint value as false, we need to keep value.)
362                 HandleRef handle = new HandleRef(this, cPtr);
363
364                 // Use original value as 'true' if we got invalid ModelNode.
365                 bool originalPositionUsesAnchorPoint = (cPtr == global::System.IntPtr.Zero || !Tizen.NUI.Interop.BaseHandle.HasBody(handle)) || Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
366                 handle = new HandleRef(null, IntPtr.Zero);
367
368                 // Register new animatable into Registry.
369                 ret = new ModelNode(cPtr, true);
370                 if (ret != null)
371                 {
372                     ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
373                 }
374             }
375             else
376             {
377                 // We found matched NUI animatable. Reduce cPtr reference count.
378                 HandleRef handle = new HandleRef(this, cPtr);
379                 Tizen.NUI.Interop.BaseHandle.DeleteBaseHandle(handle);
380                 handle = new HandleRef(null, IntPtr.Zero);
381             }
382             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
383             return ret;
384         }
385
386         /// <summary>
387         /// Release swigCPtr.
388         /// </summary>
389         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
390         [EditorBrowsable(EditorBrowsableState.Never)]
391         protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr)
392         {
393             Interop.ModelNode.DeleteModelNode(swigCPtr);
394         }
395     }
396 }