From d3e2ffbda285eca8005f0fb4a3d01c2a8b794087 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 12 Mar 2002 18:42:55 +0000 Subject: [PATCH] pgraph data graph --- panda/src/device/Sources.pp | 31 +- panda/src/device/config_device.cxx | 2 + panda/src/device/device_composite2.cxx | 1 + panda/src/device/mouseAndKeyboard.cxx | 91 ++++ panda/src/device/mouseAndKeyboard.h | 90 ++++ panda/src/dgraph/Sources.pp | 61 ++- panda/src/dgraph/config_dgraph.cxx | 2 + panda/src/dgraph/dataNodeTransmit.I | 111 +++++ panda/src/dgraph/dataNodeTransmit.cxx | 33 ++ panda/src/dgraph/dataNodeTransmit.h | 54 +++ panda/src/dgraph/dgraph_composite2.cxx | 3 + panda/src/dgraph/qpdataGraphTraverser.I | 29 ++ panda/src/dgraph/qpdataGraphTraverser.cxx | 167 +++++++ panda/src/dgraph/qpdataGraphTraverser.h | 66 +++ panda/src/dgraph/qpdataNode.I | 67 +++ panda/src/dgraph/qpdataNode.cxx | 289 +++++++++++ panda/src/dgraph/qpdataNode.h | 142 ++++++ panda/src/event/config_event.cxx | 1 - panda/src/event/eventParameter.I | 75 ++- panda/src/event/eventParameter.h | 23 +- panda/src/mathutil/Sources.pp | 36 +- panda/src/mathutil/config_mathutil.cxx | 6 +- panda/src/mathutil/linmath_events.cxx | 24 + panda/src/mathutil/linmath_events.h | 53 +++ panda/src/mathutil/mathutil_composite2.cxx | 1 + panda/src/pgraph/pandaNode.cxx | 99 +++- panda/src/pgraph/pandaNode.h | 2 + panda/src/putil/Sources.pp | 12 +- panda/src/putil/buttonEventList.I | 74 +++ panda/src/putil/buttonEventList.cxx | 62 +++ panda/src/putil/buttonEventList.h | 82 ++++ panda/src/putil/config_util.cxx | 2 + panda/src/putil/putil_composite1.cxx | 1 + panda/src/testbed/pview.cxx | 47 +- panda/src/tform/Sources.pp | 27 +- panda/src/tform/config_tform.cxx | 6 + panda/src/tform/qpbuttonThrower.cxx | 399 ++++++++++++++++ panda/src/tform/qpbuttonThrower.h | 106 +++++ panda/src/tform/qptrackball.cxx | 530 +++++++++++++++++++++ panda/src/tform/qptrackball.h | 152 ++++++ panda/src/tform/qptransform2sg.cxx | 84 ++++ panda/src/tform/qptransform2sg.h | 72 +++ panda/src/tform/tform_composite1.cxx | 1 + panda/src/tform/tform_composite2.cxx | 2 + 44 files changed, 3047 insertions(+), 171 deletions(-) create mode 100644 panda/src/device/mouseAndKeyboard.cxx create mode 100644 panda/src/device/mouseAndKeyboard.h create mode 100644 panda/src/dgraph/dataNodeTransmit.I create mode 100644 panda/src/dgraph/dataNodeTransmit.cxx create mode 100644 panda/src/dgraph/dataNodeTransmit.h create mode 100644 panda/src/dgraph/qpdataGraphTraverser.I create mode 100644 panda/src/dgraph/qpdataGraphTraverser.cxx create mode 100644 panda/src/dgraph/qpdataGraphTraverser.h create mode 100644 panda/src/dgraph/qpdataNode.I create mode 100644 panda/src/dgraph/qpdataNode.cxx create mode 100644 panda/src/dgraph/qpdataNode.h create mode 100644 panda/src/mathutil/linmath_events.cxx create mode 100644 panda/src/mathutil/linmath_events.h create mode 100644 panda/src/putil/buttonEventList.I create mode 100644 panda/src/putil/buttonEventList.cxx create mode 100644 panda/src/putil/buttonEventList.h create mode 100644 panda/src/tform/qpbuttonThrower.cxx create mode 100644 panda/src/tform/qpbuttonThrower.h create mode 100644 panda/src/tform/qptrackball.cxx create mode 100644 panda/src/tform/qptrackball.h create mode 100644 panda/src/tform/qptransform2sg.cxx create mode 100644 panda/src/tform/qptransform2sg.h diff --git a/panda/src/device/Sources.pp b/panda/src/device/Sources.pp index 6f7a024d9f..ac4e5c145b 100644 --- a/panda/src/device/Sources.pp +++ b/panda/src/device/Sources.pp @@ -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 diff --git a/panda/src/device/config_device.cxx b/panda/src/device/config_device.cxx index 8656c421f3..14b6254487 100644 --- a/panda/src/device/config_device.cxx +++ b/panda/src/device/config_device.cxx @@ -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(); } diff --git a/panda/src/device/device_composite2.cxx b/panda/src/device/device_composite2.cxx index 8e194836f4..7315d7bd6d 100644 --- a/panda/src/device/device_composite2.cxx +++ b/panda/src/device/device_composite2.cxx @@ -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" diff --git a/panda/src/device/mouseAndKeyboard.cxx b/panda/src/device/mouseAndKeyboard.cxx new file mode 100644 index 0000000000..a402e4f0df --- /dev/null +++ b/panda/src/device/mouseAndKeyboard.cxx @@ -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)); + } + } +} diff --git a/panda/src/device/mouseAndKeyboard.h b/panda/src/device/mouseAndKeyboard.h new file mode 100644 index 0000000000..b54ea9d523 --- /dev/null +++ b/panda/src/device/mouseAndKeyboard.h @@ -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 diff --git a/panda/src/dgraph/Sources.pp b/panda/src/dgraph/Sources.pp index e43a2151ee..142e4aa606 100644 --- a/panda/src/dgraph/Sources.pp +++ b/panda/src/dgraph/Sources.pp @@ -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 diff --git a/panda/src/dgraph/config_dgraph.cxx b/panda/src/dgraph/config_dgraph.cxx index 3602ccb003..5ca354b615 100644 --- a/panda/src/dgraph/config_dgraph.cxx +++ b/panda/src/dgraph/config_dgraph.cxx @@ -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(); diff --git a/panda/src/dgraph/dataNodeTransmit.I b/panda/src/dgraph/dataNodeTransmit.I new file mode 100644 index 0000000000..0acfce3327 --- /dev/null +++ b/panda/src/dgraph/dataNodeTransmit.I @@ -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 ©) : + _data(copy._data) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: DataNodeTransmit::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void DataNodeTransmit:: +operator = (const DataNodeTransmit ©) { + _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; +} diff --git a/panda/src/dgraph/dataNodeTransmit.cxx b/panda/src/dgraph/dataNodeTransmit.cxx new file mode 100644 index 0000000000..593e0af942 --- /dev/null +++ b/panda/src/dgraph/dataNodeTransmit.cxx @@ -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()); + } +} diff --git a/panda/src/dgraph/dataNodeTransmit.h b/panda/src/dgraph/dataNodeTransmit.h new file mode 100644 index 0000000000..df557b55e2 --- /dev/null +++ b/panda/src/dgraph/dataNodeTransmit.h @@ -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 ©); + INLINE void operator = (const DataNodeTransmit ©); + 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 Data; + Data _data; +}; + +#include "dataNodeTransmit.I" + +#endif diff --git a/panda/src/dgraph/dgraph_composite2.cxx b/panda/src/dgraph/dgraph_composite2.cxx index 0c75ba6520..3b2d232a4a 100644 --- a/panda/src/dgraph/dgraph_composite2.cxx +++ b/panda/src/dgraph/dgraph_composite2.cxx @@ -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" diff --git a/panda/src/dgraph/qpdataGraphTraverser.I b/panda/src/dgraph/qpdataGraphTraverser.I new file mode 100644 index 0000000000..f46eecd012 --- /dev/null +++ b/panda/src/dgraph/qpdataGraphTraverser.I @@ -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) +{ +} diff --git a/panda/src/dgraph/qpdataGraphTraverser.cxx b/panda/src/dgraph/qpdataGraphTraverser.cxx new file mode 100644 index 0000000000..125369c9ed --- /dev/null +++ b/panda/src/dgraph/qpdataGraphTraverser.cxx @@ -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); + } + } +} diff --git a/panda/src/dgraph/qpdataGraphTraverser.h b/panda/src/dgraph/qpdataGraphTraverser.h new file mode 100644 index 0000000000..ca572f3b5e --- /dev/null +++ b/panda/src/dgraph/qpdataGraphTraverser.h @@ -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 DataVector; + + class CollectedData { + public: + INLINE CollectedData(); + void set_data(int parent_index, const DataNodeTransmit &data); + + int _num_parents; + DataVector _data; + }; + typedef pmap MultipassData; + MultipassData _multipass_data; +}; + +#include "qpdataGraphTraverser.I" + +#endif diff --git a/panda/src/dgraph/qpdataNode.I b/panda/src/dgraph/qpdataNode.I new file mode 100644 index 0000000000..bc32b8ca4c --- /dev/null +++ b/panda/src/dgraph/qpdataNode.I @@ -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 ©) : + 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(); +} diff --git a/panda/src/dgraph/qpdataNode.cxx b/panda/src/dgraph/qpdataNode.cxx new file mode 100644 index 0000000000..4ccb594a5c --- /dev/null +++ b/panda/src/dgraph/qpdataNode.cxx @@ -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"; + } +} diff --git a/panda/src/dgraph/qpdataNode.h b/panda/src/dgraph/qpdataNode.h new file mode 100644 index 0000000000..0c0b870485 --- /dev/null +++ b/panda/src/dgraph/qpdataNode.h @@ -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 ©); +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 Wires; + + Wires _input_wires; + Wires _output_wires; + + class DataConnection { + public: + int _parent_index; + int _output_index; + int _input_index; + }; + typedef pvector 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 diff --git a/panda/src/event/config_event.cxx b/panda/src/event/config_event.cxx index f7131d96e3..6f760e0812 100644 --- a/panda/src/event/config_event.cxx +++ b/panda/src/event/config_event.cxx @@ -32,6 +32,5 @@ ConfigureFn(config_event) { EventStoreInt::init_type("EventStoreInt"); EventStoreDouble::init_type("EventStoreDouble"); EventStoreString::init_type("EventStoreString"); -// EventStoreVec3::init_type("EventStoreVec3"); } diff --git a/panda/src/event/eventParameter.I b/panda/src/event/eventParameter.I index 81c421d8db..17d81d1f09 100644 --- a/panda/src/event/eventParameter.I +++ b/panda/src/event/eventParameter.I @@ -21,6 +21,16 @@ template TypeHandle EventStoreValue::_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 -INLINE Type EventStoreValue:: +INLINE const Type &EventStoreValue:: get_value() const { return _value; } diff --git a/panda/src/event/eventParameter.h b/panda/src/event/eventParameter.h index b08196c816..b50cc68e11 100644 --- a/panda/src/event/eventParameter.h +++ b/panda/src/event/eventParameter.h @@ -19,14 +19,12 @@ #ifndef EVENTPARAMETER_H #define EVENTPARAMETER_H -#include +#include "pandabase.h" -#include -#include -#include -#include -//#include -#include +#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 ©); INLINE EventParameter &operator = (const EventParameter ©); @@ -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); EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); -//EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); typedef EventStoreValue EventStoreInt; typedef EventStoreValue EventStoreDouble; typedef EventStoreValue EventStoreString; -//typedef EventStoreValue EventStoreVec3; #include "eventParameter.I" diff --git a/panda/src/mathutil/Sources.pp b/panda/src/mathutil/Sources.pp index c47bfd5831..1efdb18475 100644 --- a/panda/src/mathutil/Sources.pp +++ b/panda/src/mathutil/Sources.pp @@ -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 diff --git a/panda/src/mathutil/config_mathutil.cxx b/panda/src/mathutil/config_mathutil.cxx index d0ddaaaf2b..ded99e8adc 100644 --- a/panda/src/mathutil/config_mathutil.cxx +++ b/panda/src/mathutil/config_mathutil.cxx @@ -24,7 +24,8 @@ #include "boundingSphere.h" #include "boundingHexahedron.h" #include "boundingLine.h" -#include +#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"); } diff --git a/panda/src/mathutil/linmath_events.cxx b/panda/src/mathutil/linmath_events.cxx new file mode 100644 index 0000000000..90f8522df1 --- /dev/null +++ b/panda/src/mathutil/linmath_events.cxx @@ -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 diff --git a/panda/src/mathutil/linmath_events.h b/panda/src/mathutil/linmath_events.h new file mode 100644 index 0000000000..633838fb27 --- /dev/null +++ b/panda/src/mathutil/linmath_events.h @@ -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); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); + +typedef EventStoreValue EventStoreVec2; +typedef EventStoreValue EventStoreVec3; +typedef EventStoreValue EventStoreMat4; + + +// Tell GCC that we'll take care of the instantiation explicitly here. +#ifdef __GNUC__ +#pragma interface +#endif + +#endif diff --git a/panda/src/mathutil/mathutil_composite2.cxx b/panda/src/mathutil/mathutil_composite2.cxx index 9f039ff89f..f1d7c7aad0 100644 --- a/panda/src/mathutil/mathutil_composite2.cxx +++ b/panda/src/mathutil/mathutil_composite2.cxx @@ -3,5 +3,6 @@ #include "plane.cxx" #include "rotate_to.cxx" #include "look_at.cxx" +#include "linmath_events.cxx" #include "fftCompressor.cxx" diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index b440e3fc85..a851a07405 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -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(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index e3bc6d1f08..ca5ad13e1e 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -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). diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index afae7d8bfa..39bab316b8 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -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 \ diff --git a/panda/src/putil/buttonEventList.I b/panda/src/putil/buttonEventList.I new file mode 100644 index 0000000000..3022081739 --- /dev/null +++ b/panda/src/putil/buttonEventList.I @@ -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(); +} diff --git a/panda/src/putil/buttonEventList.cxx b/panda/src/putil/buttonEventList.cxx new file mode 100644 index 0000000000..a01dd802b1 --- /dev/null +++ b/panda/src/putil/buttonEventList.cxx @@ -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"; + } +} diff --git a/panda/src/putil/buttonEventList.h b/panda/src/putil/buttonEventList.h new file mode 100644 index 0000000000..d0b75b7e24 --- /dev/null +++ b/panda/src/putil/buttonEventList.h @@ -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 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 + diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index cc02cc8674..163e8b41b7 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -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(); diff --git a/panda/src/putil/putil_composite1.cxx b/panda/src/putil/putil_composite1.cxx index 2fb75b2d55..3c27fb8148 100644 --- a/panda/src/putil/putil_composite1.cxx +++ b/panda/src/putil/putil_composite1.cxx @@ -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" diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index 8b4d5288cf..25caddc4c6 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -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(); } diff --git a/panda/src/tform/Sources.pp b/panda/src/tform/Sources.pp index 62ce07e179..9e372d15ed 100644 --- a/panda/src/tform/Sources.pp +++ b/panda/src/tform/Sources.pp @@ -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 diff --git a/panda/src/tform/config_tform.cxx b/panda/src/tform/config_tform.cxx index e0be47a881..a945839b8e 100644 --- a/panda/src/tform/config_tform.cxx +++ b/panda/src/tform/config_tform.cxx @@ -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 @@ -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(); } diff --git a/panda/src/tform/qpbuttonThrower.cxx b/panda/src/tform/qpbuttonThrower.cxx new file mode 100644 index 0000000000..21089ce235 --- /dev/null +++ b/panda/src/tform/qpbuttonThrower.cxx @@ -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)); +} diff --git a/panda/src/tform/qpbuttonThrower.h b/panda/src/tform/qpbuttonThrower.h new file mode 100644 index 0000000000..8bd2b7d04e --- /dev/null +++ b/panda/src/tform/qpbuttonThrower.h @@ -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 ThrowButtonDef; + typedef pmap 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 diff --git a/panda/src/tform/qptrackball.cxx b/panda/src/tform/qptrackball.cxx new file mode 100644 index 0000000000..4318ce0be7 --- /dev/null +++ b/panda/src/tform/qptrackball.cxx @@ -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)); +} diff --git a/panda/src/tform/qptrackball.h b/panda/src/tform/qptrackball.h new file mode 100644 index 0000000000..f38a52d59b --- /dev/null +++ b/panda/src/tform/qptrackball.h @@ -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 diff --git a/panda/src/tform/qptransform2sg.cxx b/panda/src/tform/qptransform2sg.cxx new file mode 100644 index 0000000000..c6971b7d54 --- /dev/null +++ b/panda/src/tform/qptransform2sg.cxx @@ -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)); + } + } +} diff --git a/panda/src/tform/qptransform2sg.h b/panda/src/tform/qptransform2sg.h new file mode 100644 index 0000000000..7cb8e750df --- /dev/null +++ b/panda/src/tform/qptransform2sg.h @@ -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 + diff --git a/panda/src/tform/tform_composite1.cxx b/panda/src/tform/tform_composite1.cxx index ba608cb7b5..d034bf6349 100644 --- a/panda/src/tform/tform_composite1.cxx +++ b/panda/src/tform/tform_composite1.cxx @@ -1,5 +1,6 @@ #include "buttonThrower.cxx" +#include "qpbuttonThrower.cxx" #include "config_tform.cxx" #include "dataValve.cxx" #include "driveInterface.cxx" diff --git a/panda/src/tform/tform_composite2.cxx b/panda/src/tform/tform_composite2.cxx index 8b5e2f3d99..3875791b59 100644 --- a/panda/src/tform/tform_composite2.cxx +++ b/panda/src/tform/tform_composite2.cxx @@ -4,5 +4,7 @@ #include "mouseWatcherParameter.cxx" #include "mouseWatcherRegion.cxx" #include "trackball.cxx" +#include "qptrackball.cxx" #include "transform2sg.cxx" +#include "qptransform2sg.cxx"