Browse Source

lots of improvements to the rocket integration

rdb 14 years ago
parent
commit
1168011850

+ 0 - 11
panda/src/display/displayRegion.I

@@ -512,17 +512,6 @@ get_draw_region_pcollector() {
   return _draw_region_pcollector;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::pixel_size_changed
-//       Access: Private, Virtual
-//  Description: Called when the size in pixels of this region
-//               has changed.  Also called the first time the
-//               pixel size is known.
-////////////////////////////////////////////////////////////////////
-INLINE void DisplayRegion::
-pixel_size_changed(int x_size, int y_size) {
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::CDataCull::Constructor
 //       Access: Public

+ 0 - 6
panda/src/display/displayRegion.cxx

@@ -762,12 +762,6 @@ do_compute_pixels(int x_size, int y_size, CData *cdata) {
     cdata->_pbi = int(((1.0f - cdata->_dimensions[2]) * y_size) + 0.5);
     cdata->_pti = int(((1.0f - cdata->_dimensions[3]) * y_size) + 0.5);
   }
-
-  int w = cdata->_pr - cdata->_pl;
-  int h = cdata->_pt - cdata->_pb;
-  if (old_w != w || old_h != h) {
-    pixel_size_changed(w, h);
-  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 1
panda/src/display/displayRegion.h

@@ -162,7 +162,6 @@ private:
   void win_display_regions_changed();
   void do_compute_pixels(int x_size, int y_size, CData *cdata);
   void set_active_index(int index);
-  INLINE virtual void pixel_size_changed(int x_size, int y_size);
 
 protected:
   virtual void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,

+ 2 - 0
panda/src/rocket/rocketFileInterface.cxx

@@ -35,6 +35,8 @@ RocketFileInterface(VirtualFileSystem *vfs) : _vfs(vfs) {
 ////////////////////////////////////////////////////////////////////
 Rocket::Core::FileHandle RocketFileInterface::
 Open(const Rocket::Core::String& path) {
+  rocket_cat.debug() << "Opening " << path.CString() << "\n";
+
   // A FileHandle is actually just a void pointer
   return (Rocket::Core::FileHandle)
     _vfs->open_read_file(Filename::from_os_specific(path.CString()), true);

+ 130 - 45
panda/src/rocket/rocketInputHandler.cxx

@@ -50,6 +50,83 @@ RocketInputHandler::
 ~RocketInputHandler() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RocketInputHandler::get_rocket_key
+//       Access: Published
+//  Description: Returns the libRocket KeyIdentifier for the given
+//               ButtonHandle, or KI_UNKNOWN (0) if it wasn't known.
+////////////////////////////////////////////////////////////////////
+int RocketInputHandler::
+get_rocket_key(const ButtonHandle handle) {
+  static pmap<int, int> keymap;
+  pmap<int, int>::const_iterator it;
+
+  if (keymap.size() > 0) {
+    it = keymap.find(handle.get_index());
+
+    if (it == keymap.end()) {
+      return 0;
+    } else {
+      return it->second;
+    }
+  }
+
+  keymap[KeyboardButton::space().get_index()]        = KI_SPACE;
+  keymap[KeyboardButton::backspace().get_index()]    = KI_BACK;
+  keymap[KeyboardButton::tab().get_index()]          = KI_TAB;
+  keymap[KeyboardButton::enter().get_index()]        = KI_RETURN;
+  keymap[KeyboardButton::escape().get_index()]       = KI_ESCAPE;
+  keymap[KeyboardButton::end().get_index()]          = KI_END;
+  keymap[KeyboardButton::home().get_index()]         = KI_HOME;
+  keymap[KeyboardButton::left().get_index()]         = KI_LEFT;
+  keymap[KeyboardButton::up().get_index()]           = KI_UP;
+  keymap[KeyboardButton::right().get_index()]        = KI_RIGHT;
+  keymap[KeyboardButton::down().get_index()]         = KI_DOWN;
+  keymap[KeyboardButton::insert().get_index()]       = KI_INSERT;
+  keymap[KeyboardButton::del().get_index()]          = KI_DELETE;
+  keymap[KeyboardButton::caps_lock().get_index()]    = KI_CAPITAL;
+  keymap[KeyboardButton::f1().get_index()]           = KI_F1;
+  keymap[KeyboardButton::f10().get_index()]          = KI_F10;
+  keymap[KeyboardButton::f11().get_index()]          = KI_F11;
+  keymap[KeyboardButton::f12().get_index()]          = KI_F12;
+  keymap[KeyboardButton::f13().get_index()]          = KI_F13;
+  keymap[KeyboardButton::f14().get_index()]          = KI_F14;
+  keymap[KeyboardButton::f15().get_index()]          = KI_F15;
+  keymap[KeyboardButton::f16().get_index()]          = KI_F16;
+  keymap[KeyboardButton::f2().get_index()]           = KI_F2;
+  keymap[KeyboardButton::f3().get_index()]           = KI_F3;
+  keymap[KeyboardButton::f4().get_index()]           = KI_F4;
+  keymap[KeyboardButton::f5().get_index()]           = KI_F5;
+  keymap[KeyboardButton::f6().get_index()]           = KI_F6;
+  keymap[KeyboardButton::f7().get_index()]           = KI_F7;
+  keymap[KeyboardButton::f8().get_index()]           = KI_F8;
+  keymap[KeyboardButton::f9().get_index()]           = KI_F9;
+  keymap[KeyboardButton::help().get_index()]         = KI_HELP;
+  keymap[KeyboardButton::lcontrol().get_index()]     = KI_LCONTROL;
+  keymap[KeyboardButton::lshift().get_index()]       = KI_LSHIFT;
+  keymap[KeyboardButton::num_lock().get_index()]     = KI_NUMLOCK;
+  keymap[KeyboardButton::page_down().get_index()]    = KI_NEXT;
+  keymap[KeyboardButton::page_up().get_index()]      = KI_PRIOR;
+  keymap[KeyboardButton::pause().get_index()]        = KI_PAUSE;
+  keymap[KeyboardButton::print_screen().get_index()] = KI_SNAPSHOT;
+  keymap[KeyboardButton::rcontrol().get_index()]     = KI_RCONTROL;
+  keymap[KeyboardButton::rshift().get_index()]       = KI_RSHIFT;
+  keymap[KeyboardButton::scroll_lock().get_index()]  = KI_SCROLL;
+
+  for (char c = 'a'; c <= 'z'; ++c) {
+    keymap[KeyboardButton::ascii_key(c).get_index()] = (c - 'a') + KI_A;
+  }
+  for (char c = '0'; c <= '9'; ++c) {
+    keymap[KeyboardButton::ascii_key(c).get_index()] = (c - '0') + KI_0;
+  }
+
+  it = keymap.find(handle.get_index());
+  if (it != keymap.end()) {
+    return it->second;
+  }
+  return 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RocketInputHandler::do_transmit_data
 //       Access: Protected, Virtual
@@ -92,6 +169,8 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
     for (int i = 0; i < num_events; i++) {
       const ButtonEvent &be = this_button_events->get_event(i);
 
+      int rocket_key = KI_UNKNOWN;
+
       switch (be._type) {
       case ButtonEvent::T_down:
         if (be._button == KeyboardButton::control()) {
@@ -107,10 +186,30 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
           _wheel_delta -= 1;
         } else if (be._button == MouseButton::wheel_down()) {
           _wheel_delta += 1;
+
+        } else if (be._button == MouseButton::one()) {
+          _mouse_buttons[0] = true;
+        } else if (be._button == MouseButton::two()) {
+          _mouse_buttons[1] = true;
+        } else if (be._button == MouseButton::three()) {
+          _mouse_buttons[2] = true;
+        } else if (be._button == MouseButton::four()) {
+          _mouse_buttons[3] = true;
+        } else if (be._button == MouseButton::five()) {
+          _mouse_buttons[4] = true;
+        }
+
+        rocket_key = get_rocket_key(be._button);
+        if (rocket_key != KI_UNKNOWN) {
+          _keys[rocket_key] = true;
         }
         break;
 
       case ButtonEvent::T_repeat:
+        rocket_key = get_rocket_key(be._button);
+        if (rocket_key != KI_UNKNOWN) {
+          _repeated_keys.push_back(rocket_key);
+        }
         break;
 
       case ButtonEvent::T_up:
@@ -122,11 +221,30 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
           _modifiers &= ~KM_ALT;
         } else if (be._button == KeyboardButton::meta()) {
           _modifiers &= ~KM_META;
+
+        } else if (be._button == MouseButton::one()) {
+          _mouse_buttons[0] = false;
+        } else if (be._button == MouseButton::two()) {
+          _mouse_buttons[1] = false;
+        } else if (be._button == MouseButton::three()) {
+          _mouse_buttons[2] = false;
+        } else if (be._button == MouseButton::four()) {
+          _mouse_buttons[3] = false;
+        } else if (be._button == MouseButton::five()) {
+          _mouse_buttons[4] = false;
+        }
+
+        rocket_key = get_rocket_key(be._button);
+        if (rocket_key != KI_UNKNOWN) {
+          _keys[rocket_key] = false;
         }
         break;
 
       case ButtonEvent::T_keystroke:
-        _text_input.push_back(be._keycode);
+        // Ignore control characters; otherwise, they actually get added to strings in the UI.
+        if (be._keycode > 0x1F and (be._keycode < 0x7F or be._keycode > 0x9F)) {
+          _text_input.push_back(be._keycode);
+        }
         break;
 
       case ButtonEvent::T_resume_down:
@@ -135,49 +253,6 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
       case ButtonEvent::T_move:
         break;
       }
-
-      bool down = (be._type == ButtonEvent::T_down);
-      if (down || be._type == ButtonEvent::T_up) {
-        if (be._button == MouseButton::one()) {
-          _mouse_buttons[1] = down;
-        } else if (be._button == MouseButton::two()) {
-          _mouse_buttons[2] = down;
-        } else if (be._button == MouseButton::three()) {
-          _mouse_buttons[3] = down;
-        } else if (be._button == MouseButton::four()) {
-          _mouse_buttons[4] = down;
-        } else if (be._button == MouseButton::five()) {
-          _mouse_buttons[5] = down;
-
-        // In the order they are specified in Rocket/Core/Input.h
-        } else if (be._button == KeyboardButton::space()) {
-          _keys[KI_SPACE] = down;
-        } else if (be._button == KeyboardButton::backspace()) {
-          _keys[KI_BACK] = down;
-        } else if (be._button == KeyboardButton::tab()) {
-          _keys[KI_TAB] = down;
-        } else if (be._button == KeyboardButton::enter()) {
-          _keys[KI_RETURN] = down;
-        } else if (be._button == KeyboardButton::escape()) {
-          _keys[KI_ESCAPE] = down;
-        } else if (be._button == KeyboardButton::end()) {
-          _keys[KI_END] = down;
-        } else if (be._button == KeyboardButton::home()) {
-          _keys[KI_HOME] = down;
-        } else if (be._button == KeyboardButton::left()) {
-          _keys[KI_LEFT] = down;
-        } else if (be._button == KeyboardButton::up()) {
-          _keys[KI_UP] = down;
-        } else if (be._button == KeyboardButton::right()) {
-          _keys[KI_RIGHT] = down;
-        } else if (be._button == KeyboardButton::down()) {
-          _keys[KI_DOWN] = down;
-        } else if (be._button == KeyboardButton::insert()) {
-          _keys[KI_INSERT] = down;
-        } else if (be._button == KeyboardButton::del()) {
-          _keys[KI_DELETE] = down;
-        }
-      }
     }
   }
 }
@@ -226,7 +301,17 @@ update_context(Rocket::Core::Context *context, int xoffs, int yoffs) {
         context->ProcessKeyUp((KeyIdentifier) it->first, _modifiers);
       }
     }
-    _mouse_buttons.clear();
+    _keys.clear();
+  }
+
+  if (_repeated_keys.size() > 0) {
+    pvector<int>::const_iterator it;
+
+    for (it = _repeated_keys.begin(); it != _repeated_keys.end(); ++it) {
+      context->ProcessKeyUp((KeyIdentifier) *it, _modifiers);
+      context->ProcessKeyDown((KeyIdentifier) *it, _modifiers);
+    }
+    _repeated_keys.clear();
   }
 
   if (_text_input.size() > 0) {

+ 5 - 1
panda/src/rocket/rocketInputHandler.h

@@ -17,12 +17,13 @@
 
 #include "config_rocket.h"
 #include "dataNode.h"
+#include "buttonHandle.h"
 
 namespace Rocket {
   namespace Core {
     class Context;
   }
-};
+}
 
 ////////////////////////////////////////////////////////////////////
 //       Class : RocketInputHandler
@@ -34,6 +35,8 @@ PUBLISHED:
   RocketInputHandler(const string &name = string());
   virtual ~RocketInputHandler();
 
+  static int get_rocket_key(const ButtonHandle handle);
+
 public:
   void update_context(Rocket::Core::Context *context, int xoffs, int yoffs);
 
@@ -57,6 +60,7 @@ private:
   typedef pmap<int, bool> ButtonActivityMap;
   ButtonActivityMap _mouse_buttons;
   ButtonActivityMap _keys;
+  pvector<int> _repeated_keys;
   pvector<short> _text_input;
 
 public:

+ 4 - 3
panda/src/rocket/rocketRegion.I

@@ -48,9 +48,10 @@ make(const string &context_name, GraphicsOutput *window,
 //     Function: RocketRegion::get_context
 //       Access: Published
 //  Description: Returns a pointer to the Rocket context associated
-//               with this region.  Will only be valid as long as
-//               this region still exists, so be sure to toss it
-//               when you toss the region itself.
+//               with this region.  Does not increase the reference
+//               count, so if you want to preserve it for longer
+//               than this region exists, be sure to call
+//               AddReference() and RemoveReference() yourself.
 ////////////////////////////////////////////////////////////////////
 Rocket::Core::Context* RocketRegion::
 get_context() const {

+ 33 - 60
panda/src/rocket/rocketRegion.cxx

@@ -25,29 +25,25 @@ TypeHandle RocketRegion::_type_handle;
 //  Description: Make sure that context_name is unique.
 ////////////////////////////////////////////////////////////////////
 RocketRegion::
-RocketRegion(GraphicsOutput *window, const LVecBase4 &dimensions,
+RocketRegion(GraphicsOutput *window, const LVecBase4 &dr_dimensions,
              const string &context_name) :
-  DisplayRegion(window, dimensions),
-  _dimensions(0, 0) {
+  DisplayRegion(window, dr_dimensions) {
 
-  cerr << "rocket " << this << "\n";
-
-  if (window != (GraphicsOutput *)NULL && window->has_size()) {
-    _dimensions.x = (dimensions[1] - dimensions[0]) * window->get_fb_x_size();
-    _dimensions.y = (dimensions[3] - dimensions[2]) * window->get_fb_y_size();
-  }
+  int pl, pr, pb, pt;
+  get_pixels(pl, pr, pb, pt);
+  Rocket::Core::Vector2i dimensions (pr - pl, pt - pb);
 
   rocket_cat.debug()
     << "Setting initial context dimensions to ("
-    << _dimensions.x << ", " << _dimensions.y << ")\n";
+    << dimensions.x << ", " << dimensions.y << ")\n";
 
   _context = Rocket::Core::CreateContext(context_name.c_str(),
-                                         _dimensions, &_interface);
+                                         dimensions, &_interface);
   nassertv(_context != NULL);
 
   _lens = new OrthographicLens;
-  _lens->set_film_size(_dimensions.x, -_dimensions.y);
-  _lens->set_film_offset(_dimensions.x * 0.5, _dimensions.y * 0.5);
+  _lens->set_film_size(dimensions.x, -dimensions.y);
+  _lens->set_film_offset(dimensions.x * 0.5, dimensions.y * 0.5);
   _lens->set_near_far(-1, 1);
   set_camera(new Camera(context_name, _lens));
 }
@@ -66,7 +62,7 @@ RocketRegion::
     }
 
     // We need to do this because libRocket may call into Python
-    // code to throw events.
+    // code to throw destruction events.
 #ifdef HAVE_ROCKET_PYTHON
     PyGILState_STATE gstate;
     gstate = PyGILState_Ensure();
@@ -80,41 +76,6 @@ RocketRegion::
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: RocketRegion::pixel_size_changed
-//       Access: Private, Virtual
-//  Description: Called when the size in pixels of this region
-//               has changed.
-////////////////////////////////////////////////////////////////////
-void RocketRegion::
-pixel_size_changed(int x_size, int y_size) {
-  if (x_size == _dimensions.x && y_size == _dimensions.y) {
-    return;
-  }
-
-  // We need to do this because libRocket may call into Python
-  // code to throw events.
-#ifdef HAVE_ROCKET_PYTHON
-  PyGILState_STATE gstate;
-  gstate = PyGILState_Ensure();
-#endif
-
-  rocket_cat.debug() << "Setting context dimensions to ("
-                     << x_size << ", " << y_size << ")\n";
-
-  _dimensions.x = x_size;
-  _dimensions.y = y_size;
-
-  _context->SetDimensions(_dimensions);
-
-#ifdef HAVE_ROCKET_PYTHON
-  PyGILState_Release(gstate);
-#endif
-
-  _lens->set_film_size(_dimensions.x, -_dimensions.y);
-  _lens->set_film_offset(_dimensions.x * 0.5, _dimensions.y * 0.5);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: RocketRegion::do_cull
 //       Access: Protected, Virtual
@@ -126,31 +87,43 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
 
   PStatTimer timer(get_cull_region_pcollector(), current_thread);
 
-  CullTraverser *trav = get_cull_traverser();
-  trav->set_cull_handler(cull_handler);
-  trav->set_scene(scene_setup, gsg, get_incomplete_render());
-  trav->set_view_frustum(NULL);
-
-  // We need to do this because libRocket may call into Python
-  // code to throw events.
+  // We (unfortunately) need to do this because libRocket
+  // may call into Python code to throw events.
 #ifdef HAVE_ROCKET_PYTHON
   PyGILState_STATE gstate;
   gstate = PyGILState_Ensure();
 #endif
 
+  int pl, pr, pb, pt;
+  get_pixels(pl, pr, pb, pt);
+  Rocket::Core::Vector2i dimensions (pr - pl, pt - pb);
+
+  if (_context->GetDimensions() != dimensions) {
+    rocket_cat.debug() << "Setting context dimensions to ("
+      << dimensions.x << ", " << dimensions.y << ")\n";
+
+    _context->SetDimensions(dimensions);
+
+    _lens->set_film_size(dimensions.x, -dimensions.y);
+    _lens->set_film_offset(dimensions.x * 0.5, dimensions.y * 0.5);
+  }
+
   if (_input_handler != NULL) {
-    int pl, pr, pb, pt;
-    get_pixels(pl, pr, pb, pt);
     _input_handler->update_context(_context, pl, pb);
   } else {
     _context->Update();
   }
 
+  CullTraverser *trav = get_cull_traverser();
+  trav->set_cull_handler(cull_handler);
+  trav->set_scene(scene_setup, gsg, get_incomplete_render());
+  trav->set_view_frustum(NULL);
+
+  _interface.render(_context, trav);
+
 #ifdef HAVE_ROCKET_PYTHON
   PyGILState_Release(gstate);
 #endif
 
-  _interface.render(_context, trav);
-
   trav->end_traverse();
 }

+ 2 - 5
panda/src/rocket/rocketRegion.h

@@ -32,14 +32,12 @@ protected:
   RocketRegion(GraphicsOutput *window, const LVecBase4 &dimensions,
                const string &context_name);
 
-  virtual void pixel_size_changed(int x_size, int y_size);
   virtual void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
                        GraphicsStateGuardian *gsg, Thread *current_thread);
 
-public:
+PUBLISHED:
   virtual ~RocketRegion();
 
-PUBLISHED:
   INLINE static RocketRegion* make(const string &context_name,
                                    GraphicsOutput *window);
   INLINE static RocketRegion* make(const string &context_name,
@@ -58,8 +56,7 @@ PUBLISHED:
 private:
   RocketRenderInterface _interface;
   Rocket::Core::Context* _context;
-  Rocket::Core::Vector2i _dimensions;
-  OrthographicLens* _lens;
+  PT(OrthographicLens) _lens;
   PT(RocketInputHandler) _input_handler;
 
 public:

+ 11 - 6
panda/src/rocket/rocketRegion_ext.I

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "rocketRegion.h"
+#include <Rocket/Core/Context.h>
 
 #ifndef CPPPARSER
 #undef this
@@ -31,14 +32,18 @@
 ////////////////////////////////////////////////////////////////////
 PyObject* EXT_CONST_METHOD(RocketRegion,
 get_context) {
-  python::object py_context;
-
   try {
     Rocket::Core::Context* context = _ext_this->get_context();
-    py_context = Rocket::Core::Python::Utilities::MakeObject(context);
+    python::object py_context = Rocket::Core::Python::Utilities::MakeObject(context);
+
+    // Make sure the context won't be destroyed before both the Python
+    // references and the C++ references to it are completely gone.
+    Py_INCREF(py_context.ptr());
+    context->AddReference();
+    return py_context.ptr();
+
   } catch (const python::error_already_set& e) {
-    return NULL;
+    // Return NULL, which will trigger the exception in Python
   }
-
-  return py_context.ptr();
+  return NULL;
 }

+ 21 - 11
panda/src/rocket/rocketRenderInterface.cxx

@@ -20,13 +20,14 @@
 #include "internalName.h"
 #include "geomVertexWriter.h"
 #include "geomTriangles.h"
-#include "texture.h"
-#include "textureAttrib.h"
-#include "texturePool.h"
 #include "colorBlendAttrib.h"
 #include "cullBinAttrib.h"
 #include "depthTestAttrib.h"
 #include "depthWriteAttrib.h"
+#include "scissorAttrib.h"
+#include "texture.h"
+#include "textureAttrib.h"
+#include "texturePool.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: RocketRenderInterface::render
@@ -39,11 +40,6 @@ render(Rocket::Core::Context* context, CullTraverser *trav) {
   nassertv(context != NULL);
   MutexHolder holder(_lock);
 
-  const Rocket::Core::Vector2i &dimensions = context->GetDimensions();
-  //CPT(TransformState) scale = TransformState::make_scale(
-  //  LVector3::right() * (1.0 / dimensions.x) +
-  //  LVector3::down()  * (1.0 / dimensions.y));
-
   _trav = trav;
   _net_transform = trav->get_world_transform();
   _net_state = RenderState::make(
@@ -55,6 +51,7 @@ render(Rocket::Core::Context* context, CullTraverser *trav) {
       ColorBlendAttrib::O_one_minus_incoming_alpha
     )
   );
+  _dimensions = context->GetDimensions();
 
   context->Render();
 
@@ -114,9 +111,17 @@ void RocketRenderInterface::
 render_geom(const Geom* geom, const RenderState* state, const Rocket::Core::Vector2f& translation) {
   LVector3 offset = LVector3::right() * translation.x + LVector3::up() * translation.y;
 
-  rocket_cat.spam()
-    << "Rendering geom " << geom << " with state "
-    << *state << " and translation " << offset << "\n";
+  if (_enable_scissor) {
+    state = state->add_attrib(ScissorAttrib::make(_scissor));
+    rocket_cat.spam()
+      << "Rendering geom " << geom << " with state "
+      << *state << ", translation (" << offset << "), "
+      << "scissor region (" << _scissor << ")\n";
+  } else {
+    rocket_cat.spam()
+      << "Rendering geom " << geom << " with state "
+      << *state << ", translation (" << offset << ")\n";
+  }
 
   CPT(TransformState) net_transform, modelview_transform;
   net_transform = _net_transform->compose(TransformState::make_pos(offset));
@@ -289,6 +294,7 @@ ReleaseTexture(Rocket::Core::TextureHandle texture_handle) {
 ////////////////////////////////////////////////////////////////////
 void RocketRenderInterface::
 EnableScissorRegion(bool enable) {
+  _enable_scissor = enable;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -299,4 +305,8 @@ EnableScissorRegion(bool enable) {
 ////////////////////////////////////////////////////////////////////
 void RocketRenderInterface::
 SetScissorRegion(int x, int y, int width, int height) {
+  _scissor[0] = x / (PN_stdfloat) _dimensions.x;
+  _scissor[1] = (x + width) / (PN_stdfloat) _dimensions.x;
+  _scissor[2] = 1.0f - ((y + height) / (PN_stdfloat) _dimensions.y);
+  _scissor[3] = 1.0f - (y / (PN_stdfloat) _dimensions.y);
 }

+ 10 - 0
panda/src/rocket/rocketRenderInterface.h

@@ -24,6 +24,11 @@
 
 #include <Rocket/Core/RenderInterface.h>
 
+////////////////////////////////////////////////////////////////////
+//       Class : RocketRenderInterface
+// Description : Class that provides the main render interface for
+//               libRocket integration.
+////////////////////////////////////////////////////////////////////
 class RocketRenderInterface : public Rocket::Core::RenderInterface {
 public:
   void render(Rocket::Core::Context* context, CullTraverser *trav);
@@ -56,10 +61,15 @@ protected:
 private:
   Mutex _lock;
 
+  // Hold the scissor settings and whether or not to enable scissoring.
+  bool _enable_scissor;
+  LVecBase4f _scissor;
+
   // These are temporarily filled in by render().
   CullTraverser *_trav;
   CPT(TransformState) _net_transform;
   CPT(RenderState) _net_state;
+  Rocket::Core::Vector2i _dimensions;
 };
 
 #endif