blob: 920a74655b667a53e611ecb3246178e605c18cfc [file] [log] [blame]
/*
* 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/memory/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_