pgraph data graph

This commit is contained in:
David Rose 2002-03-12 18:42:55 +00:00
parent 5e3785cbf5
commit d3e2ffbda2
44 changed files with 3047 additions and 171 deletions

View File

@ -9,21 +9,25 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
analogNode.I analogNode.h buttonNode.I buttonNode.h \
clientAnalogDevice.I clientAnalogDevice.h clientBase.I \
clientBase.h clientButtonDevice.I clientButtonDevice.h \
clientDevice.I clientDevice.h clientDialDevice.I \
clientDialDevice.h clientTrackerDevice.I \
clientTrackerDevice.h config_device.h dialNode.I dialNode.h \
mouse.h trackerData.I trackerData.h trackerNode.I \
trackerNode.h virtualMouse.h
analogNode.I analogNode.h buttonNode.I buttonNode.h \
clientAnalogDevice.I clientAnalogDevice.h clientBase.I \
clientBase.h clientButtonDevice.I clientButtonDevice.h \
clientDevice.I clientDevice.h clientDialDevice.I \
clientDialDevice.h clientTrackerDevice.I \
clientTrackerDevice.h config_device.h dialNode.I dialNode.h \
mouse.h \
mouseAndKeyboard.h \
trackerData.I trackerData.h trackerNode.I \
trackerNode.h virtualMouse.h
#define INCLUDED_SOURCES \
analogNode.cxx buttonNode.cxx clientAnalogDevice.cxx \
clientBase.cxx clientButtonDevice.cxx clientDevice.cxx \
clientDialDevice.cxx clientTrackerDevice.cxx \
config_device.cxx dialNode.cxx mouse.cxx trackerData.cxx \
trackerNode.cxx virtualMouse.cxx
analogNode.cxx buttonNode.cxx clientAnalogDevice.cxx \
clientBase.cxx clientButtonDevice.cxx clientDevice.cxx \
clientDialDevice.cxx clientTrackerDevice.cxx \
config_device.cxx dialNode.cxx mouse.cxx \
mouseAndKeyboard.cxx \
trackerData.cxx \
trackerNode.cxx virtualMouse.cxx
#define INSTALL_HEADERS \
analogNode.I analogNode.h \
@ -35,6 +39,7 @@
clientDialDevice.I clientDialDevice.h \
clientTrackerDevice.I clientTrackerDevice.h \
config_device.h mouse.h \
mouseAndKeyboard.h \
dialNode.I dialNode.h \
trackerData.I trackerData.h \
trackerNode.I trackerNode.h virtualMouse.h

View File

@ -28,6 +28,7 @@
#include "clientTrackerDevice.h"
#include "dialNode.h"
#include "mouse.h"
#include "mouseAndKeyboard.h"
#include "trackerNode.h"
#include "virtualMouse.h"
@ -68,6 +69,7 @@ init_libdevice() {
ClientTrackerDevice::init_type();
DialNode::init_type();
MouseAndKeyboard::init_type();
qpMouseAndKeyboard::init_type();
TrackerNode::init_type();
VirtualMouse::init_type();
}

View File

@ -4,6 +4,7 @@
#include "buttonNode.cxx"
#include "dialNode.cxx"
#include "mouse.cxx"
#include "mouseAndKeyboard.cxx"
#include "trackerData.cxx"
#include "trackerNode.cxx"
#include "virtualMouse.cxx"

View File

@ -0,0 +1,91 @@
// Filename: mouseAndKeyboard.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "mouseAndKeyboard.h"
#include "mouseData.h"
#include "buttonHandle.h"
#include "buttonEvent.h"
#include "dataNodeTransmit.h"
TypeHandle qpMouseAndKeyboard::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: qpMouseAndKeyboard::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
qpMouseAndKeyboard::
qpMouseAndKeyboard(GraphicsWindow *window, int device, const string &name) :
qpDataNode(name),
_window(window),
_device(device)
{
_pixel_xy_output = define_output("PixelXY", EventStoreVec2::get_class_type());
_xy_output = define_output("XY", EventStoreVec2::get_class_type());
_button_events_output = define_output("ButtonEvents", ButtonEventList::get_class_type());
_pixel_xy = new EventStoreVec2(LPoint2f(0.0f, 0.0f));
_xy = new EventStoreVec2(LPoint2f(0.0f, 0.0f));
_button_events = new ButtonEventList;
}
////////////////////////////////////////////////////////////////////
// Function: qpMouseAndKeyboard::do_transmit_data
// Access: Protected, Virtual
// Description: The virtual implementation of transmit_data(). This
// function receives an array of input parameters and
// should generate an array of output parameters. The
// input parameters may be accessed with the index
// numbers returned by the define_input() calls that
// were made earlier (presumably in the constructor);
// likewise, the output parameters should be set with
// the index numbers returned by the define_output()
// calls.
////////////////////////////////////////////////////////////////////
void qpMouseAndKeyboard::
do_transmit_data(const DataNodeTransmit &, DataNodeTransmit &output) {
if (_window->has_button_event(_device)) {
// Fill up the button events.
_button_events->clear();
while (_window->has_button_event(_device)) {
ButtonEvent be = _window->get_button_event(_device);
_button_events->add_event(be);
}
output.set_data(_button_events_output, EventParameter(_button_events));
}
if (_window->has_pointer(_device)) {
const MouseData &mdata = _window->get_mouse_data(_device);
if (mdata._in_window) {
// Get mouse motion in pixels.
_pixel_xy->set_value(LPoint2f(mdata._xpos, mdata._ypos));
output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
int w = _window->get_width();
int h = _window->get_height();
// Normalize pixel motion to range [-1,1].
float xf = (float)(2 * mdata._xpos) / (float)w - 1.0f;
float yf = 1.0f - (float)(2 * mdata._ypos) / (float)h;
_xy->set_value(LPoint2f(xf, yf));
output.set_data(_xy_output, EventParameter(_xy));
}
}
}

View File

@ -0,0 +1,90 @@
// Filename: mouseAndKeyboard.h
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MOUSEANDKEYBOARD_H
#define MOUSEANDKEYBOARD_H
#include "pandabase.h"
#include "qpdataNode.h"
#include "buttonEventList.h"
#include "linmath_events.h"
////////////////////////////////////////////////////////////////////
// Class : MouseAndKeyboard
// Description : Reads the mouse and/or keyboard data sent from a
// GraphicsWindow, and transmits it down the data graph.
//
// The mouse and keyboard devices are bundled together
// into one device here, because they interrelate so
// much. A mouse might be constrained by the holding
// down of the shift key, for instance, or the clicking
// of the mouse button might be handled in much the same
// way as a keyboard key.
//
// Mouse data is sent down the data graph as an x,y
// position as well as the set of buttons currently
// being held down; keyboard data is sent down as a set
// of keypress events in an EventDataTransition. To
// throw these events to the system, you must attach an
// EventThrower to the MouseAndKeyboard object;
// otherwise, the events will be discarded.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpMouseAndKeyboard : public qpDataNode {
PUBLISHED:
qpMouseAndKeyboard(GraphicsWindow *window, int device,
const string &name);
protected:
// Inherited from DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
DataNodeTransmit &output);
private:
// outputs
int _pixel_xy_output;
int _xy_output;
int _button_events_output;
PT(EventStoreVec2) _pixel_xy;
PT(EventStoreVec2) _xy;
PT(ButtonEventList) _button_events;
PT(GraphicsWindow) _window;
int _device;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
qpDataNode::init_type();
register_type(_type_handle, "qpMouseAndKeyboard",
qpDataNode::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;
};
#endif

View File

@ -4,38 +4,52 @@
#begin lib_target
#define TARGET dgraph
#define LOCAL_LIBS \
pstatclient sgraph graph putil sgattrib mathutil
pstatclient sgraph graph putil sgattrib mathutil event
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
buttonEventDataTransition.I buttonEventDataTransition.h \
config_dgraph.h dataGraphTraversal.h dataGraphTraverser.I \
dataGraphTraverser.h dataNode.h dataRelation.I \
dataRelation.N dataRelation.h describe_data_verbose.h \
doubleDataTransition.I doubleDataTransition.h \
intDataTransition.I intDataTransition.h \
matrixDataTransition.I matrixDataTransition.h \
numericDataTransition.I numericDataTransition.h \
vec3DataTransition.I vec3DataTransition.h \
vec4DataTransition.I vec4DataTransition.h \
vectorDataTransition.I vectorDataTransition.h
buttonEventDataTransition.I buttonEventDataTransition.h \
config_dgraph.h dataGraphTraversal.h dataGraphTraverser.I \
dataGraphTraverser.h \
qpdataGraphTraverser.I qpdataGraphTraverser.h \
dataNode.h \
qpdataNode.I qpdataNode.h \
dataNodeTransmit.I dataNodeTransmit.h \
dataRelation.I \
dataRelation.N dataRelation.h describe_data_verbose.h \
doubleDataTransition.I doubleDataTransition.h \
intDataTransition.I intDataTransition.h \
matrixDataTransition.I matrixDataTransition.h \
numericDataTransition.I numericDataTransition.h \
vec3DataTransition.I vec3DataTransition.h \
vec4DataTransition.I vec4DataTransition.h \
vectorDataTransition.I vectorDataTransition.h
#define INCLUDED_SOURCES \
buttonEventDataTransition.cxx \
config_dgraph.cxx dataGraphTraversal.cxx \
dataGraphTraverser.cxx dataNode.cxx dataRelation.cxx \
describe_data_verbose.cxx \
doubleDataTransition.cxx \
intDataTransition.cxx \
matrixDataTransition.cxx \
vec3DataTransition.cxx \
vec4DataTransition.cxx
buttonEventDataTransition.cxx \
config_dgraph.cxx dataGraphTraversal.cxx \
dataGraphTraverser.cxx \
qpdataGraphTraverser.cxx \
dataNode.cxx \
qpdataNode.cxx \
dataNodeTransmit.cxx \
dataRelation.cxx \
describe_data_verbose.cxx \
doubleDataTransition.cxx \
intDataTransition.cxx \
matrixDataTransition.cxx \
vec3DataTransition.cxx \
vec4DataTransition.cxx
#define INSTALL_HEADERS \
buttonEventDataTransition.I buttonEventDataTransition.h \
dataGraphTraversal.h \
dataNode.h dataRelation.I dataRelation.h \
qpdataGraphTraverser.I qpdataGraphTraverser.h \
dataNode.h \
qpdataNode.I qpdataNode.h \
dataNodeTransmit.I dataNodeTransmit.h \
dataRelation.I dataRelation.h \
describe_data_verbose.h \
doubleDataTransition.I doubleDataTransition.h \
intDataTransition.I intDataTransition.h \
@ -46,8 +60,7 @@
vectorDataTransition.I vectorDataTransition.h
#define IGATESCAN \
dataNode.cxx dataNode.h dataRelation.cxx dataRelation.h \
dataGraphTraversal.cxx dataGraphTraversal.h
all
#end lib_target

View File

@ -18,6 +18,7 @@
#include "config_dgraph.h"
#include "dataNode.h"
#include "qpdataNode.h"
#include "dataRelation.h"
#include "intDataTransition.h"
#include "doubleDataTransition.h"
@ -32,6 +33,7 @@ NotifyCategoryDef(dgraph, "");
ConfigureFn(config_dgraph) {
DataNode::init_type();
qpDataNode::init_type();
DataRelation::init_type();
IntDataTransition::init_type();
DoubleDataTransition::init_type();

View File

@ -0,0 +1,111 @@
// Filename: dataNodeTransmit.I
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE DataNodeTransmit::
DataNodeTransmit() {
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE DataNodeTransmit::
DataNodeTransmit(const DataNodeTransmit &copy) :
_data(copy._data)
{
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void DataNodeTransmit::
operator = (const DataNodeTransmit &copy) {
_data = copy._data;
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE DataNodeTransmit::
~DataNodeTransmit() {
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::reserve
// Access: Public
// Description: Tells the DataNodeTransmit object how many wires it
// is expected to store data for.
////////////////////////////////////////////////////////////////////
INLINE void DataNodeTransmit::
reserve(int num_wires) {
_data.reserve(num_wires);
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::get_data
// Access: Public
// Description: Extracts the data for the indicated index, if it has
// been stored, or the empty parameter if it has not.
////////////////////////////////////////////////////////////////////
INLINE const EventParameter &DataNodeTransmit::
get_data(int index) const {
if (index >= 0 && index < (int)_data.size()) {
return _data[index];
}
static EventParameter empty_parameter;
return empty_parameter;
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::has_data
// Access: Public
// Description: Returns true if the indicated parameter has been
// stored, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool DataNodeTransmit::
has_data(int index) const {
if (index >= 0 && index < (int)_data.size()) {
return !_data[index].is_empty();
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::set_data
// Access: Public
// Description: Sets the data for the indicated parameter.
////////////////////////////////////////////////////////////////////
INLINE void DataNodeTransmit::
set_data(int index, const EventParameter &data) {
if (index >= (int)_data.size()) {
slot_data(index);
}
nassertv(index >= 0 && index < (int)_data.size());
_data[index] = data;
}

View File

@ -0,0 +1,33 @@
// Filename: dataNodeTransmit.cxx
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "dataNodeTransmit.h"
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::slot_data
// Access: Private
// Description: Ensures that the given index number exists in the
// data array.
////////////////////////////////////////////////////////////////////
void DataNodeTransmit::
slot_data(int index) {
nassertv(index < 1000);
while (index >= (int)_data.size()) {
_data.push_back(EventParameter());
}
}

View File

@ -0,0 +1,54 @@
// Filename: dataNodeTransmit.h
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef DATANODETRANSMIT_H
#define DATANODETRANSMIT_H
#include "pandabase.h"
#include "eventParameter.h"
////////////////////////////////////////////////////////////////////
// Class : DataNodeTransmit
// Description : Encapsulates the data generated from (or sent into)
// any particular DataNode. This is basically just an
// array of EventParameters, one for each registered
// input or output wire.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DataNodeTransmit {
public:
INLINE DataNodeTransmit();
INLINE DataNodeTransmit(const DataNodeTransmit &copy);
INLINE void operator = (const DataNodeTransmit &copy);
INLINE ~DataNodeTransmit();
INLINE void reserve(int num_wires);
INLINE const EventParameter &get_data(int index) const;
INLINE bool has_data(int index) const;
INLINE void set_data(int index, const EventParameter &data);
private:
void slot_data(int index);
typedef pvector<EventParameter> Data;
Data _data;
};
#include "dataNodeTransmit.I"
#endif

View File

@ -1,7 +1,10 @@
#include "dataGraphTraversal.cxx"
#include "dataGraphTraverser.cxx"
#include "qpdataGraphTraverser.cxx"
#include "dataNode.cxx"
#include "qpdataNode.cxx"
#include "dataNodeTransmit.cxx"
#include "dataRelation.cxx"
#include "describe_data_verbose.cxx"
#include "doubleDataTransition.cxx"

View File

@ -0,0 +1,29 @@
// Filename: qpdataGraphTraverser.I
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::CollectedData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpDataGraphTraverser::CollectedData::
CollectedData() :
_num_parents(0)
{
}

View File

@ -0,0 +1,167 @@
// Filename: qpdataGraphTraverser.cxx
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpdataGraphTraverser.h"
#include "qpdataNode.h"
#include "config_dgraph.h"
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::CollectedData::set_data
// Access: Public
// Description: Sets the data associated with the indicated parent of
// this CollectedData object's node.
////////////////////////////////////////////////////////////////////
void qpDataGraphTraverser::CollectedData::
set_data(int parent_index, const DataNodeTransmit &data) {
if ((int)_data.size() <= parent_index) {
_data.reserve(parent_index + 1);
while ((int)_data.size() <= parent_index) {
_data.push_back(DataNodeTransmit());
}
}
nassertv(parent_index >= 0 && parent_index < (int)_data.size());
_data[parent_index] = data;
}
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
qpDataGraphTraverser::
qpDataGraphTraverser() {
}
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
qpDataGraphTraverser::
~qpDataGraphTraverser() {
}
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::traverse
// Access: Public
// Description: Starts the traversal of the data graph at the
// indicated root node.
////////////////////////////////////////////////////////////////////
void qpDataGraphTraverser::
traverse(PandaNode *node) {
if (node->is_of_type(qpDataNode::get_class_type())) {
qpDataNode *data_node = DCAST(qpDataNode, node);
int num_parents = data_node->get_num_parents();
// We must start the traversal at the root of the graph.
nassertv(num_parents == 0);
r_transmit(data_node, (DataNodeTransmit *)NULL);
} else {
r_traverse_children(node, DataNodeTransmit());
}
// Now pick up any nodes that didn't get completely traversed.
// These must be nodes that have multiple parents, with at least one
// parent completely outside of the data graph.
while (!_multipass_data.empty()) {
MultipassData::iterator mi = _multipass_data.begin();
qpDataNode *data_node = (*mi).first;
const CollectedData &collected_data = (*mi).second;
dgraph_cat.warning()
<< *data_node << " improperly parented partly outside of data graph.\n";
r_transmit(data_node, &collected_data._data[0]);
_multipass_data.erase(mi);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::r_transmit
// Access: Private
// Description: Part of the recursive implementation of traverse().
// This transmits the given data into the indicated
// DataNode, and then sends the output data to each of
// the node's children.
////////////////////////////////////////////////////////////////////
void qpDataGraphTraverser::
r_transmit(qpDataNode *data_node, const DataNodeTransmit inputs[]) {
DataNodeTransmit output;
output.reserve(data_node->get_num_outputs());
data_node->transmit_data(inputs, output);
r_traverse_children(data_node, output);
}
////////////////////////////////////////////////////////////////////
// Function: qpDataGraphTraverser::r_traverse_children
// Access: Private
// Description: Part of the recursive implementation of traverse().
// This visits each of the children of the indicated
// node, passing in the given data.
////////////////////////////////////////////////////////////////////
void qpDataGraphTraverser::
r_traverse_children(PandaNode *node, const DataNodeTransmit &output) {
PandaNode::Children cr = node->get_children();
int num_children = cr.get_num_children();
for (int i = 0; i < num_children; i++) {
PandaNode *child_node = cr.get_child(i);
if (child_node->is_of_type(qpDataNode::get_class_type())) {
qpDataNode *data_node = DCAST(qpDataNode, child_node);
// If it's a DataNode-type child, we need to pass it the data.
// Maybe it has only one parent, and can accept the data
// immediately.
int num_parents = data_node->get_num_parents();
if (num_parents == 1) {
// The easy, common case: only one parent. We make our output
// into a one-element array of inputs by turning it into a
// pointer.
r_transmit(data_node, &output);
} else {
// A more difficult case: multiple parents. We must collect
// instances together, meaning we must hold onto this node
// until we have reached it through all paths.
CollectedData &collected_data = _multipass_data[data_node];
int parent_index = data_node->find_parent(node);
nassertv(parent_index != -1);
collected_data.set_data(parent_index, output);
collected_data._num_parents++;
nassertv(collected_data._num_parents <= num_parents);
if (collected_data._num_parents == num_parents) {
// Now we've got all the data; go into the child.
r_transmit(data_node, &collected_data._data[0]);
_multipass_data.erase(data_node);
}
}
} else {
// The child node is not a DataNode-type child. We continue the
// traversal, but data does not pass through this node, and
// instances are not collected together. (Although we appear to
// be passing the data through here, it doesn't do any good
// anyway, since the child nodes of this node will not know how
// to interpret the data from a non-DataNode parent.)
r_traverse_children(child_node, output);
}
}
}

View File

@ -0,0 +1,66 @@
// Filename: qpdataGraphTraverser.h
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpDATAGRAPHTRAVERSER_H
#define qpDATAGRAPHTRAVERSER_H
#include "pandabase.h"
#include "dataNodeTransmit.h"
#include "pvector.h"
#include "pmap.h"
class qpDataNode;
class PandaNode;
////////////////////////////////////////////////////////////////////
// Class : DataGraphTraverser
// Description : This object supervises the traversal of the data
// graph and the moving of data from one DataNode to its
// children. The data graph is used to manage data from
// input devices, etc. See the overview of the data
// graph in dataNode.h.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpDataGraphTraverser {
PUBLISHED:
qpDataGraphTraverser();
~qpDataGraphTraverser();
void traverse(PandaNode *node);
private:
void r_transmit(qpDataNode *data_node, const DataNodeTransmit inputs[]);
void r_traverse_children(PandaNode *node, const DataNodeTransmit &output);
typedef pvector<DataNodeTransmit> DataVector;
class CollectedData {
public:
INLINE CollectedData();
void set_data(int parent_index, const DataNodeTransmit &data);
int _num_parents;
DataVector _data;
};
typedef pmap<qpDataNode *, CollectedData> MultipassData;
MultipassData _multipass_data;
};
#include "qpdataGraphTraverser.I"
#endif

View File

@ -0,0 +1,67 @@
// Filename: qpdataNode.I
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpDataNode::
qpDataNode(const string &name) :
PandaNode(name)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::Copy Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpDataNode::
qpDataNode(const qpDataNode &copy) :
PandaNode(copy)
{
// Copying a DataNode doesn't copy its inputs or outputs.
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::get_num_inputs
// Access: Public
// Description: Returns the number of different inputs that have been
// defined for this node using define_input(). This
// indicates the size of the DataNodeTransmit object
// that should be passed to do_transmit_data().
////////////////////////////////////////////////////////////////////
INLINE int qpDataNode::
get_num_inputs() const {
return _input_wires.size();
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::get_num_outputs
// Access: Public
// Description: Returns the number of different outputs that have been
// defined for this node using define_output(). This
// indicates the size of the DataNodeTransmit object
// that should be passed to do_transmit_data().
////////////////////////////////////////////////////////////////////
INLINE int qpDataNode::
get_num_outputs() const {
return _output_wires.size();
}

View File

@ -0,0 +1,289 @@
// Filename: qpdataNode.cxx
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpdataNode.h"
#include "dataNodeTransmit.h"
#include "config_dgraph.h"
TypeHandle qpDataNode::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::make_copy
// Access: Public, Virtual
// Description: Returns a newly-allocated Node that is a shallow copy
// of this one. It will be a different Node pointer,
// but its internal data may or may not be shared with
// that of the original Node.
////////////////////////////////////////////////////////////////////
PandaNode *qpDataNode::
make_copy() const {
return new qpDataNode(*this);
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::transmit_data
// Access: Public
// Description: Collects the data from all of the parent nodes and
// puts it into one DataNodeTransmit object, for
// processing; calls do_transmit_data() to read all the
// inputs and put the result into the indicated output.
////////////////////////////////////////////////////////////////////
void qpDataNode::
transmit_data(const DataNodeTransmit inputs[],
DataNodeTransmit &output) {
DataNodeTransmit new_input;
new_input.reserve(get_num_inputs());
DataConnections::const_iterator ci;
for (ci = _data_connections.begin(); ci != _data_connections.end(); ++ci) {
const DataConnection &connect = (*ci);
const EventParameter &data =
inputs[connect._parent_index].get_data(connect._output_index);
new_input.set_data(connect._input_index, data);
}
do_transmit_data(new_input, output);
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::write_inputs
// Access: Published
// Description: Writes to the indicated ostream a list of all the
// inputs this DataNode might expect to receive.
////////////////////////////////////////////////////////////////////
void qpDataNode::
write_inputs(ostream &out) const {
Wires::const_iterator wi;
for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) {
const string &name = (*wi).first;
const WireDef &def = (*wi).second;
out << name << " " << def._data_type << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::write_outputs
// Access: Published
// Description: Writes to the indicated ostream a list of all the
// outputs this DataNode might generate.
////////////////////////////////////////////////////////////////////
void qpDataNode::
write_outputs(ostream &out) const {
Wires::const_iterator wi;
for (wi = _output_wires.begin(); wi != _output_wires.end(); ++wi) {
const string &name = (*wi).first;
const WireDef &def = (*wi).second;
out << name << " " << def._data_type << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::write_connections
// Access: Published
// Description: Writes to the indicated ostream a list of all the
// connections currently showing between this DataNode
// and its parent(s).
////////////////////////////////////////////////////////////////////
void qpDataNode::
write_connections(ostream &out) const {
DataConnections::const_iterator ci;
for (ci = _data_connections.begin(); ci != _data_connections.end(); ++ci) {
const DataConnection &connect = (*ci);
nassertv(connect._parent_index >= 0 && connect._parent_index < get_num_parents());
// Now we have to search exhaustively for the input with the
// matching index number.
Wires::const_iterator wi;
bool found = false;
for (wi = _input_wires.begin(); wi != _input_wires.end() && !found; ++wi) {
const string &name = (*wi).first;
const WireDef &def = (*wi).second;
if (def._index == connect._input_index) {
out << name << " " << def._data_type << " from "
<< *get_parent(connect._parent_index) << "\n";
found = true;
}
}
nassertv(found);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::define_input
// Access: Protected
// Description: Adds a new input wire with the given name and the
// indicated data type. The data type should be the
// TypeHandle for some type that derives from
// TypedReferenceCount, e.g. EventStoreInt,
// EventStoreDouble, or some fancier data type like
// Texture.
//
// If there is already an input wire defined with the
// indicated name, its type is changed.
//
// The return value is the index into the "input"
// parameter to do_transmit_data() that can be used to
// access the input data.
////////////////////////////////////////////////////////////////////
int qpDataNode::
define_input(const string &name, TypeHandle data_type) {
// We shouldn't already be connected.
nassertr(_data_connections.empty(), 0);
Wires::iterator wi;
wi = _input_wires.find(name);
if (wi != _input_wires.end()) {
// This wire already existed; modify it and return the original
// index.
WireDef &def = (*wi).second;
def._data_type = data_type;
return def._index;
}
// This wire did not already exist; add it.
WireDef &def = _input_wires[name];
def._data_type = data_type;
def._index = _input_wires.size() - 1;
return def._index;
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::define_output
// Access: Protected
// Description: Adds a new output wire with the given name and the
// indicated data type. The data type should be the
// TypeHandle for some type that derives from
// TypedReferenceCount, e.g. EventStoreInt,
// EventStoreDouble, or some fancier data type like
// Texture.
//
// If there is already an output wire defined with the
// indicated name, its type is changed.
//
// The return value is the index into the "output"
// parameter to do_transmit_data() where the output data
// should be stored.
////////////////////////////////////////////////////////////////////
int qpDataNode::
define_output(const string &name, TypeHandle data_type) {
// We shouldn't already be connected.
nassertr(_data_connections.empty(), 0);
Wires::iterator wi;
wi = _output_wires.find(name);
if (wi != _output_wires.end()) {
// This wire already existed; modify it and return the original
// index.
WireDef &def = (*wi).second;
def._data_type = data_type;
return def._index;
}
// This wire did not already exist; add it.
WireDef &def = _output_wires[name];
def._data_type = data_type;
def._index = _output_wires.size() - 1;
return def._index;
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::parents_changed
// Access: Protected, Virtual
// Description: Called after a scene graph update that either adds or
// remove parents from this node, this just provides a
// hook for derived PandaNode objects that need to
// update themselves based on the set of parents the
// node has.
////////////////////////////////////////////////////////////////////
void qpDataNode::
parents_changed() {
reconnect();
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::do_transmit_data
// Access: Protected, Virtual
// Description: The virtual implementation of transmit_data(). This
// function receives an array of input parameters and
// should generate an array of output parameters. The
// input parameters may be accessed with the index
// numbers returned by the define_input() calls that
// were made earlier (presumably in the constructor);
// likewise, the output parameters should be set with
// the index numbers returned by the define_output()
// calls.
////////////////////////////////////////////////////////////////////
void qpDataNode::
do_transmit_data(const DataNodeTransmit &, DataNodeTransmit &) {
}
////////////////////////////////////////////////////////////////////
// Function: qpDataNode::reconnect
// Access: Private
// Description: Establishes the input(s) that this DataNode has in
// common with its parents' output(s). Builds up the
// _data_connections list correspondingly.
////////////////////////////////////////////////////////////////////
void qpDataNode::
reconnect() {
int num_parents = get_num_parents();
_data_connections.clear();
// Look for each input among one of the parents.
Wires::const_iterator wi;
for (wi = _input_wires.begin(); wi != _input_wires.end(); ++wi) {
const string &name = (*wi).first;
const WireDef &input_def = (*wi).second;
int num_found = 0;
for (int i = 0; i < num_parents; i++) {
PandaNode *parent_node = get_parent(i);
if (parent_node->is_of_type(qpDataNode::get_class_type())) {
qpDataNode *data_node = DCAST(qpDataNode, parent_node);
Wires::const_iterator pi;
pi = data_node->_output_wires.find(name);
if (pi != data_node->_output_wires.end()) {
const WireDef &output_def = (*pi).second;
num_found++;
if (output_def._data_type != input_def._data_type) {
dgraph_cat.warning()
<< "Ignoring mismatched type for connection " << name
<< " between " << *data_node << " and " << *this << "\n";
} else if (num_found == 1) {
DataConnection dc;
dc._parent_index = i;
dc._output_index = output_def._index;
dc._input_index = input_def._index;
_data_connections.push_back(dc);
}
}
}
}
if (num_found > 1) {
dgraph_cat.warning()
<< "Multiple connections found for " << name << " into " << *this
<< "\n";
}
}
if (_data_connections.empty() && get_num_inputs() != 0 && num_parents != 0) {
dgraph_cat.warning()
<< "No data connected to " << *this << "\n";
}
}

View File

@ -0,0 +1,142 @@
// Filename: qpdataNode.h
// Created by: drose (11Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpDATANODE_H
#define qpDATANODE_H
////////////////////////////////////////////////////////////////////
//
// The Data Graph.
//
// The data graph is intended to hook up devices and their inputs
// and/or outputs in a clean interface. It uses the same graph
// relationship that is used to construct the scene graph, with the
// same sort of nodes and NodePaths.
//
// In a data graph, each node may potentially produce and/or consume
// data, and the arcs transmit data downward, from the root of the
// graph to its leaves. Thus, an input device such as a mouse might
// be added to the graph near the root, and a tformer-style object
// that interprets the mouse data as a trackball motion and outputs a
// matrix might be the immediate child of the mouse, followed by an
// object that accepts a matrix and sets it on some particular arc in
// the scene graph.
//
// Each different kind of DataNode defines its own set of input values
// and output values, identified by name. When a DataNode is attached
// to another DataNode, the inputs of the child are automatically
// connected up to the corresponding outputs of the parent, and an
// error message is issued if there are no matching connections.
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "pandaNode.h"
#include "pointerTo.h"
class DataNodeTransmit;
////////////////////////////////////////////////////////////////////
// Class : qpDataNode
// Description : The fundamental type of node for the data graph. The
// DataNode class is itself primarily intended as an
// abstract class; it defines no inputs and no outputs.
// Most kinds of data nodes will derive from this to
// specify the inputs and outputs in the constructor.
//
// DataNode does not attempt to cycle its data with a
// PipelineCycler. The data graph is intended to be
// used only within a single thread.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpDataNode : public PandaNode {
PUBLISHED:
INLINE qpDataNode(const string &name);
protected:
INLINE qpDataNode(const qpDataNode &copy);
public:
virtual PandaNode *make_copy() const;
void transmit_data(const DataNodeTransmit inputs[],
DataNodeTransmit &output);
INLINE int get_num_inputs() const;
INLINE int get_num_outputs() const;
PUBLISHED:
void write_inputs(ostream &out) const;
void write_outputs(ostream &out) const;
void write_connections(ostream &out) const;
//protected:
int define_input(const string &name, TypeHandle data_type);
int define_output(const string &name, TypeHandle data_type);
protected:
// Inherited from PandaNode
virtual void parents_changed();
// Local to DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
DataNodeTransmit &output);
private:
void reconnect();
class WireDef {
public:
TypeHandle _data_type;
int _index;
};
typedef pmap<string, WireDef> Wires;
Wires _input_wires;
Wires _output_wires;
class DataConnection {
public:
int _parent_index;
int _output_index;
int _input_index;
};
typedef pvector<DataConnection> DataConnections;
DataConnections _data_connections;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
PandaNode::init_type();
register_type(_type_handle, "qpDataNode",
PandaNode::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 "qpdataNode.I"
#endif

View File

@ -32,6 +32,5 @@ ConfigureFn(config_event) {
EventStoreInt::init_type("EventStoreInt");
EventStoreDouble::init_type("EventStoreDouble");
EventStoreString::init_type("EventStoreString");
// EventStoreVec3::init_type("EventStoreVec3");
}

View File

@ -21,6 +21,16 @@
template<class Type>
TypeHandle EventStoreValue<Type>::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: EventParameter::Default constructor
// Access: Public
// Description: Defines an EventParameter that stores nothing: the
// "empty" parameter.
////////////////////////////////////////////////////////////////////
INLINE EventParameter::
EventParameter() {
}
////////////////////////////////////////////////////////////////////
// Function: EventParameter::Pointer constructor
// Access: Public
@ -61,18 +71,6 @@ INLINE EventParameter::
EventParameter(const string &value) : _ptr(new EventStoreString(value)) { }
////////////////////////////////////////////////////////////////////
// Function: EventParameter::LVecBase3f constructor
// Access: Public
// Description: Defines an EventParameter that stores a
// three-component numeric value.
////////////////////////////////////////////////////////////////////
#if 0
INLINE EventParameter::
EventParameter(const LVecBase3f &value) : _ptr(new EventStoreVec3(value)) { }
#endif
////////////////////////////////////////////////////////////////////
// Function: EventParameter::Copy constructor
// Access: Public
@ -93,6 +91,17 @@ operator = (const EventParameter &other) {
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: EventParameter::is_empty
// Access: Public
// Description: Returns true if the EventParameter is the empty
// parameter, storing nothing, or false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool EventParameter::
is_empty() const {
return (_ptr == (TypedReferenceCount *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: EventParameter::is_int
// Access: Public
@ -101,7 +110,9 @@ operator = (const EventParameter &other) {
////////////////////////////////////////////////////////////////////
INLINE bool EventParameter::
is_int() const {
nassertr(_ptr != (TypedReferenceCount *)NULL, false);
if (is_empty()) {
return false;
}
return _ptr->is_of_type(EventStoreInt::get_class_type());
}
@ -129,7 +140,9 @@ get_int_value() const {
////////////////////////////////////////////////////////////////////
INLINE bool EventParameter::
is_double() const {
nassertr(_ptr != (TypedReferenceCount *)NULL, false);
if (is_empty()) {
return false;
}
return _ptr->is_of_type(EventStoreDouble::get_class_type());
}
@ -154,7 +167,9 @@ get_double_value() const {
////////////////////////////////////////////////////////////////////
INLINE bool EventParameter::
is_string() const {
nassertr(_ptr != (TypedReferenceCount *)NULL, false);
if (is_empty()) {
return false;
}
return _ptr->is_of_type(EventStoreString::get_class_type());
}
@ -171,34 +186,6 @@ get_string_value() const {
return ((const EventStoreString *)_ptr.p())->get_value();
}
////////////////////////////////////////////////////////////////////
// Function: EventParameter::is_vec3
// Access: Public
// Description: Returns true if the EventParameter stores a
// three-component vector value, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool EventParameter::
is_vec3() const {
nassertr(_ptr != (TypedReferenceCount *)NULL, false);
return false;
// return _ptr->is_of_type(EventStoreVec3::get_class_type());
}
////////////////////////////////////////////////////////////////////
// Function: EventParameter::get_vec3_value
// Access: Public
// Description: Retrieves the value stored in the EventParameter. It
// is only valid to call this if is_vec3() has already
// returned true.
////////////////////////////////////////////////////////////////////
#if 0
INLINE LVecBase3f EventParameter::
get_vec3_value() const {
nassertr(is_vec3(), LVecBase3f(0.0, 0.0, 0.0));
return ((const EventStoreVec3 *)_ptr.p())->get_value();
}
#endif
////////////////////////////////////////////////////////////////////
// Function: EventParameter::get_ptr
// Access: Public
@ -234,7 +221,7 @@ set_value(const Type &value) {
// Description: Retrieves the value stored in the parameter.
////////////////////////////////////////////////////////////////////
template<class Type>
INLINE Type EventStoreValue<Type>::
INLINE const Type &EventStoreValue<Type>::
get_value() const {
return _value;
}

View File

@ -19,14 +19,12 @@
#ifndef EVENTPARAMETER_H
#define EVENTPARAMETER_H
#include <pandabase.h>
#include "pandabase.h"
#include <typedef.h>
#include <typedObject.h>
#include <typedReferenceCount.h>
#include <pointerTo.h>
//#include <luse.h>
#include <string>
#include "typedef.h"
#include "typedObject.h"
#include "typedReferenceCount.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : EventParameter
@ -40,11 +38,11 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS EventParameter {
PUBLISHED:
INLINE EventParameter();
INLINE EventParameter(const TypedReferenceCount *ptr);
INLINE EventParameter(int value);
INLINE EventParameter(double value);
INLINE EventParameter(const string &value);
// INLINE EventParameter(const LVecBase3f &value);
INLINE EventParameter(const EventParameter &copy);
INLINE EventParameter &operator = (const EventParameter &copy);
@ -54,14 +52,13 @@ PUBLISHED:
// retrieve the corresponding value. Of course, it is possible that
// the EventParameter is some user-defined type, and is none of
// these.
INLINE bool is_empty() const;
INLINE bool is_int() const;
INLINE int get_int_value() const;
INLINE bool is_double() const;
INLINE double get_double_value() const;
INLINE bool is_string() const;
INLINE string get_string_value() const;
INLINE bool is_vec3() const;
// INLINE LVecBase3f get_vec3_value() const;
INLINE const TypedReferenceCount *get_ptr() const;
@ -85,7 +82,7 @@ public:
EventStoreValue(const Type &value) : _value(value) { }
INLINE void set_value(const Type &value);
INLINE Type get_value() const;
INLINE const Type &get_value() const;
Type _value;
@ -93,7 +90,7 @@ public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type(const string &type_name) {
static void init_type(const string &type_name = "EventStoreValue") {
TypedReferenceCount::init_type();
register_type(_type_handle, type_name,
TypedReferenceCount::get_class_type());
@ -114,12 +111,10 @@ private:
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<int>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<double>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<std::string>);
//EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<LVecBase3f>);
typedef EventStoreValue<int> EventStoreInt;
typedef EventStoreValue<double> EventStoreDouble;
typedef EventStoreValue<string> EventStoreString;
//typedef EventStoreValue<LVecBase3f> EventStoreVec3;
#include "eventParameter.I"

View File

@ -4,28 +4,32 @@
#begin lib_target
#define TARGET mathutil
#define LOCAL_LIBS \
linmath putil express
linmath putil event express
#define USE_FFTW yes
#define UNIX_SYS_LIBS m
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
boundingLine.h boundingSphere.I boundingSphere.h \
boundingVolume.I boundingVolume.h config_mathutil.h \
fftCompressor.h finiteBoundingVolume.h frustum.h \
frustum_src.I frustum_src.h geometricBoundingVolume.I \
geometricBoundingVolume.h look_at.h look_at_src.I \
look_at_src.cxx look_at_src.h omniBoundingVolume.I \
omniBoundingVolume.h plane.h plane_src.I plane_src.cxx \
plane_src.h rotate_to.h rotate_to_src.cxx
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
boundingLine.h boundingSphere.I boundingSphere.h \
boundingVolume.I boundingVolume.h config_mathutil.h \
fftCompressor.h finiteBoundingVolume.h frustum.h \
frustum_src.I frustum_src.h geometricBoundingVolume.I \
geometricBoundingVolume.h \
linmath_events.h \
look_at.h look_at_src.I \
look_at_src.cxx look_at_src.h omniBoundingVolume.I \
omniBoundingVolume.h plane.h plane_src.I plane_src.cxx \
plane_src.h rotate_to.h rotate_to_src.cxx
#define INCLUDED_SOURCES \
boundingHexahedron.cxx boundingLine.cxx boundingSphere.cxx \
boundingVolume.cxx config_mathutil.cxx fftCompressor.cxx \
finiteBoundingVolume.cxx geometricBoundingVolume.cxx \
look_at.cxx omniBoundingVolume.cxx plane.cxx rotate_to.cxx
boundingHexahedron.cxx boundingLine.cxx boundingSphere.cxx \
boundingVolume.cxx config_mathutil.cxx fftCompressor.cxx \
finiteBoundingVolume.cxx geometricBoundingVolume.cxx \
look_at.cxx \
linmath_events.cxx \
omniBoundingVolume.cxx plane.cxx rotate_to.cxx
#define INSTALL_HEADERS \
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
@ -33,7 +37,9 @@
boundingVolume.h config_mathutil.h fftCompressor.h \
finiteBoundingVolume.h frustum.h frustum_src.I frustum_src.h \
geometricBoundingVolume.I geometricBoundingVolume.h look_at.h \
look_at_src.I look_at_src.h mathHelpers.I mathHelpers.h \
look_at_src.I look_at_src.h \
linmath_events.h \
mathHelpers.I mathHelpers.h \
omniBoundingVolume.I omniBoundingVolume.h plane.h plane_src.I \
plane_src.h rotate_to.h

View File

@ -24,7 +24,8 @@
#include "boundingSphere.h"
#include "boundingHexahedron.h"
#include "boundingLine.h"
#include <dconfig.h>
#include "linmath_events.h"
#include "dconfig.h"
Configure(config_mathutil);
NotifyCategoryDef(mathutil, "");
@ -41,5 +42,8 @@ ConfigureFn(config_mathutil) {
GeometricBoundingVolume::init_type();
OmniBoundingVolume::init_type();
BoundingLine::init_type();
EventStoreVec2::init_type("EventStoreVec2");
EventStoreVec3::init_type("EventStoreVec3");
EventStoreMat4::init_type("EventStoreMat4");
}

View File

@ -0,0 +1,24 @@
// Filename: linmath_events.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "linmath_events.h"
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma implementation
#endif

View File

@ -0,0 +1,53 @@
// Filename: linmath_events.h
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef LINMATH_EVENTS_H
#define LINMATH_EVENTS_H
#include "pandabase.h"
#include "eventParameter.h"
#include "luse.h"
////////////////////////////////////////////////////////////////////
//
// This file defines a few more EventStore classes for storing linmath
// objects in an EventParameter. We can't define this with the other
// EventStore classes, because linmath hasn't been defined yet at that
// point.
//
// See eventParameter.h.
//
////////////////////////////////////////////////////////////////////
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<LVecBase2f>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<LVecBase3f>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<LMatrix4f>);
typedef EventStoreValue<LVecBase2f> EventStoreVec2;
typedef EventStoreValue<LVecBase3f> EventStoreVec3;
typedef EventStoreValue<LMatrix4f> EventStoreMat4;
// Tell GCC that we'll take care of the instantiation explicitly here.
#ifdef __GNUC__
#pragma interface
#endif
#endif

View File

@ -3,5 +3,6 @@
#include "plane.cxx"
#include "rotate_to.cxx"
#include "look_at.cxx"
#include "linmath_events.cxx"
#include "fftCompressor.cxx"

View File

@ -510,6 +510,10 @@ add_child(PandaNode *child_node, int sort) {
// Mark the bounding volumes stale.
force_bound_stale();
// Call callback hooks.
children_changed();
child_node->parents_changed();
}
////////////////////////////////////////////////////////////////////
@ -519,11 +523,12 @@ add_child(PandaNode *child_node, int sort) {
////////////////////////////////////////////////////////////////////
void PandaNode::
remove_child(int n) {
PT(PandaNode) child_node;
{
CDWriter cdata(_cycler);
nassertv(n >= 0 && n < (int)cdata->_down.size());
PT(PandaNode) child_node = cdata->_down[n].get_child();
child_node = cdata->_down[n].get_child();
CDWriter cdata_child(child_node->_cycler);
cdata->_down.erase(cdata->_down.begin() + n);
@ -562,6 +567,10 @@ remove_child(int n) {
// Mark the bounding volumes stale.
force_bound_stale();
// Call callback hooks.
children_changed();
child_node->parents_changed();
}
////////////////////////////////////////////////////////////////////
@ -574,9 +583,9 @@ remove_child(int n) {
bool PandaNode::
remove_child(PandaNode *child_node) {
// Ensure the child_node is not deleted while we do this.
{
PT(PandaNode) keep_child = child_node;
PT(PandaNode) keep_child = child_node;
{
CDWriter cdata(_cycler);
CDWriter cdata_child(child_node->_cycler);
@ -626,6 +635,10 @@ remove_child(PandaNode *child_node) {
// Mark the bounding volumes stale.
force_bound_stale();
// Call callback hooks.
children_changed();
child_node->parents_changed();
return true;
}
@ -641,36 +654,40 @@ remove_all_children() {
Down::iterator ci;
for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
PT(PandaNode) child_node = (*ci).get_child();
CDWriter cdata_child(child_node->_cycler);
cdata_child->_up.erase(UpConnection(this));
{
CDWriter cdata_child(child_node->_cycler);
cdata_child->_up.erase(UpConnection(this));
// Now sever any qpNodePathComponents on the child that reference
// this node. If we have multiple of these, we have to collapse
// them together (see above).
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
// Now sever any qpNodePathComponents on the child that
// reference this node. If we have multiple of these, we have
// to collapse them together (see above).
qpNodePathComponent *collapsed = (qpNodePathComponent *)NULL;
Chains::iterator ci;
ci = cdata_child->_chains.begin();
while (ci != cdata_child->_chains.end()) {
Chains::iterator cnext = ci;
++cnext;
if (!(*ci)->is_top_node() && (*ci)->get_next()->get_node() == this) {
if (collapsed == (qpNodePathComponent *)NULL) {
(*ci)->set_top_node();
collapsed = (*ci);
} else {
(*ci)->collapse_with(collapsed);
cdata_child->_chains.erase(ci);
}
}
ci = cnext;
}
ci = cnext;
child_node->fix_chain_lengths(cdata_child);
}
child_node->fix_chain_lengths(cdata_child);
child_node->parents_changed();
}
}
// Mark the bounding volumes stale.
force_bound_stale();
children_changed();
}
////////////////////////////////////////////////////////////////////
@ -813,6 +830,32 @@ recompute_internal_bound() {
return _internal_bound.recompute_bound();
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::parents_changed
// Access: Protected, Virtual
// Description: Called after a scene graph update that either adds or
// remove parents from this node, this just provides a
// hook for derived PandaNode objects that need to
// update themselves based on the set of parents the
// node has.
////////////////////////////////////////////////////////////////////
void PandaNode::
parents_changed() {
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::children_changed
// Access: Protected, Virtual
// Description: Called after a scene graph update that either adds or
// remove children from this node, this just provides a
// hook for derived PandaNode objects that need to
// update themselves based on the set of children the
// node has.
////////////////////////////////////////////////////////////////////
void PandaNode::
children_changed() {
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::attach
// Access: Private, Static
@ -900,6 +943,10 @@ detach(qpNodePathComponent *child) {
// Mark the bounding volumes stale.
parent_node->force_bound_stale();
// Call callback hooks.
parent_node->children_changed();
child_node->parents_changed();
}
////////////////////////////////////////////////////////////////////
@ -936,6 +983,10 @@ reparent(qpNodePathComponent *new_parent, qpNodePathComponent *child, int sort)
// Mark the bounding volumes stale.
parent_node->force_bound_stale();
// Call callback hooks.
parent_node->children_changed();
child_node->parents_changed();
}
////////////////////////////////////////////////////////////////////

View File

@ -144,6 +144,8 @@ protected:
// Local to PandaNode
virtual BoundingVolume *recompute_internal_bound();
INLINE void changed_internal_bound();
virtual void parents_changed();
virtual void children_changed();
// This is the bounding volume around the contents of the node
// itself (without including all of the node's children).

View File

@ -10,7 +10,9 @@
#define SOURCES \
bam.h bamReader.I bamReader.N bamReader.h bamReaderParam.I \
bamReaderParam.h bamWriter.I bamWriter.h bitMask.I \
bitMask.h buttonEvent.I buttonEvent.h buttonHandle.I \
bitMask.h buttonEvent.I buttonEvent.h \
buttonEventList.I buttonEventList.h \
buttonHandle.I \
buttonHandle.h buttonRegistry.I buttonRegistry.h \
collideMask.h \
compareTo.I compareTo.h \
@ -50,7 +52,9 @@
#define INCLUDED_SOURCES \
bamReader.cxx bamReaderParam.cxx bamWriter.cxx bitMask.cxx \
buttonEvent.cxx buttonHandle.cxx buttonRegistry.cxx \
buttonEvent.cxx \
buttonEventList.cxx \
buttonHandle.cxx buttonRegistry.cxx \
config_util.cxx configurable.cxx \
cycleData.cxx \
cycleDataReader.cxx \
@ -78,7 +82,9 @@
#define INSTALL_HEADERS \
bam.h bamReader.I bamReader.h bamReaderParam.I bamReaderParam.h \
bamWriter.I bamWriter.h bitMask.I bitMask.h buttonEvent.I \
buttonEvent.h buttonHandle.I buttonHandle.h buttonRegistry.I \
buttonEvent.h \
buttonEventList.I buttonEventList.h \
buttonHandle.I buttonHandle.h buttonRegistry.I \
buttonRegistry.h collideMask.h \
compareTo.I compareTo.h \
config_util.h configurable.h factory.I factory.h \

View File

@ -0,0 +1,74 @@
// Filename: buttonEventList.I
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ButtonEventList::
ButtonEventList() {
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::add_event
// Access: Public
// Description: Adds a new event to the end of the list.
////////////////////////////////////////////////////////////////////
INLINE void ButtonEventList::
add_event(ButtonEvent event) {
_events.push_back(event);
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::get_num_events
// Access: Public
// Description: Returns the number of events in the list.
////////////////////////////////////////////////////////////////////
INLINE int ButtonEventList::
get_num_events() const {
return _events.size();
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::get_event
// Access: Public
// Description: Returns the nth event in the list. This does not
// remove the event from the list; the only way to
// remove events is to empty the whole list with
// clear().
////////////////////////////////////////////////////////////////////
INLINE const ButtonEvent &ButtonEventList::
get_event(int n) const {
#ifndef NDEBUG
static ButtonEvent empty_event;
nassertr(n >= 0 && n < (int)_events.size(), empty_event);
#endif // NDEBUG
return _events[n];
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::clear
// Access: Public
// Description: Empties all the events from the list.
////////////////////////////////////////////////////////////////////
INLINE void ButtonEventList::
clear() {
_events.clear();
}

View File

@ -0,0 +1,62 @@
// Filename: buttonEventList.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "buttonEventList.h"
#include "modifierButtons.h"
#include "indent.h"
TypeHandle ButtonEventList::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::update_mods
// Access: Public
// Description: Updates the indicated ModifierButtons object with all
// of the button up/down transitions indicated in the
// list.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
update_mods(ModifierButtons &mods) const {
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
mods.add_event(*ei);
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEventList::
output(ostream &out) const {
out << get_type() << " (" << get_num_events() << " events)";
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEventList::
write(ostream &out, int indent_level) const {
indent(out, indent_level) << *this << ":\n";
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
indent(out, indent_level + 2) << (*ei) << "\n";
}
}

View File

@ -0,0 +1,82 @@
// Filename: buttonEventList.h
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef BUTTONEVENTLIST_H
#define BUTTONEVENTLIST_H
#include "pandabase.h"
#include "buttonEvent.h"
#include "typedReferenceCount.h"
#include "pvector.h"
class ModifierButtons;
////////////////////////////////////////////////////////////////////
// Class : ButtonEventList
// Description : Records a set of button events that happened
// recently. This class is usually used only in the
// data graph, to transmit the recent button presses,
// but it may be used anywhere a list of ButtonEvents
// is desired.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ButtonEventList : public TypedReferenceCount {
public:
INLINE ButtonEventList();
INLINE void add_event(ButtonEvent event);
INLINE int get_num_events() const;
INLINE const ButtonEvent &get_event(int n) const;
INLINE void clear();
void update_mods(ModifierButtons &mods) const;
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;
private:
typedef pvector<ButtonEvent> Events;
Events _events;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
register_type(_type_handle, "ButtonEventList",
TypedReferenceCount::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;
};
INLINE ostream &operator << (ostream &out, const ButtonEventList &list) {
list.output(out);
return out;
}
#include "buttonEventList.I"
#endif

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "config_util.h"
#include "buttonEventList.h"
#include "clockObject.h"
#include "typedObject.h"
#include "configurable.h"
@ -43,6 +44,7 @@ NotifyCategoryDef(bam, util_cat);
ConfigureFn(config_util) {
// ClockObject::init_ptr();
ButtonEventList::init_type();
TypedObject::init_type();
Configurable::init_type();
Namable::init_type();

View File

@ -3,6 +3,7 @@
#include "bamWriter.cxx"
#include "bitMask.cxx"
#include "buttonEvent.cxx"
#include "buttonEventList.cxx"
#include "buttonHandle.cxx"
#include "buttonRegistry.cxx"
#include "config_util.cxx"

View File

@ -39,21 +39,16 @@
#include "notify.h"
#include "qpnodePath.h"
#include "cullBinManager.h"
// These are in support of legacy data graph operations.
#include "namedNode.h"
#include "mouse.h"
#include "mouseWatcher.h"
#include "trackball.h"
#include "transform2sg.h"
#include "dataRelation.h"
#include "dataGraphTraversal.h"
#include "buttonThrower.h"
#include "mouseAndKeyboard.h"
#include "qpbuttonThrower.h"
#include "qptrackball.h"
#include "qptransform2sg.h"
#include "modifierButtons.h"
#include "keyboardButton.h"
#include "event.h"
#include "eventQueue.h"
#include "eventHandler.h"
#include "qpdataGraphTraverser.h"
// Use dconfig to read a few Configrc variables.
Configure(config_pview);
@ -233,32 +228,32 @@ get_models(PandaNode *parent, int argc, char *argv[]) {
}
}
NamedNode *
setup_mouse(NamedNode *data_root, GraphicsWindow *window) {
MouseAndKeyboard *mouse = new MouseAndKeyboard(window, 0);
new DataRelation(data_root, mouse);
PandaNode *
setup_mouse(PandaNode *data_root, GraphicsWindow *window) {
qpMouseAndKeyboard *mouse = new qpMouseAndKeyboard(window, 0, "mouse");
data_root->add_child(mouse);
// Create a ButtonThrower to throw events from the keyboard.
PT(ButtonThrower) bt = new ButtonThrower("kb-events");
PT(qpButtonThrower) bt = new qpButtonThrower("kb-events");
ModifierButtons mods;
mods.add_button(KeyboardButton::shift());
mods.add_button(KeyboardButton::control());
mods.add_button(KeyboardButton::alt());
bt->set_modifier_buttons(mods);
new DataRelation(mouse, bt);
mouse->add_child(bt);
return mouse;
}
void
setup_trackball(NamedNode *mouse, qpCamera *camera) {
PT(Trackball) trackball = new Trackball("trackball");
setup_trackball(PandaNode *mouse, qpCamera *camera) {
PT(qpTrackball) trackball = new qpTrackball("trackball");
trackball->set_pos(LVector3f::forward() * 50.0);
new DataRelation(mouse, trackball);
mouse->add_child(trackball);
PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
PT(qpTransform2SG) tball2cam = new qpTransform2SG("tball2cam");
tball2cam->set_node(camera);
new DataRelation(trackball, tball2cam);
trackball->add_child(tball2cam);
}
void
@ -365,11 +360,11 @@ main(int argc, char *argv[]) {
// sorting, above, in event_s().
CullBinManager::get_global_ptr()->add_bin("unsorted", CullBinManager::BT_unsorted, 0);
// Set up a data graph for tracking user input. For now, this uses
// the old-style graph interface.
PT(NamedNode) data_root = new NamedNode("data_root");
NamedNode *mouse = setup_mouse(data_root, window);
// Set up a data graph for tracking user input.
PT(PandaNode) data_root = new PandaNode("data_root");
PandaNode *mouse = setup_mouse(data_root, window);
setup_trackball(mouse, camera);
qpDataGraphTraverser dg_trav;
// Use an event handler to manage keyboard events.
EventHandler event_handler(EventQueue::get_global_event_queue());
@ -401,7 +396,7 @@ main(int argc, char *argv[]) {
// This is our main update loop. Loop here until someone
// (e.g. event_esc) sets run_flag to false.
while (run_flag) {
traverse_data_graph(data_root);
dg_trav.traverse(data_root);
event_handler.process_events();
engine->render_frame();
}

View File

@ -10,26 +10,41 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
buttonThrower.h config_tform.h dataValve.I dataValve.h \
buttonThrower.h \
qpbuttonThrower.h \
config_tform.h dataValve.I dataValve.h \
driveInterface.I driveInterface.h mouseWatcher.I \
mouseWatcher.h mouseWatcherGroup.h \
mouseWatcherParameter.I mouseWatcherParameter.h \
mouseWatcherRegion.I mouseWatcherRegion.h \
planarSlider.h trackball.h transform2sg.h
planarSlider.h trackball.h \
qptrackball.h \
transform2sg.h \
qptransform2sg.h
#define INCLUDED_SOURCES \
buttonThrower.cxx config_tform.cxx dataValve.cxx \
buttonThrower.cxx \
qpbuttonThrower.cxx \
config_tform.cxx dataValve.cxx \
driveInterface.cxx mouseWatcher.cxx mouseWatcherGroup.cxx \
mouseWatcherParameter.cxx mouseWatcherRegion.cxx \
planarSlider.cxx trackball.cxx transform2sg.cxx
planarSlider.cxx trackball.cxx \
qptrackball.cxx \
transform2sg.cxx \
qptransform2sg.cxx
#define INSTALL_HEADERS \
buttonThrower.h dataValve.I dataValve.h \
buttonThrower.h \
qpbuttonThrower.h \
dataValve.I dataValve.h \
driveInterface.I driveInterface.h mouseWatcher.I mouseWatcher.h \
mouseWatcherGroup.h \
mouseWatcherParameter.I mouseWatcherParameter.h \
mouseWatcherRegion.I mouseWatcherRegion.h \
planarSlider.h trackball.h transform2sg.h
planarSlider.h trackball.h \
qptrackball.h \
transform2sg.h \
qptransform2sg.h
#define IGATESCAN all

View File

@ -21,12 +21,15 @@
#include "dataValve.h"
#include "driveInterface.h"
#include "buttonThrower.h"
#include "qpbuttonThrower.h"
#include "mouseWatcher.h"
#include "mouseWatcherGroup.h"
#include "mouseWatcherRegion.h"
#include "planarSlider.h"
#include "trackball.h"
#include "qptrackball.h"
#include "transform2sg.h"
#include "qptransform2sg.h"
#include <dconfig.h>
@ -49,10 +52,13 @@ ConfigureFn(config_tform) {
DataValve::init_type();
DriveInterface::init_type();
ButtonThrower::init_type();
qpButtonThrower::init_type();
MouseWatcher::init_type();
MouseWatcherGroup::init_type();
MouseWatcherRegion::init_type();
PlanarSlider::init_type();
Trackball::init_type();
qpTrackball::init_type();
Transform2SG::init_type();
qpTransform2SG::init_type();
}

View File

@ -0,0 +1,399 @@
// Filename: qpbuttonThrower.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpbuttonThrower.h"
#include "buttonEvent.h"
#include "buttonEventList.h"
#include "dataNodeTransmit.h"
#include "throw_event.h"
#include "indent.h"
TypeHandle qpButtonThrower::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
qpButtonThrower::
qpButtonThrower(const string &name) :
qpDataNode(name)
{
_button_events_input = define_input("ButtonEvents", ButtonEventList::get_class_type());
_button_events_output = define_output("ButtonEvents", ButtonEventList::get_class_type());
_button_events = new ButtonEventList;
_throw_buttons_active = false;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
qpButtonThrower::
~qpButtonThrower() {
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::set_prefix
// Access: Published
// Description: Sets the prefix which is prepended to all event names
// thrown by this object.
////////////////////////////////////////////////////////////////////
void qpButtonThrower::
set_prefix(const string &prefix) {
_prefix = prefix;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::has_prefix
// Access: Published
// Description: Returns true if the qpButtonThrower has a prefix set,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool qpButtonThrower::
has_prefix() const {
return !_prefix.empty();
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::get_prefix
// Access: Published
// Description: Returns the prefix that has been set on this
// qpButtonThrower. See set_prefix().
////////////////////////////////////////////////////////////////////
string qpButtonThrower::
get_prefix() const {
return _prefix;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::get_modifier_buttons
// Access: Published
// Description: Returns the set of ModifierButtons that the
// qpButtonThrower will consider important enough to
// prepend the event name with. Normally, this set will
// be empty, and the qpButtonThrower will therefore ignore
// all ModifierButtons attached to the key events, but
// if one or more buttons have been added to this set,
// and those modifier buttons are set on the button
// event, then the event name will be prepended with the
// names of the modifier buttons.
////////////////////////////////////////////////////////////////////
const ModifierButtons &qpButtonThrower::
get_modifier_buttons() const {
return _mods;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::set_modifier_buttons
// Access: Published
// Description: Changes the set of ModifierButtons that the
// qpButtonThrower will consider important enough to
// prepend the event name with. Normally, this set will
// be empty, and the qpButtonThrower will therefore ignore
// all ModifierButtons attached to the key events, but
// if one or more buttons have been added to this set,
// then the event name will be prepended with the names
// of the modifier buttons.
//
// It is recommended that you change this setting by
// first calling get_modifier_buttons(), making
// adjustments, and passing the new value to
// set_modifier_buttons(). This way the current state
// of the modifier buttons will not be lost.
////////////////////////////////////////////////////////////////////
void qpButtonThrower::
set_modifier_buttons(const ModifierButtons &mods) {
_mods = mods;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::set_throw_buttons_active
// Access: Published
// Description: Sets the flag that indicates whether the
// qpButtonThrower will only process events for the
// explicitly named buttons or not. Normally this is
// false, meaning all buttons are processed; set it true
// to indicate that only some buttons should be
// processed. See add_throw_button().
////////////////////////////////////////////////////////////////////
void qpButtonThrower::
set_throw_buttons_active(bool flag) {
_throw_buttons_active = flag;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::get_throw_buttons_active
// Access: Published
// Description: Returns the flag that indicates whether the
// qpButtonThrower will only process events for the
// explicitly named buttons or not. See
// set_throw_buttons_active().
////////////////////////////////////////////////////////////////////
bool qpButtonThrower::
get_throw_buttons_active() const {
return _throw_buttons_active;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::add_throw_button
// Access: Published
// Description: Adds a new button to the set of buttons that the
// qpButtonThrower explicitly processes.
//
// If set_throw_buttons_active is false (which is the
// default), the qpButtonThrower will process all buttons.
// Otherwise, the qpButtonThrower will only process events
// for the button(s) explicitly named by this function;
// buttons not on the list will be ignored by this
// object and passed on downstream to the child node(s)
// in the data graph. A button that *is* on the list
// will be processed by the qpButtonThrower and not passed
// on to the child node(s).
//
// The return value is true if the button is added, or
// false if it was already in the set.
////////////////////////////////////////////////////////////////////
bool qpButtonThrower::
add_throw_button(const ModifierButtons &mods, const ButtonHandle &button) {
ThrowButtonDef &def = _throw_buttons[button];
// This is a vector of ModifierButtons for which the indicated
// button is handled. Make sure the current ModifierButtons object
// is not already on the list.
ThrowButtonDef::iterator di;
for (di = def.begin(); di != def.end(); ++di) {
if (mods.matches(*di)) {
return false;
}
}
def.push_back(mods);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::remove_throw_button
// Access: Published
// Description: Removes the indicated button from the set of buttons
// that the qpButtonThrower explicitly processes. See
// add_throw_button().
//
// The return value is true if the button is removed, or
// false if it was not on the set.
////////////////////////////////////////////////////////////////////
bool qpButtonThrower::
remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button) {
ThrowButtons::iterator ti = _throw_buttons.find(button);
if (ti == _throw_buttons.end()) {
// No buttons of this kind are in the set.
return false;
}
ThrowButtonDef &def = (*ti).second;
// This is a vector of ModifierButtons for which the indicated
// button is handled.
ThrowButtonDef::iterator di;
for (di = def.begin(); di != def.end(); ++di) {
if (mods.matches(*di)) {
def.erase(di);
if (def.empty()) {
_throw_buttons.erase(ti);
}
return true;
}
}
// The indicated ModifierButtons are not applied to this button in
// the set.
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::has_throw_button
// Access: Published
// Description: Returns true if the indicated button is on the set of
// buttons that will be processed by the qpButtonThrower,
// false otherwise. See add_throw_button().
////////////////////////////////////////////////////////////////////
bool qpButtonThrower::
has_throw_button(const ModifierButtons &mods, const ButtonHandle &button) const {
ThrowButtons::const_iterator ti = _throw_buttons.find(button);
if (ti == _throw_buttons.end()) {
// No buttons of this kind are in the set.
return false;
}
const ThrowButtonDef &def = (*ti).second;
// This is a vector of ModifierButtons for which the indicated
// button is handled.
ThrowButtonDef::const_iterator di;
for (di = def.begin(); di != def.end(); ++di) {
if (mods.matches(*di)) {
return true;
}
}
// The indicated ModifierButtons are not applied to this button in
// the set.
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::has_throw_button
// Access: Published
// Description: Returns true if the indicated button, in conjunction
// with any nonspecified modifier buttons, is on the set
// of buttons that will be processed by the
// qpButtonThrower. That is to say, returns true if this
// button was ever passed as the second parameter
// add_throw_button(), regardless of what the first
// parameter was.
////////////////////////////////////////////////////////////////////
bool qpButtonThrower::
has_throw_button(const ButtonHandle &button) const {
ThrowButtons::const_iterator ti = _throw_buttons.find(button);
if (ti == _throw_buttons.end()) {
// No buttons of this kind are in the set.
return false;
}
const ThrowButtonDef &def = (*ti).second;
return !def.empty();
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::clear_throw_buttons
// Access: Published
// Description: Empties the set of buttons that were added via
// add_throw_button(). See add_throw_button().
////////////////////////////////////////////////////////////////////
void qpButtonThrower::
clear_throw_buttons() {
_throw_buttons.clear();
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::write
// Access: Public, Virtual
// Description: Throw all events for button events found in the data
// element.
////////////////////////////////////////////////////////////////////
void qpButtonThrower::
write(ostream &out, int indent_level) const {
qpDataNode::write(out, indent_level);
if (_throw_buttons_active) {
indent(out, indent_level)
<< "Processing keys:\n";
// Write the list of buttons that we're processing too.
ThrowButtons::const_iterator ti;
for (ti = _throw_buttons.begin(); ti != _throw_buttons.end(); ++ti) {
ButtonHandle button = (*ti).first;
const ThrowButtonDef &def = (*ti).second;
ThrowButtonDef::const_iterator di;
for (di = def.begin(); di != def.end(); ++di) {
indent(out, indent_level + 2)
<< (*di).get_prefix() << button.get_name() << "\n";
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: qpButtonThrower::do_transmit_data
// Access: Protected, Virtual
// Description: The virtual implementation of transmit_data(). This
// function receives an array of input parameters and
// should generate an array of output parameters. The
// input parameters may be accessed with the index
// numbers returned by the define_input() calls that
// were made earlier (presumably in the constructor);
// likewise, the output parameters should be set with
// the index numbers returned by the define_output()
// calls.
////////////////////////////////////////////////////////////////////
void qpButtonThrower::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
// Clear our outgoing button events. We'll fill it up again with
// just those events that want to carry on.
_button_events->clear();
if (input.has_data(_button_events_input)) {
const ButtonEventList *button_events;
DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
int num_events = button_events->get_num_events();
for (int i = 0; i < num_events; i++) {
const ButtonEvent &be = button_events->get_event(i);
string event_name = be._button.get_name();
if (be._type == ButtonEvent::T_down) {
// Button down.
if (!_mods.button_down(be._button)) {
// We only prepend modifier names on the button-down events,
// and only for buttons which are not themselves modifiers.
event_name = _mods.get_prefix() + event_name;
}
if (!_throw_buttons_active || has_throw_button(_mods, be._button)) {
// Process this button.
throw_event(_prefix + event_name);
} else {
// Don't process this button; instead, pass it down to future
// generations.
_button_events->add_event(be);
}
} else if (be._type == ButtonEvent::T_up) {
// Button up.
_mods.button_up(be._button);
// We always throw button "up" events if we have any
// definition for the button at all, regardless of the state
// of the modifier keys.
if (!_throw_buttons_active || has_throw_button(be._button)) {
throw_event(_prefix + event_name + "-up");
}
if (_throw_buttons_active) {
// Now pass the event on to future generations. We always
// pass "up" events, even if we are intercepting this
// particular button; unless we're processing all buttons in
// which case it doesn't matter.
_button_events->add_event(be);
}
} else {
// Some other kind of button event (e.g. keypress). Don't
// throw an event for this, but do pass it down.
_button_events->add_event(be);
}
}
}
output.set_data(_button_events_output, EventParameter(_button_events));
}

View File

@ -0,0 +1,106 @@
// Filename: qpbuttonThrower.h
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpBUTTONTHROWER_H
#define qpBUTTONTHROWER_H
#include "pandabase.h"
#include "qpdataNode.h"
#include "modifierButtons.h"
#include "buttonEventList.h"
#include "pvector.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
// Class : qpButtonThrower
// Description : Throws Panda Events for button down/up events
// generated within the data graph.
//
// This is a DataNode which is intended to be parented
// to the data graph below a device which is generating
// a sequence of button events, like a MouseAndKeyboard
// device. It simply takes each button it finds and
// throws a corresponding event based on the button name
// via the throw_event() call.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpButtonThrower : public qpDataNode {
PUBLISHED:
qpButtonThrower(const string &name);
~qpButtonThrower();
void set_prefix(const string &prefix);
bool has_prefix() const;
string get_prefix() const;
const ModifierButtons &get_modifier_buttons() const;
void set_modifier_buttons(const ModifierButtons &mods);
void set_throw_buttons_active(bool flag);
bool get_throw_buttons_active() const;
bool add_throw_button(const ModifierButtons &mods, const ButtonHandle &button);
bool remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button);
bool has_throw_button(const ModifierButtons &mods, const ButtonHandle &button) const;
bool has_throw_button(const ButtonHandle &button) const;
void clear_throw_buttons();
public:
virtual void write(ostream &out, int indent_level = 0) const;
private:
string _prefix;
ModifierButtons _mods;
typedef pvector<ModifierButtons> ThrowButtonDef;
typedef pmap<ButtonHandle, ThrowButtonDef> ThrowButtons;
ThrowButtons _throw_buttons;
bool _throw_buttons_active;
protected:
// Inherited from DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
DataNodeTransmit &output);
private:
// inputs
int _button_events_input;
// outputs
int _button_events_output;
PT(ButtonEventList) _button_events;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
qpDataNode::init_type();
register_type(_type_handle, "qpButtonThrower",
qpDataNode::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;
};
#endif

View File

@ -0,0 +1,530 @@
// Filename: qptrackball.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qptrackball.h"
#include "buttonEvent.h"
#include "buttonEventList.h"
#include "dataNodeTransmit.h"
#include "compose_matrix.h"
#include "mouseData.h"
#include "modifierButtons.h"
TypeHandle qpTrackball::_type_handle;
// These are used internally.
#define B1_MASK 0x1
#define B2_MASK 0x2
#define B3_MASK 0x4
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
qpTrackball::
qpTrackball(const string &name) :
qpDataNode(name)
{
_pixel_xy_input = define_input("PixelXY", EventStoreVec2::get_class_type());
_button_events_input = define_input("ButtonEvents", ButtonEventList::get_class_type());
_transform_output = define_output("Transform", EventStoreMat4::get_class_type());
_transform = new EventStoreMat4(LMatrix4f::ident_mat());
_rotscale = 0.3f;
_fwdscale = 0.3f;
_lastx = _lasty = 0.5f;
_rotation = LMatrix4f::ident_mat();
_translation.set(0.0f, 0.0f, 0.0f);
_mat = LMatrix4f::ident_mat();
_orig = LMatrix4f::ident_mat();
_invert = true;
_cs = default_coordinate_system;
_mods.add_button(MouseButton::one());
_mods.add_button(MouseButton::two());
_mods.add_button(MouseButton::three());
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::Destructor
// Access: Public, Scheme
// Description:
////////////////////////////////////////////////////////////////////
qpTrackball::
~qpTrackball() {
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::reset
// Access: Public, Scheme
// Description: Reinitializes all transforms to identity.
////////////////////////////////////////////////////////////////////
void qpTrackball::
reset() {
_rotation = LMatrix4f::ident_mat();
_translation.set(0.0f, 0.0f, 0.0f);
_orig = LMatrix4f::ident_mat();
_mat = LMatrix4f::ident_mat();
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_pos
// Access: Public, Scheme
// Description: Return the offset from the center of rotation.
////////////////////////////////////////////////////////////////////
const LPoint3f &qpTrackball::
get_pos() const {
return _translation;
}
float qpTrackball::
get_x() const {
return _translation[0];
}
float qpTrackball::
get_y() const {
return _translation[1];
}
float qpTrackball::
get_z() const {
return _translation[2];
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::set_pos
// Access: Public, Scheme
// Description: Directly set the offset from the rotational origin.
////////////////////////////////////////////////////////////////////
void qpTrackball::
set_pos(const LVecBase3f &vec) {
_translation = vec;
recompute();
}
void qpTrackball::
set_pos(float x, float y, float z) {
_translation.set(x, y, z);
recompute();
}
void qpTrackball::
set_x(float x) {
_translation[0] = x;
recompute();
}
void qpTrackball::
set_y(float y) {
_translation[1] = y;
recompute();
}
void qpTrackball::
set_z(float z) {
_translation[2] = z;
recompute();
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_hpr
// Access: Public, Scheme
// Description: Return the trackball's orientation.
////////////////////////////////////////////////////////////////////
LVecBase3f qpTrackball::
get_hpr() const {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
return hpr;
}
float qpTrackball::
get_h() const {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
return hpr[0];
}
float qpTrackball::
get_p() const {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
return hpr[1];
}
float qpTrackball::
get_r() const {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
return hpr[2];
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::set_hpr
// Access: Public, Scheme
// Description: Directly set the mover's orientation.
////////////////////////////////////////////////////////////////////
void qpTrackball::
set_hpr(const LVecBase3f &hpr) {
LVecBase3f scale, old_hpr, translate;
decompose_matrix(_rotation, scale, old_hpr, translate);
compose_matrix(_rotation, scale, hpr, translate);
recompute();
}
void qpTrackball::
set_hpr(float h, float p, float r) {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
hpr.set(h, p, r);
compose_matrix(_rotation, scale, hpr, translate);
recompute();
}
void qpTrackball::
set_h(float h) {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
hpr[0] = h;
compose_matrix(_rotation, scale, hpr, translate);
recompute();
}
void qpTrackball::
set_p(float p) {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
hpr[1] = p;
compose_matrix(_rotation, scale, hpr, translate);
recompute();
}
void qpTrackball::
set_r(float r) {
LVecBase3f scale, hpr, translate;
decompose_matrix(_rotation, scale, hpr, translate);
hpr[2] = r;
compose_matrix(_rotation, scale, hpr, translate);
recompute();
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::reset_origin_here
// Access: Public, Scheme
// Description: Reposition the center of rotation to coincide with
// the current translation offset. Future rotations
// will be about the current origin.
////////////////////////////////////////////////////////////////////
void qpTrackball::
reset_origin_here() {
recompute();
_rotation = _orig;
_translation.set(0.0f, 0.0f, 0.0f);
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::move_origin
// Access: Public, Scheme
// Description: Moves the center of rotation by the given amount.
////////////////////////////////////////////////////////////////////
void qpTrackball::
move_origin(float x, float y, float z) {
_rotation = LMatrix4f::translate_mat(LVecBase3f(x, y, z)) * _rotation;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::set_invert
// Access: Public, Scheme
// Description: Sets the invert flag. When this is set, the inverse
// matrix is generated, suitable for joining to a
// camera, instead of parenting the scene under it.
////////////////////////////////////////////////////////////////////
void qpTrackball::
set_invert(bool flag) {
_invert = flag;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_invert
// Access: Public, Scheme
// Description: Returns the invert flag. When this is set, the
// inverse matrix is generated, suitable for joining to
// a camera, instead of parenting the scene under it.
////////////////////////////////////////////////////////////////////
bool qpTrackball::
get_invert() const {
return _invert;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::set_rel_to
// Access: Public, Scheme
// Description: Sets the NodePath that all trackball manipulations
// are to be assumed to be relative to. For instance,
// set your camera node here to make the trackball
// motion camera relative. The default is the empty
// path, which means trackball motion is in global
// space.
////////////////////////////////////////////////////////////////////
void qpTrackball::
set_rel_to(const qpNodePath &rel_to) {
_rel_to = rel_to;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_rel_to
// Access: Public, Scheme
// Description: Returns the NodePath that all trackball manipulations
// are relative to, or the empty path.
////////////////////////////////////////////////////////////////////
const qpNodePath &qpTrackball::
get_rel_to() const {
return _rel_to;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::set_coordinate_system
// Access: Public, Scheme
// Description: Sets the coordinate system of the Trackball.
// Normally, this is the default coordinate system.
// This changes the axes the Trackball manipulates so
// that the user interface remains consistent across
// different coordinate systems.
////////////////////////////////////////////////////////////////////
void qpTrackball::
set_coordinate_system(CoordinateSystem cs) {
_cs = cs;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_coordinate_system
// Access: Public, Scheme
// Description: Returns the coordinate system of the Trackball.
// See set_coordinate_system().
////////////////////////////////////////////////////////////////////
CoordinateSystem qpTrackball::
get_coordinate_system() const {
return _cs;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::set_mat
// Access: Public, Scheme
// Description: Stores the indicated transform in the trackball.
// This is a transform in global space, regardless of
// the rel_to node.
////////////////////////////////////////////////////////////////////
void qpTrackball::
set_mat(const LMatrix4f &mat) {
_orig = mat;
if (_invert) {
_mat = invert(_orig);
} else {
_mat = _orig;
}
reextract();
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_mat
// Access: Public, Scheme
// Description: Returns the matrix represented by the trackball
// rotation.
////////////////////////////////////////////////////////////////////
const LMatrix4f &qpTrackball::
get_mat() const {
return _orig;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::get_trans_mat
// Access: Public, Scheme
// Description: Returns the actual transform that will be applied to
// the scene graph. This is the same as get_mat(),
// unless invert is in effect.
////////////////////////////////////////////////////////////////////
const LMatrix4f &qpTrackball::
get_trans_mat() const {
return _mat;
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::apply
// Access: Private
// Description: Applies the operation indicated by the user's mouse
// motion to the current state. Returns the matrix
// indicating the new state.
////////////////////////////////////////////////////////////////////
void qpTrackball::
apply(double x, double y, int button) {
if (button && !_rel_to.is_empty()) {
// If we have a rel_to node, we must first adjust our rotation and
// translation to be in those local coordinates.
reextract();
}
if (button == B1_MASK) {
// Button 1: translate in plane parallel to screen.
_translation +=
x * _fwdscale * LVector3f::right(_cs) +
y * _fwdscale * LVector3f::down(_cs);
} else if (button == (B2_MASK | B3_MASK)) {
// Buttons 2 + 3: rotate about the vector perpendicular to the
// screen.
_rotation *=
LMatrix4f::rotate_mat_normaxis((x - y) * _rotscale,
LVector3f::forward(_cs), _cs);
} else if ((button == B2_MASK) || (button == (B1_MASK | B3_MASK))) {
// Button 2, or buttons 1 + 3: rotate about the right and up
// vectors. (We alternately define this as buttons 1 + 3, to
// support two-button mice.)
_rotation *=
LMatrix4f::rotate_mat_normaxis(x * _rotscale, LVector3f::up(_cs), _cs) *
LMatrix4f::rotate_mat_normaxis(y * _rotscale, LVector3f::right(_cs), _cs);
} else if ((button == B3_MASK) || (button == (B1_MASK | B2_MASK))) {
// Button 3, or buttons 1 + 2: dolly in and out along the forward
// vector. (We alternately define this as buttons 1 + 2, to
// support two-button mice.)
_translation -= y * _fwdscale * LVector3f::forward(_cs);
}
if (button) {
recompute();
}
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::reextract
// Access: Private
// Description: Given a correctly computed _orig matrix, rederive the
// translation and rotation elements.
////////////////////////////////////////////////////////////////////
void qpTrackball::
reextract() {
LMatrix4f m = _orig;
if (!_rel_to.is_empty()) {
qpNodePath root;
const LMatrix4f &rel_mat = root.get_mat(_rel_to);
m = _orig * rel_mat;
}
m.get_row3(_translation,3);
_rotation = m;
_rotation.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::recompute
// Access: Private
// Description: Rebuilds the matrix according to the stored rotation
// and translation components.
////////////////////////////////////////////////////////////////////
void qpTrackball::
recompute() {
_orig = _rotation * LMatrix4f::translate_mat(_translation);
if (!_rel_to.is_empty()) {
qpNodePath root;
const LMatrix4f &rel_mat = _rel_to.get_mat(root);
_orig = _orig * rel_mat;
}
if (_invert) {
_mat = invert(_orig);
} else {
_mat = _orig;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpTrackball::do_transmit_data
// Access: Protected, Virtual
// Description: The virtual implementation of transmit_data(). This
// function receives an array of input parameters and
// should generate an array of output parameters. The
// input parameters may be accessed with the index
// numbers returned by the define_input() calls that
// were made earlier (presumably in the constructor);
// likewise, the output parameters should be set with
// the index numbers returned by the define_output()
// calls.
////////////////////////////////////////////////////////////////////
void qpTrackball::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
// First, update our modifier buttons.
if (input.has_data(_button_events_input)) {
const ButtonEventList *button_events;
DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
button_events->update_mods(_mods);
}
// Now, check for mouse motion.
if (input.has_data(_pixel_xy_input)) {
const EventStoreVec2 *pixel_xy;
DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
const LVecBase2f &p = pixel_xy->get_value();
float this_x = p[0];
float this_y = p[1];
int this_button = 0;
if (_mods.is_down(MouseButton::one())) {
this_button |= B1_MASK;
}
if (_mods.is_down(MouseButton::two())) {
this_button |= B2_MASK;
}
if (_mods.is_down(MouseButton::three())) {
this_button |= B3_MASK;
}
float x = this_x - _lastx;
float y = this_y - _lasty;
apply(x, y, this_button);
_lastx = this_x;
_lasty = this_y;
}
// Now send our matrix down the pipe.
_transform->set_value(_mat);
output.set_data(_transform_output, EventParameter(_transform));
}

View File

@ -0,0 +1,152 @@
// Filename: qptrackball.h
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpTRACKBALL_H
#define qpTRACKBALL_H
#include "pandabase.h"
#include "qpdataNode.h"
#include "qpnodePath.h"
#include "modifierButtons.h"
#include "luse.h"
#include "linmath_events.h"
////////////////////////////////////////////////////////////////////
// Class : qpTrackball
// Description : Trackball acts like Performer in trackball mode. It
// can either spin around a piece of geometry directly,
// or it can spin around a camera with the inverse
// transform to make it appear that the whole world is
// spinning.
//
// The Trackball object actually just places a transform
// in the data graph; parent a Transform2SG node under
// it to actually transform objects (or cameras) in the
// world.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpTrackball : public qpDataNode {
PUBLISHED:
qpTrackball(const string &name);
~qpTrackball();
void reset();
/// **** Translation ****
const LPoint3f &get_pos() const;
float get_x() const;
float get_y() const;
float get_z() const;
void set_pos(const LVecBase3f &vec);
void set_pos(float x, float y, float z);
void set_x(float x);
void set_y(float y);
void set_z(float z);
/// **** Rotation ****
LVecBase3f get_hpr() const;
float get_h() const;
float get_p() const;
float get_r() const;
void set_hpr(const LVecBase3f &hpr);
void set_hpr(float h, float p, float r);
void set_h(float h);
void set_p(float p);
void set_r(float r);
/// **** Origin of Rotation ****
void reset_origin_here();
void move_origin(float x, float y, float z);
/// **** Misc ****
void set_invert(bool flag);
bool get_invert() const;
void set_rel_to(const qpNodePath &_rel_to);
const qpNodePath &get_rel_to() const;
void set_coordinate_system(CoordinateSystem cs);
CoordinateSystem get_coordinate_system() const;
void set_mat(const LMatrix4f &mat);
const LMatrix4f &get_mat() const;
const LMatrix4f &get_trans_mat() const;
private:
void apply(double x, double y, int button);
void reextract();
void recompute();
float _lastx, _lasty;
float _rotscale;
float _fwdscale;
LMatrix4f _rotation;
LPoint3f _translation;
LMatrix4f _mat, _orig;
bool _invert;
qpNodePath _rel_to;
CoordinateSystem _cs;
// Remember which mouse buttons are being held down.
ModifierButtons _mods;
protected:
// Inherited from DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
DataNodeTransmit &output);
private:
// inputs
int _pixel_xy_input;
int _button_events_input;
// outputs
int _transform_output;
PT(EventStoreMat4) _transform;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
qpDataNode::init_type();
register_type(_type_handle, "qpTrackball",
qpDataNode::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;
};
#endif

View File

@ -0,0 +1,84 @@
// Filename: qptransform2sg.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qptransform2sg.h"
#include "transformState.h"
TypeHandle qpTransform2SG::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: qpTransform2SG::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
qpTransform2SG::
qpTransform2SG(const string &name) :
qpDataNode(name)
{
_transform_input = define_input("Transform", EventStoreMat4::get_class_type());
_node = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: qpTransform2SG::set_node
// Access: Public
// Description: Sets the node that this node will adjust.
////////////////////////////////////////////////////////////////////
void qpTransform2SG::
set_node(PandaNode *node) {
_node = node;
}
////////////////////////////////////////////////////////////////////
// Function: qpTransform2SG::get_node
// Access: Public
// Description: Returns the node that this node will adjust, or NULL
// if the node has not yet been set.
////////////////////////////////////////////////////////////////////
PandaNode *qpTransform2SG::
get_node() const {
return _node;
}
////////////////////////////////////////////////////////////////////
// Function: qpTransform2SG::do_transmit_data
// Access: Protected, Virtual
// Description: The virtual implementation of transmit_data(). This
// function receives an array of input parameters and
// should generate an array of output parameters. The
// input parameters may be accessed with the index
// numbers returned by the define_input() calls that
// were made earlier (presumably in the constructor);
// likewise, the output parameters should be set with
// the index numbers returned by the define_output()
// calls.
////////////////////////////////////////////////////////////////////
void qpTransform2SG::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &) {
if (input.has_data(_transform_input)) {
const EventStoreMat4 *transform;
DCAST_INTO_V(transform, input.get_data(_transform_input).get_ptr());
const LMatrix4f &mat = transform->get_value();
if (_node != (PandaNode *)NULL) {
_node->set_transform(TransformState::make_mat(mat));
}
}
}

View File

@ -0,0 +1,72 @@
// Filename: qptransform2sg.h
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpTRANSFORM2SG_H
#define qpTRANSFORM2SG_H
#include "pandabase.h"
#include "qpdataNode.h"
#include "pandaNode.h"
////////////////////////////////////////////////////////////////////
// Class : qpTransform2SG
// Description : input: Transform (matrix)
//
// output: none, but applies the matrix as the transform
// transition for a given arc of the scene graph.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpTransform2SG : public qpDataNode {
PUBLISHED:
qpTransform2SG(const string &name);
void set_node(PandaNode *node);
PandaNode *get_node() const;
private:
PandaNode *_node;
protected:
// Inherited from DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
DataNodeTransmit &output);
private:
// inputs
int _transform_input;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
qpDataNode::init_type();
register_type(_type_handle, "qpTransform2SG",
qpDataNode::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;
};
#endif

View File

@ -1,5 +1,6 @@
#include "buttonThrower.cxx"
#include "qpbuttonThrower.cxx"
#include "config_tform.cxx"
#include "dataValve.cxx"
#include "driveInterface.cxx"

View File

@ -4,5 +4,7 @@
#include "mouseWatcherParameter.cxx"
#include "mouseWatcherRegion.cxx"
#include "trackball.cxx"
#include "qptrackball.cxx"
#include "transform2sg.cxx"
#include "qptransform2sg.cxx"