summaryrefslogtreecommitdiffstats
path: root/o3d/core/cross/client.h
blob: 19cc45ea46dd194675459104061e2715a388c95b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
/*
 * Copyright 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


// This file contains the class definition of the o3d::Client,
// the main entry point to O3D.

#ifndef O3D_CORE_CROSS_CLIENT_H_
#define O3D_CORE_CROSS_CLIENT_H_

#include <build/build_config.h>
#include <map>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "core/cross/service_dependency.h"
#include "core/cross/error_status.h"
#include "core/cross/draw_list_manager.h"
#include "core/cross/counter_manager.h"
#include "core/cross/object_manager.h"
#include "core/cross/semantic_manager.h"
#include "core/cross/transformation_context.h"
#include "core/cross/render_node.h"
#include "core/cross/callback.h"
#include "core/cross/event.h"
#include "core/cross/event_callback.h"
#include "core/cross/event_manager.h"
#include "core/cross/lost_resource_callback.h"
#include "core/cross/render_event.h"
#include "core/cross/render_surface.h"
#include "core/cross/tick_event.h"
#include "core/cross/timer.h"
#include "core/cross/timingtable.h"
#include "core/cross/transform.h"

namespace o3d {
class MessageQueue;
class Profiler;
class State;
class Pack;

// The Client class is the main point of entry to O3D.  It defines methods
// for creating and deleting packs and internal use only methods for creating
// most objects. Each new object created by the Client is assigned a unique ID
// which can be used to efficiently retrieve the object using the appropriate
// Get*ById() method.
//
// The Client has a root transform for the transform graph and a root render
// node for the render graph.
class Client {
  friend class ObjectBase;
  friend class ParamObject;

 public:

  explicit Client(ServiceLocator* service_locator);
  ~Client();

  typedef NonRecursiveCallback1Manager<const RenderEvent&>
      RenderCallbackManager;
  typedef RenderCallbackManager::CallbackType RenderCallback;

  // Name of the default pack that the default rendergraph rendernodes belong
  // to.
  static const char* kDefaultPackName;

  Id id() const {
    return id_;
  }

  // Sets the renderer to be used for all platform-specific graphics
  // methods and sets up the default rendergraph
  void Init();

  // Cleansup certain things in preparation for unloading the plugin.
  // This is for Javascript because there are certain conditions, the Render
  // callback for example, which can cause a javascript error in the browser
  // while the page is being unloaded. This function, if called during
  // window.onunload, handles those cases.
  void Cleanup();

  // Pack methods --------------------------

  // Creates a pack object, and registers it within the Client's internal
  // dictionary strutures.  Note that multiple packs may share the same name.
  // The system does not enforce pack name uniqueness.
  // Returns:
  //  A smart-pointer reference to the newly created pack object.
  Pack* CreatePack();

  // Node methods --------------------------

  // Returns the transform graph root transform
  // Parameters:
  //  None
  // Returns:
  //  A pointer to the transform graph root Transform
  inline Transform* root() const {
    return root_.Get();
  }

  // RenderNode methods --------------------------

  enum RenderMode {
    RENDERMODE_CONTINUOUS,  // Draw as often as possible up to refresh rate.
    RENDERMODE_ON_DEMAND,   // Draw once, then only when the OS requests it
                            //    (like uncovering part of a window.)
  };

  RenderMode render_mode() const {
    return render_mode_;
  }

  void set_render_mode(RenderMode render_mode);

  // Returns the rendergraph root render node.
  // Parameters:
  //  None.
  // Returns:
  //  A pointer to the rendergraph root rendernode.
  inline RenderNode* render_graph_root() const {
    return rendergraph_root_;
  }

  // Searches the entire Client's rendernode dictionary for rendernodes that
  // match the given name. It will find rendernodes created by the Client
  // regardless of whether or not they are part of the rendergraph.
  // Parameters:
  //  name: Node name to look for.
  //  render_nodes: RenderNodeArray to receive list of nodes. It anything is in
  //                the array will be cleared.
  void GetRenderNodesFast(const String& name,
                          RenderNodeArray* render_nodes) const;

  // Renders a subtree of the rendergraph.
  // Parameters:
  //  tree_root: The root of the subtree to be drawn.
  // Returns:
  //  Nothing
  void RenderTree(RenderNode *tree_root);

  // Sets the render callback.
  // NOTE: The client takes ownership of the RenderCallback you pass in. It will
  // be deleted if you call SetRenderCallback a second time or if you call
  // ClearRenderCallback
  //
  // Parameters:
  //   render_callback: RenderCallback to call each frame.
  void SetRenderCallback(RenderCallback* render_callback);

  // Clears the render callback
  // NOTE: The client takes ownership of the RenderCallback you pass in to
  // SetRenderCallback. It will be deleted if you call SetRenderCallback a
  // second time or if you call ClearRenderCallback
  void ClearRenderCallback();

  // Sets the callback for a events of a supplied type.
  // NOTE: The client takes ownership of the EventCallback you pass in. It will
  // be deleted if you call SetEventCallback a second time for the same event
  // type or if you call ClearEventCallback for that type.
  //
  // Parameters:
  //   event_callback: EventCallback to call each time an event of the right
  //                   type occurs.
  //   type: Type of event this callback handles.
  void SetEventCallback(Event::Type type, EventCallback* render_callback);
  void SetEventCallback(String type_name, EventCallback* render_callback);

  // Clears the callback for events of a given type.
  void ClearEventCallback(Event::Type type);
  void ClearEventCallback(String type_name);

  // Automatically drops some events to throttle event bandwidth.
  void AddEventToQueue(const Event& event);
  // Adds a resize event to the queue.
  void SendResizeEvent(int width, int height, bool fullscreen);

  // Sets the lost resources callback.
  // NOTE: The client takes ownership of the LostResourcesCallback you pass in.
  // It will be deleted if you call SetLostResourcesCallback a second time or if
  // you call ClearLostResourcesCallback
  //
  // Parameters:
  //   callback: LostResourcesCallback to call each frame.
  void SetLostResourcesCallback(LostResourcesCallback* callback);

  // Clears the lost resources callback
  // NOTE: The client takes ownership of the LostResourcesCallback you pass in
  // to SetLostResourcesCallback. It will be deleted if you call
  // SetLostResourcesCallback a second time or if you call
  // ClearLostResourcesCallback.
  void ClearLostResourcesCallback();

  // Forces a render of the current scene if the current render mode is
  // RENDERMODE_ON_DEMAND.
  void Render();

  // Sets the post render callback.
  // NOTE: The client takes ownership of the RenderCallback you pass in. It will
  // be deleted if you call SetPostRenderCallback a second time or if you call
  // ClearPostRenderCallback
  //
  // Parameters:
  //   post_render_callback: RenderCallback to call at the end of
  //                         the render cycle in each frame.
  void SetPostRenderCallback(RenderCallback* post_render_callback);

  // Clears the post render callback
  // NOTE: The client takes ownership of the RenderCallback you pass in to
  // SetPostRenderCallback. It will be deleted if you call post
  // SetRenderCallback a second time or if you call ClearRenderCallback.
  void ClearPostRenderCallback();

  // Updates the current state of the objects handled by the Client and
  // processes any messages found in the message queue then renders the client.
  // This is the function anything hosting the client, like a plugin, should
  // call to render.
  // Parameters:
  //   send_callback : whether to make the javascript render callback.
  //       Generally you want to pass true, but if the render is happening
  //       in non-windowed mode (eg on a Mac) and is in response to an update
  //       event rather than a timer, it can be useful to pass false to prevent
  //       the javascript code triggering another update and causing an infinite
  //       calback loop. Case in point is the custom camera example, which
  //       modifies some HTML form text fields on render callback, which on
  //       Firefox causes a plugin invalidation and round and round we would
  //       go.
  void RenderClient(bool send_callback);

  // In some situations (on Mac OS X at least) calling the user's
  // render callback can cause OS events to be dispatched which cause
  // the plugin to become reentrant. Detect this at a higher level.
  bool IsRendering();

  // Needs either ONDEMAND or CONTINOUS render.
  bool NeedsRender();

  // If Renderer::max_fps has been set in RENDERMODE_CONTINUOUS mode, we don't
  // draw on each tick but just let new textures drive the rendering. There is
  // only one exception: if we haven't received any new textures for a while, we
  // still need to draw in order to trigger rendering callback. Since there
  // might be some UI depends on rendering callback.
  // This function determines if this has happened and if we need a draw.
  bool NeedsContinuousRender();

  // Sets the texture to use when a Texture or Sampler is missing while
  // rendering. If you set it to NULL you'll get an error if you try to render
  // something that is missing a needed Texture, Sampler or ParamSampler
  // Parameters:
  //   texture: texture to use for missing texture or NULL.
  void SetErrorTexture(Texture* texture);

  // Tick Methods ----------------------------

  typedef NonRecursiveCallback1Manager<const o3d::TickEvent&>
      TickCallbackManager;
  typedef TickCallbackManager::CallbackType TickCallback;

  // Sets the tick callback.
  // NOTE: The client takes ownership of the TickCallback you pass in. It will
  // be deleted if you call SetTickCallback a second time or if you call
  // ClearTickCallback.
  //
  // Parameters:
  //   tick_callback: TickCallback to call each time the client processes a
  //       tick.
  void SetTickCallback(TickCallback* tick_callback);

  // Clears the tick callback NOTE: The client takes ownership of the
  // TickCallback you pass in to SetTickCallback. It will be deleted if you call
  // SetTickCallback a second time or if you call ClearTickCallback.
  void ClearTickCallback();

  // Tick the client. This method is called by the plugin to give the client
  // a chance to process NaCl messages and update animation.
  // Returns:
  //   true if message check was ok.
  bool Tick();

  // Indicates whether a call to Tick() is in progress. This is needed
  // to avoid reentrancy problems on some platforms.
  bool IsTicking() const {
    return is_ticking_;
  }

  // Searches in the Client for an object by its id. This function is for
  // Javascript.
  // Parameters:
  //   id: id of object to look for.
  // Returns:
  //   Pointer to the object or NULL if not found.
  ObjectBase* GetObjectById(Id id) const {
    return object_manager_->GetObjectById(id);
  }

  // Searches the Client for objects of a particular name and type.
  // This function is for Javascript.
  // Parameters:
  //   name: name of object to look for.
  //   type_name: name of class to look for.
  // Returns:
  //   Array of raw pointers to the found objects.
  ObjectBaseArray GetObjects(const String& name,
                             const String& type_name) const {
    return object_manager_->GetObjects(name, type_name);
  }

  // Searches by id for an Object created by the Client. To search
  // for an object regardless of type use:
  //   Client::GetById<ObjectBase>(obj_id)
  // To search for an object of a specific type use:
  //   Client::GetById<Type>(obj_id)
  // for example, to search for Transform use:
  //   Client::GetById<Transform>(transform_id)
  // Parameters:
  //  id: Unique id of the object to search for
  // Returns:
  //  Pointer to the object with matching id or NULL if no object is found
  template<class T> T* GetById(Id id) const {
    return object_manager_->GetById<T>(id);
  }

  // Search the client for all objects of a certain class
  // Returns:
  //   Array of Pointers to the requested class.
  template<typename T>
  std::vector<T*> GetByClass() const {
    return object_manager_->GetByClass<T>();
  }

  // Search the client for all objects of a certain class
  // Parameters:
  //  class_type_name: the Class of the object. It is okay to pass base types
  //                   for example Node::GetApparentClass()->name will return
  //                   both Transforms and Shapes.
  // Returns:
  //   Array of Object Pointers.
  ObjectBaseArray GetObjectsByClassName(const String& class_type_name) const {
    return object_manager_->GetObjectsByClassName(class_type_name);
  }

  // Returns the socket address of the IMC message queue associated with the
  // Client.
  String GetMessageQueueAddress() const;

  // Error Methods ----------------

  typedef Callback1<const String&> ErrorCallback;

  // Sets the error callback. NOTE: The client takes ownership of the
  // ErrorCallback you pass in. It will be deleted if you call SetErrorCallback
  // a second time or if you call ClearErrorCallback.
  //
  // Parameters:
  //   error_callback: ErrorCallback to call each time the client gets
  //       an error.
  void SetErrorCallback(ErrorCallback* error_callback);

  // Clears the Error callback NOTE: The client takes ownership of the
  // ErrorCallback you pass in to SetErrorCallback. It will be deleted if you
  // call SetErrorCallback a second time or if you call ClearErrorCallback.
  void ClearErrorCallback();

  // Gets the last reported error.
  const String& GetLastError() const;

  // Clears the stored last error.
  void ClearLastError();

  // Parameter methods ------------------

  // Marks all parameters as so they will get re-evaluated
  void InvalidateAllParameters();

  // Profiling methods -------------------

  // Starts the timer ticking for the code range identified by key.
  void ProfileStart(const std::string& key);

  // Stops the timer for the code range identified by key.
  void ProfileStop(const std::string& key);

  // Resets the profiler, clearing out all data.
  void ProfileReset();

  // Dumps all profiler state to a string.
  String ProfileToString();

  // Reutrns a data: URL of the client area in png format.
  String ToDataURL();

  // This class is intended to be used on the stack, such that the variable gets
  // incremented on scope entry and decremented on scope exit.  It's currently
  // used in WindowProc to determine if we're reentrant or not, but may be
  // needed on other platforms as well.
  class ScopedIncrement {
   public:
    explicit ScopedIncrement(Client *client) {
      DCHECK(client);
      client_ = client;
      ++client_->calls_;
      DCHECK_GT(client_->calls_, 0);
    }
    int get() {
      DCHECK(client_);  // Don't call this after decrement!
      return client_->calls_;
    }
    void decrement() {
      if (client_) {
        DCHECK_GT(client_->calls_, 0);
        --client_->calls_;
        client_ = NULL;
      }
    }
    ~ScopedIncrement() {
      decrement();
    }
   private:
    Client *client_;
    DISALLOW_COPY_AND_ASSIGN(ScopedIncrement);
  };

  // Offscreen rendering methods -------------------

  // Sets up this Client so that RenderClient will cause the rendering
  // results to go into the given surfaces.
  void SetOffscreenRenderingSurfaces(
      RenderSurface::Ref surface,
      RenderDepthStencilSurface::Ref depth_surface);

 private:
  // Renders the client.
  void RenderClientInner(bool present, bool send_callback);

  // Gets a screenshot.
  String GetScreenshotAsDataURL();

  // MessageQueue that allows external code to communicate with the Client.
  scoped_ptr<MessageQueue> message_queue_;

  ServiceLocator* service_locator_;
  ServiceDependency<ObjectManager> object_manager_;
  ErrorStatus error_status_;
  DrawListManager draw_list_manager_;
  CounterManager counter_manager_;
  TransformationContext transformation_context_;
  SemanticManager semantic_manager_;
  ServiceDependency<Profiler> profiler_;
  ServiceDependency<Renderer> renderer_;
  ServiceDependency<EvaluationCounter> evaluation_counter_;

  // RenderTree was called.
  bool render_tree_called_;

  // Render mode.
  RenderMode render_mode_;

  // Used for rendering control
  bool texture_on_hold_;

  // Render Callbacks.
  RenderCallbackManager render_callback_manager_;

  RenderCallbackManager post_render_callback_manager_;

  // Render Event to pass to the render callback.
  RenderEvent render_event_;

  // This class holds on to all the handlers and the event queue for standard
  // JavaScript IO events.
  EventManager event_manager_;

  // Timer for getting the elapsed time between render updates.
  ElapsedTimeTimer render_elapsed_time_timer_;

  // Tick Callback.
  TickCallbackManager tick_callback_manager_;

  // Tick Event to pass to the tick callback.
  TickEvent tick_event_;

  // Timer for getting the elapsed time between tick updates.
  ElapsedTimeTimer tick_elapsed_time_timer_;

  // Whether a call to Tick() is currently active.
  bool is_ticking_;

  // Used to gather render time from mulitple RenderTree calls.
  float total_time_to_render_;

  // Time used for tick and message processing.
  float last_tick_time_;

  // Number of ticks since last reset.
  int tick_count_;

  // Reference to global transform graph root for Client.
  Transform::Ref root_;

  // Global Render Graph root for Client.
  RenderNode::Ref rendergraph_root_;

  ParamObject::Ref sas_param_object_;

  // The id of the client.
  Id id_;

  int calls_;  // Used to check reentrancy along with ScopedIncrement.

  RenderSurface::Ref offscreen_render_surface_;
  RenderDepthStencilSurface::Ref offscreen_depth_render_surface_;

  DISALLOW_COPY_AND_ASSIGN(Client);
};  // Client

}  // namespace o3d

#endif  // O3D_CORE_CROSS_CLIENT_H_