47760608cb405f5cb704fc93913f1b1885fef271
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.Samples / Tizen.NUI.Samples / Samples / DisposeTest.cs
1 using System;
2 using System.Runtime.InteropServices;
3 using Tizen.NUI.BaseComponents;
4 using System.Collections.Generic;
5
6 namespace Tizen.NUI.Samples
7 {
8     // Make custom view to ignore Layout features so we can use Depth information
9     public class Custom3DView : CustomView
10     {
11         // Default View Enabled SizeNegotiations, and It is Breakdown the depth values.
12         // So we need to create CustomView whitch CustomViewBehavior.DisableSizeNegotiation.
13         public Custom3DView() : base("Custom3DView", CustomViewBehaviour.DisableSizeNegotiation)
14         {
15         }
16     }
17
18     // copied from https://github.com/hinohie/nui-demo/blob/geotest/Mesh/Mesh.cs
19     public class DisposeTest : IExample
20     {
21         public struct Vec2
22         {
23             float x;
24             float y;
25             public Vec2(float xIn, float yIn)
26             {
27                 x = xIn;
28                 y = yIn;
29             }
30         }
31         public struct Vec3
32         {
33             float x;
34             float y;
35             float z;
36             public Vec3(float xIn, float yIn, float zIn)
37             {
38                 x = xIn;
39                 y = yIn;
40                 z = zIn;
41             }
42         }
43
44         struct TexturedQuadVertex
45         {
46             public Vec3 position;
47             public Vec3 normal;
48             public Vec2 texcoord;
49         }
50
51         static readonly string VERTEX_SHADER =
52         "attribute mediump vec3 aPosition;\n" +
53         "attribute mediump vec3 aNormal;\n" +
54         "attribute mediump vec2 aTexCoord;\n" +
55         "uniform mediump mat4 uMvpMatrix;\n" +
56         "uniform mediump mat3 uNormalMatrix;\n" +
57         "uniform mediump vec3 uSize;\n" +
58         "varying mediump vec3 vNormal;\n" +
59         "varying mediump vec2 vTexCoord;\n" +
60         "varying mediump vec3 vPosition;\n" +
61         "void main()\n" +
62         "{\n" +
63         "    vec4 pos = vec4(aPosition, 1.0)*vec4(uSize,1.0);\n"+
64         "    gl_Position = uMvpMatrix*pos;\n" +
65         "    vPosition = aPosition;\n" +
66         "    vNormal   = normalize(uNormalMatrix * aNormal);\n" +
67         "    vTexCoord = aTexCoord;\n" +
68         "}\n";
69
70         static readonly string FRAGMENT_SHADER =
71         "uniform lowp vec4 uColor;\n" +
72         "uniform sampler2D sTexture;\n" +
73         "varying mediump vec3 vNormal;\n" +
74         "varying mediump vec2 vTexCoord;\n" +
75         "varying mediump vec3 vPosition;\n" +
76         "mediump vec3 uLightDir = vec3(2.0, 0.5, 1.0);\n" + // constant light dir
77         "mediump vec3 uViewDir  = vec3(0.0, 0.0, 1.0);\n" + // constant view dir.
78         "mediump vec3 uAmbientColor = vec3(0.2, 0.2, 0.2);\n" +
79         "mediump vec3 uDiffuseColor = vec3(0.8, 0.8, 0.8);\n" +
80         "mediump vec3 uSpecularColor = vec3(0.5, 0.5, 0.5);\n" +
81         "void main()\n" +
82         "{\n" +
83         "    mediump vec3 lightdir = normalize(uLightDir);\n" +
84         "    mediump vec3 eyedir   = normalize(uViewDir);\n" +
85         "    mediump vec4 texColor = texture2D( sTexture, vTexCoord ) * uColor;\n" +
86         "    mediump float diffuse = min(max(-dot(vNormal, lightdir) + 0.1, 0.0), 1.0);\n" +
87         "    mediump vec3 reflectdir = reflect(-lightdir, vNormal);\n" +
88         "    mediump float specular = pow(max(0.0, dot(reflectdir, eyedir)), 50.0);\n" +
89         "    mediump vec4 color = texColor * vec4(uAmbientColor + uDiffuseColor * diffuse, 1.0) + vec4(uSpecularColor, 0.0) * specular;\n" +
90         "    gl_FragColor = color;\n" +
91         "}\n";
92
93         // Copy from dali-toolkit/internal/visuals/primitive/primitive-visual.cpp
94         // NOTE. I add one more slices for texture coordinate
95         private global::System.IntPtr SphereVertexDataPtr()
96         {
97             TexturedQuadVertex[] vertices = new TexturedQuadVertex[SPHERE_VERTEX_NUMBER];
98
99             const int slices = SPHERE_SLICES;
100             const int stacks = SPHERE_STACKS;
101             // Build start.
102             {
103                 int vertexIndex = 0; //Track progress through vertices.
104                 float x;
105                 float y;
106                 float z;
107
108                 //Top stack.
109                 vertices[vertexIndex].position = new Vec3(0.0f, 0.5f, 0.0f);
110                 vertices[vertexIndex].normal = new Vec3(0.0f, 1.0f, 0.0f);
111                 vertices[vertexIndex].texcoord = new Vec2(0.5f, 1.0f);
112                 vertexIndex++;
113
114                 //Middle stacks.
115                 for (int i = 1; i < stacks; i++)
116                 {
117                     //Note. This vertex method is not common.
118                     //We set one more vertexes for correct texture coordinate. at j == slices
119                     //j==0 and j==slices have equal position, normal, but there texcoord.x is different
120                     for (int j = 0; j <= slices; j++, vertexIndex++)
121                     {
122                         float cos_j = (float)Math.Cos(2.0f * (float)Math.PI * j / (float)slices);
123                         float sin_j = (float)Math.Sin(2.0f * (float)Math.PI * j / (float)slices);
124                         float cos_i = (float)Math.Cos((float)Math.PI * i / (float)stacks);
125                         float sin_i = (float)Math.Sin((float)Math.PI * i / (float)stacks);
126                         x = cos_j * sin_i;
127                         y = cos_i;
128                         z = sin_j * sin_i;
129
130                         vertices[vertexIndex].position = new Vec3(x / 2.0f, y / 2.0f, z / 2.0f);
131                         vertices[vertexIndex].normal = new Vec3(x, y, z);
132                         vertices[vertexIndex].texcoord = new Vec2((float)j / (float)slices, 1.0f - (float)i / (float)stacks);
133                     }
134                 }
135
136                 //Bottom stack.
137                 vertices[vertexIndex].position = new Vec3(0.0f, -0.5f, 0.0f);
138                 vertices[vertexIndex].normal = new Vec3(0.0f, -1.0f, 0.0f);
139                 vertices[vertexIndex].texcoord = new Vec2(0.5f, 0.0f);
140             }
141             // Build done.
142
143             int length = Marshal.SizeOf(vertices[0]);
144             global::System.IntPtr pA = Marshal.AllocHGlobal(length * SPHERE_VERTEX_NUMBER);
145
146             for (int i = 0; i < SPHERE_VERTEX_NUMBER; i++)
147             {
148                 Marshal.StructureToPtr(vertices[i], pA + i * length, true);
149             }
150
151             return pA;
152         }
153
154         private ushort[] SphereIndexData()
155         {
156             ushort[] indices = new ushort[SPHERE_INDEX_NUMBER];
157             const int slices = SPHERE_SLICES;
158             const int stacks = SPHERE_STACKS;
159
160             // Build start.
161             {
162                 int indiceIndex = 0; //Used to keep track of progress through indices.
163                 int previousCycleBeginning = 1; //Stores the index of the vertex that started the cycle of the previous stack.
164                 int currentCycleBeginning = 1 + slices + 1;
165
166                 //Top stack. Loop from index 1 to index slices, as not counting the very first vertex.
167                 for (int i = 1; i <= slices; i++, indiceIndex += 3)
168                 {
169                     indices[indiceIndex] = 0;
170                     indices[indiceIndex + 1] = (ushort)(i + 1);
171                     indices[indiceIndex + 2] = (ushort)i;
172                 }
173
174                 //Middle Stacks. Want to form triangles between the top and bottom stacks, so loop up to the number of stacks - 2.
175                 //Note. This index method is not common.
176                 //We increase Beginning indexes slices+1 cause we add one more vertexes for correct texture coordinate.
177                 for (int i = 0; i < stacks - 2; i++, previousCycleBeginning += slices + 1, currentCycleBeginning += slices + 1)
178                 {
179                     for (int j = 0; j < slices; j++, indiceIndex += 6)
180                     {
181                         indices[indiceIndex] = (ushort)(previousCycleBeginning + j);
182                         indices[indiceIndex + 1] = (ushort)(previousCycleBeginning + 1 + j);
183                         indices[indiceIndex + 2] = (ushort)(currentCycleBeginning + j);
184                         indices[indiceIndex + 3] = (ushort)(currentCycleBeginning + j);
185                         indices[indiceIndex + 4] = (ushort)(previousCycleBeginning + 1 + j);
186                         indices[indiceIndex + 5] = (ushort)(currentCycleBeginning + 1 + j);
187                     }
188                 }
189
190                 //Bottom stack. Loop around the last stack from the previous loop, and go up to the penultimate vertex.
191                 for (int i = 0; i < slices; i++, indiceIndex += 3)
192                 {
193                     indices[indiceIndex] = (ushort)(previousCycleBeginning + slices + 1);
194                     indices[indiceIndex + 1] = (ushort)(previousCycleBeginning + i);
195                     indices[indiceIndex + 2] = (ushort)(previousCycleBeginning + i + 1);
196                 }
197             }
198             // Build done.
199
200             return indices;
201         }
202         const int SPHERE_SLICES = 30; // >= 3
203         const int SPHERE_STACKS = 20; // >= 1
204         const int SPHERE_VERTEX_NUMBER = (SPHERE_SLICES + 1) * (SPHERE_STACKS - 1) + 2;
205         const int SPHERE_INDEX_NUMBER = 6 * SPHERE_SLICES * (SPHERE_STACKS - 1);
206
207
208         private const int AutoDisposedObjectCount = 10;
209         private const int ManualDisposedObjectCount = 10;
210         private Window win;
211         private View root;
212         private Timer timer;
213         private bool toggle = false;
214         private string resource;
215         private List<Custom3DView> views;
216         private Animation rotateAnimation;
217
218         public void Activate()
219         {
220             win = NUIApplication.GetDefaultWindow();
221             resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
222             // Set layer behavior as Layer3D. without this, Rendering will be broken
223             win.GetDefaultLayer().Behavior = Layer.LayerBehavior.Layer3D;
224             root = new View()
225             {
226                 Name = "root",
227                 Size = new Size(10, 10),
228                 BackgroundColor = Color.Blue,
229             };
230             win.Add(root);
231
232             views = new List<Custom3DView>();
233             rotateAnimation = new Animation(1500); //1.5s
234
235             AddManyViews();
236             toggle = true;
237
238             timer = new Timer(3000); //3s
239             timer.Tick += OnTimerTick;
240             timer.Start();
241
242         }
243
244         private bool OnTimerTick(object source, Timer.TickEventArgs e)
245         {
246             toggle = !toggle;
247             if (toggle)
248             {
249                 AddManyViews();
250             }
251             else
252             {
253                 RemoveAllViews();
254                 FullGC();
255             }
256             return true;
257         }
258
259         private Geometry GenerateGeometry()
260         {
261             PropertyMap vertexFormat = new PropertyMap();
262             vertexFormat.Add("aPosition", new PropertyValue((int)PropertyType.Vector3));
263             vertexFormat.Add("aNormal", new PropertyValue((int)PropertyType.Vector3));
264             vertexFormat.Add("aTexCoord", new PropertyValue((int)PropertyType.Vector2));
265             PropertyBuffer vertexBuffer = new PropertyBuffer(vertexFormat);
266
267             vertexBuffer.SetData(SphereVertexDataPtr(), SPHERE_VERTEX_NUMBER);
268
269             ushort[] indexBuffer = SphereIndexData();
270
271             Geometry geometry = new Geometry();
272             geometry.AddVertexBuffer(vertexBuffer);
273             geometry.SetIndexBuffer(indexBuffer, SPHERE_INDEX_NUMBER);
274             geometry.SetType(Geometry.Type.TRIANGLES);
275             return geometry;
276         }
277
278         private void AddManyViews()
279         {
280             Random rand = new Random();
281
282             for (int i = 0; i < AutoDisposedObjectCount; i++)
283             {
284                 int viewSize = 150;
285                 var view = new Custom3DView()
286                 {
287                     Size = new Size(viewSize, viewSize, viewSize),
288                     Position = new Position(
289                         rand.Next(10, win.WindowSize.Width - 10),
290                         rand.Next(10, win.WindowSize.Height - 10),
291                         rand.Next(-3 * viewSize, 3 * viewSize)
292                     ),
293                 };
294                 root.Add(view);
295
296                 PixelData pixelData = PixelBuffer.Convert(ImageLoading.LoadImageFromFile(
297                     resource + "/images/PopupTest/circle.jpg",
298                     new Size2D(),
299                     FittingModeType.ScaleToFill
300                 ));
301                 Texture texture = new Texture(
302                     TextureType.TEXTURE_2D,
303                     pixelData.GetPixelFormat(),
304                     pixelData.GetWidth(),
305                     pixelData.GetHeight()
306                 );
307                 texture.Upload(pixelData);
308                 TextureSet textureSet = new TextureSet();
309                 textureSet.SetTexture(0u, texture);
310                 Renderer renderer = new Renderer(GenerateGeometry(), new Shader(VERTEX_SHADER, FRAGMENT_SHADER));
311                 renderer.SetTextures(textureSet);
312                 view.AddRenderer(renderer);
313
314                 rotateAnimation.AnimateBy(view, "Orientation", new Rotation(new Radian(new Degree(360.0f)), Vector3.YAxis));
315             }
316
317             for (int i = 0; i < ManualDisposedObjectCount; i++)
318             {
319                 int viewSize = 150;
320                 var view = new Custom3DView()
321                 {
322                     Size = new Size(viewSize, viewSize, viewSize),
323                     Position = new Position(
324                         rand.Next(10, win.WindowSize.Width - 10),
325                         rand.Next(10, win.WindowSize.Height - 10),
326                         rand.Next(-3 * viewSize, 3 * viewSize)
327                     ),
328                 };
329                 root.Add(view);
330                 views.Add(view);
331
332                 PixelData pixelData = PixelBuffer.Convert(ImageLoading.LoadImageFromFile(
333                     resource + "/images/PaletteTest/red2.jpg",
334                     new Size2D(),
335                     FittingModeType.ScaleToFill
336                 ));
337                 Texture texture = new Texture(
338                     TextureType.TEXTURE_2D,
339                     pixelData.GetPixelFormat(),
340                     pixelData.GetWidth(),
341                     pixelData.GetHeight()
342                 );
343                 texture.Upload(pixelData);
344                 TextureSet textureSet = new TextureSet();
345                 textureSet.SetTexture(0u, texture);
346                 Renderer renderer = new Renderer(GenerateGeometry(), new Shader(VERTEX_SHADER, FRAGMENT_SHADER));
347                 renderer.SetTextures(textureSet);
348                 view.AddRenderer(renderer);
349
350                 rotateAnimation.AnimateBy(view, "Orientation", new Rotation(new Radian(new Degree(-360.0f)), Vector3.YAxis));
351             }
352             rotateAnimation.Looping = true;
353             rotateAnimation.Play();
354         }
355         private void RemoveAllViews()
356         {
357             uint cnt = root.ChildCount;
358             for (int i = (int)(cnt - 1); i >= 0; i--)
359             {
360                 root.Remove(root.GetChildAt((uint)i));
361             }
362             foreach(var view in views)
363             {
364                 var renderer = view.GetRendererAt(0);
365                 renderer.Dispose();
366                 view.Dispose();
367             }
368             views.Clear();
369             rotateAnimation.Clear();
370         }
371
372         private void FullGC()
373         {
374             global::System.GC.Collect();
375             global::System.GC.WaitForPendingFinalizers();
376             global::System.GC.Collect();
377         }
378
379         public void Deactivate()
380         {
381             timer.Stop();
382             RemoveAllViews();
383             rotateAnimation?.Dispose();
384             root.Unparent();
385             root.Dispose();
386         }
387     }
388 }