integrate pview with new task manager

This commit is contained in:
David Rose 2008-10-03 20:30:07 +00:00
parent b9cb301df9
commit 4beba6ca6f
15 changed files with 507 additions and 40 deletions

View File

@ -15,6 +15,7 @@
config_event.h \
buttonEvent.I buttonEvent.h \
buttonEventList.I buttonEventList.h \
genericAsyncTask.h genericAsyncTask.I \
pointerEvent.I pointerEvent.h \
pointerEventList.I pointerEventList.h \
pythonTask.h pythonTask.I \
@ -30,6 +31,7 @@
asyncTaskManager.cxx \
buttonEvent.cxx \
buttonEventList.cxx \
genericAsyncTask.cxx \
pointerEvent.cxx \
pointerEventList.cxx \
pythonTask.cxx \
@ -44,6 +46,7 @@
asyncTaskManager.h asyncTaskManager.I \
buttonEvent.I buttonEvent.h \
buttonEventList.I buttonEventList.h \
genericAsyncTask.cxx \
pointerEvent.I pointerEvent.h \
pointerEventList.I pointerEventList.h \
pythonTask.h pythonTask.I \

View File

@ -466,3 +466,30 @@ upon_death(bool clean_exit) {
throw_event(event);
}
}
////////////////////////////////////////////////////////////////////
// Function: AsyncTask::release_lock
// Access: Protected
// Description: Releases the task lock. This is intended to be
// used within callback functions, for instance
// upon_birth() or upon_death(), as needed to release
// the lock for processing. Be sure to grab it again
// before returning.
////////////////////////////////////////////////////////////////////
void AsyncTask::
release_lock() {
_manager->_lock.release();
}
////////////////////////////////////////////////////////////////////
// Function: AsyncTask::grab_lock
// Access: Protected
// Description: Releases the task lock. This is intended to be
// used within callback functions, to grab the lock
// after a previous call to release_lock().
////////////////////////////////////////////////////////////////////
void AsyncTask::
grab_lock() {
_manager->_lock.lock();
}

View File

@ -117,6 +117,9 @@ protected:
virtual void upon_birth();
virtual void upon_death(bool clean_exit);
void release_lock();
void grab_lock();
protected:
AtomicAdjust::Integer _task_id;
string _chain_name;

View File

@ -156,7 +156,6 @@ private:
friend class AsyncTaskChain;
friend class AsyncTaskChain::AsyncTaskChainThread;
friend class AsyncTask;
friend class PythonTask;
};
INLINE ostream &operator << (ostream &out, const AsyncTaskManager &manager) {

View File

@ -20,6 +20,7 @@
#include "event.h"
#include "eventHandler.h"
#include "eventParameter.h"
#include "genericAsyncTask.h"
#include "pointerEventList.h"
#include "pythonTask.h"
@ -43,6 +44,7 @@ ConfigureFn(config_event) {
EventStoreString::init_type("EventStoreString");
EventStoreWstring::init_type("EventStoreWstring");
EventStoreTypedRefCount::init_type();
GenericAsyncTask::init_type();
PythonTask::init_type();
ButtonEventList::register_with_read_factory();

View File

@ -4,6 +4,7 @@
#include "asyncTaskManager.cxx"
#include "buttonEvent.cxx"
#include "buttonEventList.cxx"
#include "genericAsyncTask.cxx"
#include "pointerEvent.cxx"
#include "pointerEventList.cxx"
#include "pythonTask.cxx"

View File

@ -0,0 +1,103 @@
// Filename: genericAsyncTask.I
// Created by: drose (03Oct08)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::set_function
// Access: Published
// Description: Replaces the function that is called when the task
// runs.
////////////////////////////////////////////////////////////////////
INLINE void GenericAsyncTask::
set_function(GenericAsyncTask::TaskFunc *function) {
_function = function;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::get_function
// Access: Published
// Description: Returns the function that is called when the task
// runs.
////////////////////////////////////////////////////////////////////
INLINE GenericAsyncTask::TaskFunc *GenericAsyncTask::
get_function() const {
return _function;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::set_upon_birth
// Access: Published
// Description: Replaces the function that is called when the task
// begins. This is an optional function.
////////////////////////////////////////////////////////////////////
INLINE void GenericAsyncTask::
set_upon_birth(GenericAsyncTask::BirthFunc *upon_birth) {
_upon_birth = upon_birth;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::get_upon_birth
// Access: Published
// Description: Returns the function that is called when the task
// begins, or NULL if the function is not defined.
////////////////////////////////////////////////////////////////////
INLINE GenericAsyncTask::BirthFunc *GenericAsyncTask::
get_upon_birth() const {
return _upon_birth;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::set_upon_death
// Access: Published
// Description: Replaces the function that is called when the task
// ends. This is an optional function.
////////////////////////////////////////////////////////////////////
INLINE void GenericAsyncTask::
set_upon_death(GenericAsyncTask::DeathFunc *upon_death) {
_upon_death = upon_death;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::get_upon_death
// Access: Published
// Description: Returns the function that is called when the task
// ends, or NULL if the function is not defined.
////////////////////////////////////////////////////////////////////
INLINE GenericAsyncTask::DeathFunc *GenericAsyncTask::
get_upon_death() const {
return _upon_death;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::set_user_data
// Access: Published
// Description: Replaces the void pointer that is passed to the task
// function. This is any arbitrary pointer; the task
// object does no processing on it.
////////////////////////////////////////////////////////////////////
INLINE void GenericAsyncTask::
set_user_data(void *user_data) {
_user_data = user_data;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::get_user_data
// Access: Published
// Description: Returns the void pointer that is passed to the task
// function.
////////////////////////////////////////////////////////////////////
INLINE void *GenericAsyncTask::
get_user_data() const {
return _user_data;
}

View File

@ -0,0 +1,123 @@
// Filename: genericAsyncTask.cxx
// Created by: drose (03Oct08)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "genericAsyncTask.h"
#include "pnotify.h"
TypeHandle GenericAsyncTask::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
GenericAsyncTask::
GenericAsyncTask(const string &name) :
AsyncTask(name)
{
_function = NULL;
_upon_birth = NULL;
_upon_death = NULL;
_user_data = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
GenericAsyncTask::
GenericAsyncTask(const string &name, GenericAsyncTask::TaskFunc *function, void *user_data) :
AsyncTask(name),
_function(function),
_user_data(user_data)
{
_upon_birth = NULL;
_upon_death = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::is_runnable
// Access: Protected, Virtual
// Description: Override this function to return true if the task can
// be successfully executed, false if it cannot. Mainly
// intended as a sanity check when attempting to add the
// task to a task manager.
//
// This function is called with the lock held.
////////////////////////////////////////////////////////////////////
bool GenericAsyncTask::
is_runnable() {
return _function != NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::do_task
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus GenericAsyncTask::
do_task() {
nassertr(_function != NULL, DS_abort);
return (*_function)(this, _user_data);
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::upon_birth
// Access: Protected, Virtual
// Description: Override this function to do something useful when the
// task has been added to the active queue.
//
// This function is called with the lock held. You may
// temporarily release if it necessary, but be sure to
// return with it held.
////////////////////////////////////////////////////////////////////
void GenericAsyncTask::
upon_birth() {
AsyncTask::upon_birth();
if (_upon_birth != NULL) {
release_lock();
(*_upon_birth)(this, _user_data);
grab_lock();
}
}
////////////////////////////////////////////////////////////////////
// Function: GenericAsyncTask::upon_death
// Access: Protected, Virtual
// Description: Override this function to do something useful when the
// task has been removed from the active queue. The
// parameter clean_exit is true if the task has been
// removed because it exited normally (returning
// DS_done), or false if it was removed for some other
// reason (e.g. AsyncTaskManager::remove()).
//
// The normal behavior is to throw the done_event only
// if clean_exit is true.
//
// This function is called with the lock held. You may
// temporarily release if it necessary, but be sure to
// return with it held.
////////////////////////////////////////////////////////////////////
void GenericAsyncTask::
upon_death(bool clean_exit) {
AsyncTask::upon_death(clean_exit);
if (_upon_death != NULL) {
release_lock();
(*_upon_death)(this, clean_exit, _user_data);
grab_lock();
}
}

View File

@ -0,0 +1,83 @@
// Filename: genericAsyncTask.h
// Created by: drose (16Sep08)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef GENERICASYNCTASK_H
#define GENERICASYNCTASK_H
#include "pandabase.h"
#include "asyncTask.h"
////////////////////////////////////////////////////////////////////
// Class : GenericAsyncTask
// Description : Associates a generic C-style function pointer with an
// AsyncTask object. You can use this when you want to
// create an AsyncTask without having to subclass.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PIPELINE GenericAsyncTask : public AsyncTask {
public:
typedef DoneStatus TaskFunc(GenericAsyncTask *task, void *user_data);
typedef void BirthFunc(GenericAsyncTask *task, void *user_data);
typedef void DeathFunc(GenericAsyncTask *task, bool clean_exit, void *user_data);
GenericAsyncTask(const string &name = string());
GenericAsyncTask(const string &name, TaskFunc *function, void *user_data);
ALLOC_DELETED_CHAIN(GenericAsyncTask);
INLINE void set_function(TaskFunc *function);
INLINE TaskFunc *get_function() const;
INLINE void set_upon_birth(BirthFunc *function);
INLINE BirthFunc *get_upon_birth() const;
INLINE void set_upon_death(DeathFunc *function);
INLINE DeathFunc *get_upon_death() const;
INLINE void set_user_data(void *user_data);
INLINE void *get_user_data() const;
protected:
virtual bool is_runnable();
virtual DoneStatus do_task();
virtual void upon_birth();
virtual void upon_death(bool clean_exit);
private:
TaskFunc *_function;
BirthFunc *_upon_birth;
DeathFunc *_upon_death;
void *_user_data;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
AsyncTask::init_type();
register_type(_type_handle, "GenericAsyncTask",
AsyncTask::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "genericAsyncTask.I"
#endif

View File

@ -476,7 +476,7 @@ upon_birth() {
AsyncTask::upon_birth();
if (_owner != Py_None) {
_manager->_lock.release();
release_lock();
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Use PyGILState to protect this asynchronous call.
PyGILState_STATE gstate;
@ -488,7 +488,7 @@ upon_birth() {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyGILState_Release(gstate);
#endif
_manager->_lock.lock();
grab_lock();
}
}
@ -514,7 +514,7 @@ upon_death(bool clean_exit) {
AsyncTask::upon_death(clean_exit);
if (_owner != Py_None && _upon_death != Py_None) {
_manager->_lock.release();
release_lock();
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Use PyGILState to protect this asynchronous call.
PyGILState_STATE gstate;
@ -527,7 +527,7 @@ upon_death(bool clean_exit) {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyGILState_Release(gstate);
#endif
_manager->_lock.lock();
grab_lock();
}
}

View File

@ -23,7 +23,10 @@
INLINE GraphicsEngine *PandaFramework::
get_graphics_engine() {
if (_engine == (GraphicsEngine *)NULL) {
_engine = new GraphicsEngine;
_engine = GraphicsEngine::get_global_ptr();
PT(GenericAsyncTask) task = new GenericAsyncTask("igloop", task_igloop, this);
task->set_sort(50);
_task_mgr.add(task);
}
return _engine;
}
@ -52,6 +55,17 @@ get_event_handler() {
return _event_handler;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_task_mgr
// Access: Public
// Description: Returns the Task Manager object that manages tasks in
// the framework.
////////////////////////////////////////////////////////////////////
INLINE AsyncTaskManager &PandaFramework::
get_task_mgr() {
return _task_mgr;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_window_title
// Access: Public

View File

@ -37,7 +37,8 @@ LoaderOptions PandaFramework::_loader_options;
////////////////////////////////////////////////////////////////////
PandaFramework::
PandaFramework() :
_event_handler(*EventHandler::get_global_event_handler())
_event_handler(*EventHandler::get_global_event_handler()),
_task_mgr(*AsyncTaskManager::get_global_ptr())
{
_is_open = false;
_made_default_pipe = false;
@ -86,7 +87,18 @@ open_framework(int &argc, char **&argv) {
reset_frame_rate();
{
PT(GenericAsyncTask) task = new GenericAsyncTask("event", task_event, this);
_task_mgr.add(task);
}
_data_root = NodePath("data");
{
PT(GenericAsyncTask) task = new GenericAsyncTask("data_loop", task_data_loop, this);
task->set_sort(-50);
_task_mgr.add(task);
}
_highlight_wireframe = NodePath("wireframe");
_highlight_wireframe.set_render_mode_wireframe(1);
_highlight_wireframe.set_texture_off(1);
@ -98,12 +110,20 @@ open_framework(int &argc, char **&argv) {
// playing.
_recorder = new RecorderController;
_recorder->begin_playback(Filename::from_os_specific(playback_session));
PT(GenericAsyncTask) task = new GenericAsyncTask("play_frame", task_play_frame, this);
task->set_sort(55);
_task_mgr.add(task);
} else if (!record_session.empty()) {
// If the config file so indicates, create a recorder and start it
// recording.
_recorder = new RecorderController;
_recorder->begin_record(Filename::from_os_specific(record_session));
PT(GenericAsyncTask) task = new GenericAsyncTask("record_frame", task_record_frame, this);
task->set_sort(45);
_task_mgr.add(task);
}
_event_handler.add_hook("window-event", event_window_event, this);
@ -125,7 +145,7 @@ close_framework() {
close_all_windows();
// Also close down any other windows that might have been opened.
if (_engine != (GraphicsEngine *)NULL) {
delete _engine;
_engine->remove_all_windows();
_engine = NULL;
}
@ -766,30 +786,8 @@ enable_default_keys() {
bool PandaFramework::
do_frame(Thread *current_thread) {
nassertr(_is_open, false);
DataGraphTraverser dg_trav(current_thread);
dg_trav.traverse(_data_root.node());
throw_event("NewFrame");
_event_handler.process_events();
if (!_screenshot_text.is_empty()) {
double now = ClockObject::get_global_clock()->get_frame_time();
if (now >= _screenshot_clear_time) {
_screenshot_text.remove_node();
}
}
if (_recorder != (RecorderController *)NULL) {
_recorder->record_frame();
}
if (_engine != (GraphicsEngine *)NULL) {
_engine->render_frame();
}
if (_recorder != (RecorderController *)NULL) {
_recorder->play_frame();
}
_task_mgr.poll();
return !_exit_flag;
}
@ -1338,8 +1336,11 @@ event_f9(const Event *event, void *data) {
self->_screenshot_text.reparent_to(wf->get_aspect_2d());
cout << "Screenshot saved: " + output_text + "\n";
double now = ClockObject::get_global_clock()->get_frame_time();
self->_screenshot_clear_time = now + 3.0;
// Set a do-later to remove the text in 3 seconds.
self->_task_mgr.remove(self->_task_mgr.find_tasks("clear_text"));
PT(GenericAsyncTask) task = new GenericAsyncTask("clear_text", task_clear_text, self);
task->set_delay(3.0);
self->_task_mgr.add(task);
}
}
@ -1469,3 +1470,97 @@ event_window_event(const Event *event, void *data) {
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::task_data_loop
// Access: Public, Static
// Description: Called once per frame to process the data graph (which
// handles user input via the mouse and keyboard, etc.)
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PandaFramework::
task_data_loop(GenericAsyncTask *task, void *data) {
PandaFramework *self = (PandaFramework *)data;
DataGraphTraverser dg_trav;
dg_trav.traverse(self->_data_root.node());
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::task_event
// Access: Public, Static
// Description: Called once per frame to process the pending events.
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PandaFramework::
task_event(GenericAsyncTask *task, void *data) {
PandaFramework *self = (PandaFramework *)data;
throw_event("NewFrame");
self->_event_handler.process_events();
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::task_igloop
// Access: Public, Static
// Description: Called once per frame to render the scene.
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PandaFramework::
task_igloop(GenericAsyncTask *task, void *data) {
PandaFramework *self = (PandaFramework *)data;
if (self->_engine != (GraphicsEngine *)NULL) {
self->_engine->render_frame();
}
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::task_record_frame
// Access: Public, Static
// Description: Called once per frame to ask the recorder to record
// the user input data, if enabled.
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PandaFramework::
task_record_frame(GenericAsyncTask *task, void *data) {
PandaFramework *self = (PandaFramework *)data;
if (self->_recorder != (RecorderController *)NULL) {
self->_recorder->record_frame();
}
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::task_play_frame
// Access: Public, Static
// Description: Called once per frame to ask the recorder to play back
// the user input data, if enabled.
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PandaFramework::
task_play_frame(GenericAsyncTask *task, void *data) {
PandaFramework *self = (PandaFramework *)data;
if (self->_recorder != (RecorderController *)NULL) {
self->_recorder->play_frame();
}
return AsyncTask::DS_cont;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::task_clear_text
// Access: Public, Static
// Description: Called once to remove the screenshot text from onscreen.
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PandaFramework::
task_clear_text(GenericAsyncTask *task, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->clear_text();
return AsyncTask::DS_cont;
}

View File

@ -26,6 +26,8 @@
#include "graphicsWindow.h"
#include "recorderController.h"
#include "pointerTo.h"
#include "asyncTaskManager.h"
#include "genericAsyncTask.h"
#include "pvector.h"
@ -47,6 +49,7 @@ public:
INLINE GraphicsEngine *get_graphics_engine();
INLINE const NodePath &get_data_root() const;
INLINE EventHandler &get_event_handler();
INLINE AsyncTaskManager &get_task_mgr();
NodePath get_mouse(GraphicsWindow *window);
void remove_mouse(const GraphicsWindow *window);
@ -148,6 +151,15 @@ public:
static void event_window_event(const Event *, void *data);
static AsyncTask::DoneStatus task_data_loop(GenericAsyncTask *task, void *data);
static AsyncTask::DoneStatus task_event(GenericAsyncTask *task, void *data);
static AsyncTask::DoneStatus task_clear_screenshot_text(GenericAsyncTask *task, void *data);
static AsyncTask::DoneStatus task_igloop(GenericAsyncTask *task, void *data);
static AsyncTask::DoneStatus task_record_frame(GenericAsyncTask *task, void *data);
static AsyncTask::DoneStatus task_play_frame(GenericAsyncTask *task, void *data);
static AsyncTask::DoneStatus task_clear_text(GenericAsyncTask *task, void *data);
private:
bool _is_open;
bool _made_default_pipe;
@ -155,10 +167,11 @@ private:
string _window_title;
PT(GraphicsPipe) _default_pipe;
GraphicsEngine *_engine;
PT(GraphicsEngine) _engine;
NodePath _data_root;
EventHandler &_event_handler;
AsyncTaskManager &_task_mgr;
typedef pvector< PT(WindowFramework) > Windows;
Windows _windows;
@ -196,7 +209,6 @@ private:
NodePath _help_text;
NodePath _screenshot_text;
double _screenshot_clear_time;
PT(RecorderController) _recorder;

View File

@ -1302,7 +1302,7 @@ create_anim_controls() {
setup_shuttle_button("4", 2, st_play_button);
setup_shuttle_button(":", 3, st_forward_button);
_panda_framework->get_event_handler().add_hook("NewFrame", st_update_anim_controls, (void *)this);
_panda_framework->get_task_mgr().add(new GenericAsyncTask("controls", st_update_anim_controls, (void *)this));
}
////////////////////////////////////////////////////////////////////
@ -1442,12 +1442,13 @@ forward_button() {
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::st_update_anim_controls
// Access: Private, Static
// Description: The static event handler function.
// Description: The static task function.
////////////////////////////////////////////////////////////////////
void WindowFramework::
st_update_anim_controls(const Event *, void *data) {
AsyncTask::DoneStatus WindowFramework::
st_update_anim_controls(GenericAsyncTask *, void *data) {
WindowFramework *self = (WindowFramework *)data;
self->update_anim_controls();
return AsyncTask::DS_cont;
}

View File

@ -32,6 +32,7 @@
#include "pgSliderBar.h"
#include "textNode.h"
#include "eventHandler.h"
#include "genericAsyncTask.h"
class PandaFramework;
class AmbientLight;
@ -146,7 +147,7 @@ private:
void play_button();
void forward_button();
static void st_update_anim_controls(const Event *, void *data);
static AsyncTask::DoneStatus st_update_anim_controls(GenericAsyncTask *task, void *data);
static void st_back_button(const Event *, void *data);
static void st_pause_button(const Event *, void *data);