anim controls in pview

This commit is contained in:
David Rose 2005-10-10 19:50:20 +00:00
parent d9b6585a78
commit 5bf4f3557d
13 changed files with 285 additions and 11 deletions

View File

@ -186,6 +186,20 @@ get_num_frames(const string &anim_name) const {
return control->get_num_frames();
}
////////////////////////////////////////////////////////////////////
// Function: AnimControlCollection::get_num_frames
// Access: Public
// Description: Returns the total number of frames in the
// last-started animation.
////////////////////////////////////////////////////////////////////
INLINE int AnimControlCollection::
get_num_frames() const {
if (_last_started_control == (AnimControl *)NULL) {
return 0;
}
return _last_started_control->get_num_frames();
}
INLINE ostream &
operator << (ostream &out, const AnimControlCollection &collection) {
collection.output(out);

View File

@ -185,6 +185,7 @@ play_all() {
Controls::const_iterator ci;
for (ci = _controls.begin(); ci != _controls.end(); ++ci) {
(*ci)._control->play();
_last_started_control = (*ci)._control;
}
}
@ -198,6 +199,7 @@ play_all(int from, int to) {
Controls::const_iterator ci;
for (ci = _controls.begin(); ci != _controls.end(); ++ci) {
(*ci)._control->play(from, to);
_last_started_control = (*ci)._control;
}
}
@ -211,6 +213,7 @@ loop_all(bool restart) {
Controls::const_iterator ci;
for (ci = _controls.begin(); ci != _controls.end(); ++ci) {
(*ci)._control->loop(restart);
_last_started_control = (*ci)._control;
}
}
@ -224,6 +227,7 @@ loop_all(bool restart, int from, int to) {
Controls::const_iterator ci;
for (ci = _controls.begin(); ci != _controls.end(); ++ci) {
(*ci)._control->loop(restart, from, to);
_last_started_control = (*ci)._control;
}
}
@ -258,6 +262,7 @@ pose_all(int frame) {
Controls::const_iterator ci;
for (ci = _controls.begin(); ci != _controls.end(); ++ci) {
(*ci)._control->pose(frame);
_last_started_control = (*ci)._control;
}
}

View File

@ -74,6 +74,7 @@ PUBLISHED:
INLINE int get_frame() const;
INLINE int get_num_frames(const string &anim_name) const;
INLINE int get_num_frames() const;
INLINE bool is_playing(const string &anim_name) const;
INLINE bool is_playing() const;

View File

@ -28,6 +28,7 @@
#include "textNode.h"
#include "mouseAndKeyboard.h"
#include "mouseRecorder.h"
#include "throw_event.h"
LoaderOptions PandaFramework::_loader_options;
@ -747,6 +748,8 @@ do_frame() {
nassertr(_is_open, false);
DataGraphTraverser dg_trav;
dg_trav.traverse(_data_root.node());
throw_event("NewFrame");
_event_handler.process_events();
if (!_screenshot_text.is_empty()) {
@ -834,6 +837,7 @@ do_enable_default_keys() {
define_key("i", "invert (reverse) single-sided faces", event_i, this);
define_key("l", "toggle lighting", event_l, this);
define_key("c", "recenter view on object", event_c, this);
define_key("a", "toggle animation controls", event_a, this);
define_key("shift-c", "toggle collision surfaces", event_C, this);
define_key("shift-b", "report bounding volume", event_B, this);
define_key("shift-l", "list hierarchy", event_L, this);
@ -1025,6 +1029,23 @@ event_c(CPT_Event event, void *data) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_a
// Access: Public, Static
// Description: Default handler for a key: toggle the animation
// controls.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_a(CPT_Event event, void *data) {
if (event->get_num_parameters() == 1) {
EventParameter param = event->get_parameter(0);
WindowFramework *wf;
DCAST_INTO_V(wf, param.get_ptr());
wf->next_anim_control();
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_C
// Access: Public, Static

View File

@ -132,6 +132,7 @@ public:
static void event_i(CPT_Event, void *data);
static void event_l(CPT_Event, void *data);
static void event_c(CPT_Event, void *data);
static void event_a(CPT_Event, void *data);
static void event_C(CPT_Event, void *data);
static void event_B(CPT_Event, void *data);
static void event_L(CPT_Event, void *data);

View File

@ -63,6 +63,16 @@ get_camera(int n) const {
return _cameras[n];
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_anim_controls
// Access: Public
// Description: Returns the current state of the anim_controls flag.
////////////////////////////////////////////////////////////////////
INLINE bool WindowFramework::
get_anim_controls() const {
return _anim_controls_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_wireframe
// Access: Public

View File

@ -54,6 +54,7 @@
#include "loaderFileTypeRegistry.h"
#include "pnmImage.h"
#include "virtualFileSystem.h"
#include "string_utils.h"
// This is generated data for the standard texture we apply to the
// blue triangle.
@ -79,6 +80,8 @@ WindowFramework(PandaFramework *panda_framework) :
_got_keyboard = false;
_got_trackball = false;
_got_lights = false;
_anim_controls_enabled = false;
_anim_index = 0;
_wireframe_enabled = false;
_texture_enabled = true;
_two_sided_enabled = false;
@ -103,6 +106,8 @@ WindowFramework(const WindowFramework &copy, DisplayRegion *display_region) :
_got_keyboard = false;
_got_trackball = false;
_got_lights = false;
_anim_controls_enabled = false;
_anim_index = 0;
_wireframe_enabled = false;
_texture_enabled = true;
_two_sided_enabled = false;
@ -345,8 +350,8 @@ get_mouse() {
// from get_mouse() is actually a MouseWatcher, but since it
// presents the same interface as a Mouse, no one should mind.
// Another advantage to using a MouseWatcher is that it the PGTop
// of aspect2d likes it better.
// Another advantage to using a MouseWatcher is that the PGTop of
// aspect2d likes it better.
PT(MouseWatcher) mw = new MouseWatcher("watcher");
mw->set_display_region(_display_region_3d);
_mouse = mouse.attach_new_node(mw);
@ -674,6 +679,50 @@ loop_animations(int hierarchy_match_flags) {
_anim_controls.loop_all(true);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::next_anim_control
// Access: Public
// Description: Rotates the animation controls through all of the
// available animations. If the animation controls are
// not already enabled, enables them at sets to the
// first animation; if they are already enabled, steps
// to the next animation; if that is the last animation,
// disables the animation controls.
////////////////////////////////////////////////////////////////////
void WindowFramework::
next_anim_control() {
if (_anim_controls_enabled) {
destroy_anim_controls();
++_anim_index;
if (_anim_index >= _anim_controls.get_num_anims()) {
set_anim_controls(false);
} else {
create_anim_controls();
}
} else {
_anim_index = 0;
set_anim_controls(true);
}
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::set_anim_controls
// Access: Public
// Description: Creates an onscreen animation slider for
// frame-stepping through the animations.
////////////////////////////////////////////////////////////////////
void WindowFramework::
set_anim_controls(bool enable) {
_anim_controls_enabled = enable;
if (_anim_controls_enabled) {
create_anim_controls();
} else {
destroy_anim_controls();
}
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::split_window
// Access: Public
@ -1060,3 +1109,121 @@ load_image_as_model(const Filename &filename) {
return card_node.p();
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::create_anim_controls
// Access: Private
// Description: Creates an onscreen animation slider for
// frame-stepping through the animations.
////////////////////////////////////////////////////////////////////
void WindowFramework::
create_anim_controls() {
destroy_anim_controls();
AnimControl *control = _anim_controls.get_anim(_anim_index);
nassertv(control != (AnimControl *)NULL);
PT(PGItem) group = new PGItem("anim_controls_group");
PGFrameStyle style;
style.set_type(PGFrameStyle::T_flat);
style.set_color(0.0f, 0.0f, 0.0f, 0.3f);
group->set_frame(-1.0f, 1.0f, 0.0f, 0.2f);
group->set_frame_style(0, style);
group->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
group->set_active(true);
_anim_controls_group = get_aspect_2d().attach_new_node(group);
_anim_controls_group.set_pos(0.0f, 0.0f, -0.9f);
if (_anim_index >= _anim_controls.get_num_anims()) {
PT(TextNode) label = new TextNode("label");
label->set_align(TextNode::A_center);
label->set_text("No animation.");
NodePath tnp = _anim_controls_group.attach_new_node(label);
tnp.set_pos(0.0f, 0.0f, 0.07f);
tnp.set_scale(0.1f);
return;
}
PT(TextNode) label = new TextNode("anim_name");
label->set_align(TextNode::A_left);
label->set_text(_anim_controls.get_anim_name(_anim_index));
NodePath tnp = _anim_controls_group.attach_new_node(label);
tnp.set_pos(-1.0f, 0.0f, 0.15f);
tnp.set_scale(0.05f);
_anim_slider = new PGSliderBar("anim_slider");
_anim_slider->setup_slider(false, 1.8f, 0.1f, 0.01f);
_anim_slider->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
_anim_slider->get_thumb_button()->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
_anim_slider->set_range(0.0f, (float)(control->get_num_frames() - 1));
_anim_slider->set_scroll_size(0.0f);
_anim_slider->set_page_size(1.0f);
NodePath snp = _anim_controls_group.attach_new_node(_anim_slider);
snp.set_pos(0.0f, 0.0f, 0.06f);
_frame_number = new TextNode("frame_number");
_frame_number->set_text_color(0.0f, 0.0f, 0.0f, 1.0f);
_frame_number->set_align(TextNode::A_center);
_frame_number->set_text(format_string(control->get_frame()));
NodePath fnp = NodePath(_anim_slider->get_thumb_button()).attach_new_node(_frame_number);
fnp.set_scale(0.05f);
fnp.set_pos(0.0f, 0.0f, -0.01f);
_panda_framework->get_event_handler().add_hook("NewFrame", st_update_anim_controls, (void *)this);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::destroy_anim_controls
// Access: Private
// Description: Removes the previously-created anim controls, if any.
////////////////////////////////////////////////////////////////////
void WindowFramework::
destroy_anim_controls() {
if (!_anim_controls_group.is_empty()) {
_anim_controls_group.remove_node();
_panda_framework->get_event_handler().remove_hook("NewFrame", st_update_anim_controls, (void *)this);
if (_anim_index < _anim_controls.get_num_anims()) {
AnimControl *control = _anim_controls.get_anim(_anim_index);
nassertv(control != (AnimControl *)NULL);
control->loop(false);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::update_anim_controls
// Access: Private
// Description: A per-frame callback to update the anim slider for
// the current frame.
////////////////////////////////////////////////////////////////////
void WindowFramework::
update_anim_controls() {
AnimControl *control = _anim_controls.get_anim(_anim_index);
nassertv(control != (AnimControl *)NULL);
if (_anim_slider->is_button_down()) {
control->pose((int)(_anim_slider->get_value() + 0.5));
} else {
_anim_slider->set_value((float)control->get_frame());
}
_frame_number->set_text(format_string(control->get_frame()));
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::st_update_anim_controls
// Access: Private, Static
// Description: The static event handler function.
////////////////////////////////////////////////////////////////////
void WindowFramework::
st_update_anim_controls(CPT_Event, void *data) {
WindowFramework *self = (WindowFramework *)data;
self->update_anim_controls();
}

View File

@ -33,6 +33,8 @@
#include "typedWritableReferenceCount.h"
#include "graphicsWindow.h"
#include "loaderOptions.h"
#include "pgSliderBar.h"
#include "textNode.h"
class PandaFramework;
class AmbientLight;
@ -92,6 +94,9 @@ public:
void loop_animations(int hierarchy_match_flags =
PartGroup::HMF_ok_part_extra |
PartGroup::HMF_ok_anim_extra);
void next_anim_control();
void set_anim_controls(bool enable);
INLINE bool get_anim_controls() const;
enum BackgroundType {
BT_other = 0,
@ -129,6 +134,10 @@ protected:
private:
PT(PandaNode) load_image_as_model(const Filename &filename);
void create_anim_controls();
void destroy_anim_controls();
void update_anim_controls();
static void st_update_anim_controls(CPT_Event, void *data);
private:
PandaFramework *_panda_framework;
@ -143,7 +152,13 @@ private:
NodePath _render;
NodePath _render_2d;
NodePath _aspect_2d;
AnimControlCollection _anim_controls;
bool _anim_controls_enabled;
int _anim_index;
NodePath _anim_controls_group;
PT(PGSliderBar) _anim_slider;
PT(TextNode) _frame_number;
NodePath _mouse;
PT(Trackball) _trackball;

View File

@ -103,7 +103,8 @@ get_click_event(const ButtonHandle &button) const {
////////////////////////////////////////////////////////////////////
// Function: PGButton::is_button_down
// Access: Published
// Description: Returns if the value of button_down
// Description: Returns true if the user is currently holding the
// mouse button down on the button, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool PGButton::
is_button_down() {

View File

@ -196,9 +196,9 @@ get_value() const {
////////////////////////////////////////////////////////////////////
INLINE void PGSliderBar::
set_ratio(float ratio) {
_ratio = max(min(ratio, 1.0f), 0.0f);
_needs_reposition = true;
adjust();
if (!is_button_down()) {
internal_set_ratio(ratio);
}
}
////////////////////////////////////////////////////////////////////
@ -212,6 +212,20 @@ get_ratio() const {
return _ratio;
}
////////////////////////////////////////////////////////////////////
// Function: PGSliderBar::is_button_down
// Access: Published
// Description: Returns true if the user is currently holding down
// the mouse button to manipulate the slider. When
// true, calls to set_ratio() or set_value() will have
// no effect.
////////////////////////////////////////////////////////////////////
INLINE bool PGSliderBar::
is_button_down() const {
return _dragging || _mouse_button_page ||
(_scroll_button_held != (PGItem *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: PGSliderBar::set_resize_thumb
// Access: Published
@ -433,3 +447,17 @@ INLINE string PGSliderBar::
get_adjust_event() const {
return get_adjust_prefix() + get_id();
}
////////////////////////////////////////////////////////////////////
// Function: PGSliderBar::internal_set_ratio
// Access: Private
// Description: Sets the current value of the slider, expressed in
// the range 0 .. 1, without checking whether the user
// is currently manipulating the slider.
////////////////////////////////////////////////////////////////////
INLINE void PGSliderBar::
internal_set_ratio(float ratio) {
_ratio = max(min(ratio, 1.0f), 0.0f);
_needs_reposition = true;
adjust();
}

View File

@ -713,10 +713,10 @@ reposition() {
void PGSliderBar::
advance_scroll() {
if (_scroll_button_held == _left_button) {
set_ratio(max(_ratio - _scroll_ratio, 0.0f));
internal_set_ratio(max(_ratio - _scroll_ratio, 0.0f));
} else if (_scroll_button_held == _right_button) {
set_ratio(min(_ratio + _scroll_ratio, 1.0f));
internal_set_ratio(min(_ratio + _scroll_ratio, 1.0f));
}
_next_advance_time =
@ -744,7 +744,7 @@ advance_page() {
} else {
t = min(_ratio + _page_ratio - _scroll_ratio, target_ratio);
}
set_ratio(t);
internal_set_ratio(t);
if (t == target_ratio) {
// We made it; begin dragging from now on until the user releases
// the mouse.
@ -786,7 +786,7 @@ continue_drag() {
}
if (_range_x != 0.0f) {
float current_x = mouse_to_local(_mouse_pos).dot(_axis);
set_ratio((current_x - _drag_start_x) / _range_x);
internal_set_ratio((current_x - _drag_start_x) / _range_x);
}
}

View File

@ -81,6 +81,8 @@ PUBLISHED:
INLINE void set_ratio(float ratio);
INLINE float get_ratio() const;
INLINE bool is_button_down() const;
INLINE void set_resize_thumb(bool resize_thumb);
INLINE bool get_resize_thumb() const;
@ -118,6 +120,8 @@ protected:
virtual void item_move(PGItem *item, const MouseWatcherParameter &param);
private:
INLINE void internal_set_ratio(float ratio);
void reposition();
void advance_scroll();
void advance_page();

View File

@ -213,7 +213,8 @@ help() {
" -a\n"
" Convert and play animations, if loading an external file type\n"
" (like .mb) directly and if the converter supports animations.\n\n"
" (like .mb) directly and if the converter supports animations.\n"
" Also implicitly enables the animation controls.\n\n"
" -c\n"
" Automatically center models within the viewing window on startup.\n"
@ -252,6 +253,7 @@ main(int argc, char *argv[]) {
framework.open_framework(argc, argv);
framework.set_window_title("Panda Viewer");
bool anim_controls = false;
bool auto_center = false;
bool show_loading = false;
bool auto_screenshot = false;
@ -267,6 +269,7 @@ main(int argc, char *argv[]) {
while (flag != EOF) {
switch (flag) {
case 'a':
anim_controls = true;
PandaFramework::_loader_options.set_flags(PandaFramework::_loader_options.get_flags() | LoaderOptions::LF_convert_anim);
break;
@ -353,6 +356,10 @@ main(int argc, char *argv[]) {
return(output_screenshot(screenshotfn) ? 0:1);
}
if (anim_controls) {
window->set_anim_controls(true);
}
framework.enable_default_keys();
framework.define_key("shift-w", "open a new window", event_W, NULL);
framework.define_key("shift-f", "flatten hierarchy", event_F, NULL);