extras; samples: Fixed warnings
[sdk] / samples / 3D / ModelViewer / eModel.ec
1 import "ecere"
2 import "engineSettings"
3
4 static FileFilter fileFilters[] =
5 {
6    {
7       "3D Studio Model Files (*.3ds)",
8       "3ds"
9    },
10    { "All files", null }
11 };
12
13 FileDialog fileDialog
14 {
15    filters = fileFilters, sizeFilters = sizeof(fileFilters);
16    text = "Select a 3DS model to display..."
17 };
18
19 ModelViewer modelViewer { };
20
21 class eModelApp : GuiApplication
22 {
23    // driver = "OpenGL";
24
25    void Main()
26    {
27       if(EngineSettings { }.Modal())
28       {
29          bool selected = false;
30          if(argc > 1)
31          {
32             selected = true;
33             fileDialog.filePath = argv[1];
34          }
35          else
36          {
37             fileDialog.filePath = "models/cow/cow.3DS";
38             //selected = true;
39          }
40          while(selected || fileDialog.Modal() == ok)
41          {
42             modelViewer.modelFile = fileDialog.filePath;
43             modelViewer.Modal();
44             selected = false;
45          }
46       }
47    }
48 }
49
50 class ModelViewer : Window
51 {
52    caption = $"Ecere Model Viewer";
53    background = blue;
54    borderStyle = sizable;
55    hasMaximize = true;
56    hasMinimize = true;
57    hasClose = true;
58    anchor = { left = 0, top = 0, right = 0, bottom = 0 };
59
60    Camera camera
61    {
62       attached,
63       fovDirection = vertical,
64       fov = 53,
65       position = { 0, 0, -10 },
66       eulerOrientation = Euler { 30, 0, 0 },
67       zMin = 1;
68       zMax = 10000;
69    };
70    Object cameraTarget { };
71    Object model {};
72
73    //FPS frameRate;
74
75    bool moving, lightMoving;
76    Timer timer
77    {
78       this, delay = 0.01;
79
80       bool DelayExpired()
81       {
82          if(model)
83             model.frame++;
84
85          Update(null);
86          return true;
87       }
88    };
89
90    Point startPosition;
91    Euler startOrientation;
92    Light light
93    {
94       diffuse = white;
95       specular = white;
96       orientation = Euler { pitch = 50, yaw = 45 };
97    };
98    EditBox help
99    {
100       this, caption = $"Help", background = red, 0.2f, borderStyle = sizable, font = { "Courier New", 10 }, size = { 420, 130 }, anchor = { top = 0, right = 0 }, visible = false, hasHorzScroll = true, true, readOnly = true, true, noCaret = true
101    };
102
103    FillModeValue fillMode;
104    SkyBox sky { size = { 10000, 10000, 10000 }, folder = ":skycube", extension = "jpg" };
105
106    const char * modelFile;
107
108    ModelViewer()
109    {
110       File f = FileOpen(":help.txt", read);
111       if(f)
112       {
113          help.Load(f);
114          delete f;
115       }
116    }
117
118    bool OnCreate()
119    {
120       fillMode = solid;
121       timer.userData = this;
122       // timer.Start();
123       return true;
124    }
125
126    void OnUnloadGraphics()
127    {
128       sky.Free(displaySystem);
129       model.Free(displaySystem);
130       displaySystem.ClearMaterials();
131       displaySystem.ClearTextures();
132       displaySystem.ClearMeshes();
133    }
134
135    void OnDestroy()
136    {
137       delete model;
138       model = { };
139       //sky.Free(null);
140       //model.Free(null);
141    }
142
143    void OnResize(int w, int h)
144    {
145       camera.Setup(w, h, null);
146       Update(null);
147    }
148
149    bool OnLeftButtonDown(int x, int y, Modifiers mods)
150    {
151       if(!moving && !lightMoving)
152       {
153          startPosition.x = x;
154          startPosition.y = y;
155          startOrientation = camera.eulerOrientation;
156          Capture();
157          moving = true;
158       }
159       return true;
160    }
161
162    bool OnLeftButtonUp(int x, int y, Modifiers mods)
163    {
164       if(moving)
165       {
166          ReleaseCapture();
167          moving = false;
168       }
169       return true;
170    }
171
172    bool OnRightButtonDown(int x, int y, Modifiers mods)
173    {
174       if(!moving && !lightMoving)
175       {
176          startPosition.x = x;
177          startPosition.y = y;
178          startOrientation = light.orientation;
179          Capture();
180          lightMoving = true;
181       }
182       return true;
183    }
184
185    bool OnRightButtonUp(int x, int y, Modifiers mods)
186    {
187       if(lightMoving)
188       {
189          ReleaseCapture();
190          lightMoving = false;
191       }
192       return true;
193    }
194
195    bool OnMouseMove(int x, int y, Modifiers mods)
196    {
197       if(moving)
198       {
199          Euler euler
200          {
201             startOrientation.yaw   - (x - startPosition.x),
202             startOrientation.pitch + (y - startPosition.y),
203             0
204          };
205
206          camera.eulerOrientation = euler;
207
208          Update(null);
209       }
210       else if(lightMoving)
211       {
212          light.orientation = Euler
213          {
214             startOrientation.yaw   - (x - startPosition.x),
215             startOrientation.pitch + (y - startPosition.y),
216             0
217          };
218
219          Update(null);
220       }
221       return true;
222    }
223
224    bool OnKeyDown(Key key, unichar ch)
225    {
226       switch(key)
227       {
228          case escape: Destroy(0); return false;
229          case g:
230             fillMode = (fillMode == wireframe) ? solid : wireframe;
231             break;
232          case h:
233             help.visible ^= true;
234             break;
235       }
236       return true;
237    }
238
239    bool OnKeyHit(Key key, unichar ch)
240    {
241       switch((SmartKey) key)
242       {
243          case wheelDown: case minus: camera.position.z *= 1.1111111f; Update(null); break;
244          case wheelUp: case plus: camera.position.z *= 0.9f; Update(null); break;
245          case up:    camera.position.y += camera.position.z / 20; Update(null); break;
246          case down:  camera.position.y -= camera.position.z / 20; Update(null); break;
247          case left:    camera.position.x += camera.position.z / 20; Update(null); break;
248          case right:  camera.position.x -= camera.position.z / 20; Update(null); break;
249          /*
250             case pageDown: model.Animate(model.frame + 1); break;
251             case pageUp: model.Animate(model.frame - 1); break;
252             case home: model.Animate(model.startFrame); break;
253             case end: model.Animate(model.endFrame); break;
254          */
255       }
256       return true;
257    }
258
259    bool OnLoadGraphics()
260    {
261       if(model.Load(modelFile, null, displaySystem))
262       {
263          float r = model.radius;
264          cameraTarget.transform.position =
265          {
266             (model.max.x + model.min.x) / 2,
267             (model.max.y + model.min.y) / 2,
268             (model.max.z + model.min.z) / 2
269          };
270          // model.Merge(displaySystem);
271          camera.zMin = 1;
272          camera.zMax = 10000;
273          camera.position = { 0, 0, -r * 2 };
274          camera.eulerOrientation = Euler { 30, 0, 0 };
275
276          light.orientation = Euler { pitch = 50, yaw = 45 };
277
278          if(r * 2 < camera.zMax / 10)
279          {
280             while(r * 2 < camera.zMax / 100)
281             {
282                camera.zMax /= 10;
283                camera.zMin /= 10;
284             }
285          }
286          else
287             while(r * 2 > camera.zMax / 10)
288             {
289                camera.zMax *= 10;
290                camera.zMin *= 10;
291             }
292
293          camera.target = cameraTarget;
294
295          sky.size = { camera.zMax, camera.zMax, camera.zMax };
296          sky.Create(displaySystem);
297          return true;
298       }
299       return false;
300    }
301
302    void OnRedraw(Surface surface)
303    {
304       //display.fogColor = blue;
305       display.fogDensity = 0; //0.000001f;
306
307       surface.SetBackground(lightBlue);
308       surface.Clear(colorAndDepth);
309
310       camera.Update();
311
312       // Set Light before setting the camera will set the light in view space
313       display.SetLight(0, &light);
314
315       display.SetCamera(surface, camera);
316
317       // Set Light after setting the camera will set the light in world space
318       //display.SetLight(0, &light);
319
320       display.ambient = { 30, 30, 30 }; //black;
321       // display.SetLights(model);
322
323       display.fillMode = fillMode;
324
325       sky.Render(camera, display);
326       display.DrawObject(model);
327
328       display.fillMode = solid;
329
330       display.SetCamera(surface, null);
331
332       /*
333       frameRate.Step();
334       surface.SetForeground(Black);
335       if(model)
336          surface.WriteTextf(0,0, "%.2f, Frame: %d",  frameRate.fps, model.frame++);
337       */
338       surface.WriteTextf(0,20, "Press H to toggle help screen");
339    }
340 }