diff --git a/samples/rocket-console/assets/Perfect DOS VGA 437.ttf b/samples/rocket-console/assets/Perfect DOS VGA 437.ttf
new file mode 100644
index 0000000000..f5cbfc06fd
Binary files /dev/null and b/samples/rocket-console/assets/Perfect DOS VGA 437.ttf differ
diff --git a/samples/rocket-console/assets/console.rcss b/samples/rocket-console/assets/console.rcss
new file mode 100755
index 0000000000..b1df4879f5
--- /dev/null
+++ b/samples/rocket-console/assets/console.rcss
@@ -0,0 +1,38 @@
+body
+{
+ font-family: "Perfect DOS VGA 437";
+ font-weight: normal;
+ font-style: normal;
+
+ // use all the allocated texture space
+ min-width: 100%;
+ min-height: 100%;
+
+ background-color: #000;
+}
+
+
+text#content
+{
+ z-index: 2;
+ font-size: 30px;
+
+ white-space: pre-wrap;
+
+ margin: auto;
+
+ text-align: left;
+ position: absolute;
+
+ // account for non-proportionality of our 1024x512
+ // buffer compared with VGA font proportions and
+ // wanting to center the screen with 40 columns
+ top: 16px;
+ left: 32px;
+
+ width: 100%;
+ height: 100%;
+
+ color: #888;
+
+}
diff --git a/samples/rocket-console/assets/console.rml b/samples/rocket-console/assets/console.rml
new file mode 100755
index 0000000000..7887f4ef7c
--- /dev/null
+++ b/samples/rocket-console/assets/console.rml
@@ -0,0 +1,11 @@
+
+
+
+ Administrative Console
+
+
+
+
+
+
+
diff --git a/samples/rocket-console/assets/dos437.txt b/samples/rocket-console/assets/dos437.txt
new file mode 100644
index 0000000000..614d29885e
--- /dev/null
+++ b/samples/rocket-console/assets/dos437.txt
@@ -0,0 +1 @@
+from www.dafont.com/perfect-dos-vga-437.font (info at http://zehfernando.com/2015/revisiting-vga-fonts/)
\ No newline at end of file
diff --git a/samples/rocket-console/assets/loading.rml b/samples/rocket-console/assets/loading.rml
new file mode 100755
index 0000000000..c85a5d3bed
--- /dev/null
+++ b/samples/rocket-console/assets/loading.rml
@@ -0,0 +1,54 @@
+
+
+ Main Menu
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/rocket-console/assets/modenine.nfo b/samples/rocket-console/assets/modenine.nfo
new file mode 100644
index 0000000000..c6af4f1f8b
--- /dev/null
+++ b/samples/rocket-console/assets/modenine.nfo
@@ -0,0 +1,18 @@
+ModeNine
+
+Based on Andrew Bulhak's ModeSeven, in turn inspired by the screen
+output of the BBC Micro.
+
+copyright:
+(C) 1998 Andrew C. Bulhak
+(C) 2001 Graham H Freeman
+
+Freely Distributable.
+
+All we ask is that this readme file must be included with the font package.
+Impresarios of free font sites and shovelware cd-roms, this means you!
+
+If you think this font is doovy, let us know at fonts@grudnuk.com, and we
+might actually make more fonts.
+
+Another fine Grudnuk Creations produkt | http://grudnuk.com/
\ No newline at end of file
diff --git a/samples/rocket-console/assets/modenine.ttf b/samples/rocket-console/assets/modenine.ttf
new file mode 100644
index 0000000000..c0b00462d7
Binary files /dev/null and b/samples/rocket-console/assets/modenine.ttf differ
diff --git a/samples/rocket-console/assets/monitor.egg.pz b/samples/rocket-console/assets/monitor.egg.pz
new file mode 100644
index 0000000000..9c9f3675fd
Binary files /dev/null and b/samples/rocket-console/assets/monitor.egg.pz differ
diff --git a/samples/rocket-console/assets/monitor.txt b/samples/rocket-console/assets/monitor.txt
new file mode 100644
index 0000000000..f2e1f7265e
--- /dev/null
+++ b/samples/rocket-console/assets/monitor.txt
@@ -0,0 +1,12 @@
+
+This is an edited version of this file from blendswap.com (http://www.blendswap.com/blends/view/74468).
+
+VERY IMPORTANT LICENSE INFORMATION:
+
+This file has been released by buzo under the following license:
+
+ Creative Commons Zero (Public Domain)
+
+You can use this model for any purposes according to the following conditions:
+
+ There are no requirements for CC-Zero licensed blends.
\ No newline at end of file
diff --git a/samples/rocket-console/assets/rkt.rcss b/samples/rocket-console/assets/rkt.rcss
new file mode 100755
index 0000000000..ebc49f50fb
--- /dev/null
+++ b/samples/rocket-console/assets/rkt.rcss
@@ -0,0 +1,44 @@
+/*
+* Default styles for all the basic elements.
+*/
+
+div
+{
+ display: block;
+}
+
+p
+{
+ display: block;
+}
+
+h1
+{
+ display: block;
+}
+
+em
+{
+ font-style: italic;
+}
+
+strong
+{
+ font-weight: bold;
+}
+
+datagrid
+{
+ display: block;
+}
+
+select, dataselect, datacombo
+{
+ text-align: left;
+}
+
+tabset tabs
+{
+ display: block;
+}
+
diff --git a/samples/rocket-console/assets/takeyga_kb.egg b/samples/rocket-console/assets/takeyga_kb.egg
new file mode 100644
index 0000000000..3085947839
--- /dev/null
+++ b/samples/rocket-console/assets/takeyga_kb.egg
@@ -0,0 +1,316 @@
+ { Z-up }
+ takeyga_kb {
+ diffr { 0.800000 }
+ diffg { 0.800000 }
+ diffb { 0.800000 }
+ specr { 0.500000 }
+ specg { 0.500000 }
+ specb { 0.500000 }
+ shininess { 12.5 }
+ ambr { 1.000000 }
+ ambg { 1.000000 }
+ ambb { 1.000000 }
+ emitr { 0.000000 }
+ emitg { 0.000000 }
+ emitb { 0.000000 }
+}
+
+ Texture.001 {
+ "./tex/takeyga_kb_specular.dds"
+ envtype { MODULATE }
+ minfilter { LINEAR_MIPMAP_LINEAR }
+ magfilter { LINEAR_MIPMAP_LINEAR }
+ wrap { REPEAT }
+}
+
+ Tex {
+ "./tex/takeyga_kb_diffuse.dds"
+ envtype { MODULATE }
+ minfilter { LINEAR_MIPMAP_LINEAR }
+ magfilter { LINEAR_MIPMAP_LINEAR }
+ wrap { REPEAT }
+}
+
+ Texture {
+ "./tex/takeyga_kb_normal.dds"
+ envtype { NORMAL }
+ minfilter { LINEAR_MIPMAP_LINEAR }
+ magfilter { LINEAR_MIPMAP_LINEAR }
+ wrap { REPEAT }
+}
+
+ Cube.001 {
+ {
+ {
+ 0.08499996364116669 0.0 0.0 0.0
+ 0.0 0.23999987542629242 0.0 0.0
+ 0.0 0.0 0.02500000037252903 0.0
+ 0.0 0.0 0.0 1.0
+ }
+ }
+
+ Cube.001 {
+
+ 0 {0.082953 0.240000 -0.025000
+ {
+ 0.158203125 0.595703125
+ }
+ }
+ 1 {0.082953 -0.240000 -0.025000
+ {
+ 0.98828125 0.6015625
+ }
+ }
+ 2 {-0.085000 -0.240000 -0.025000
+ {
+ 0.98828125 0.986328125
+ }
+ }
+ 3 {-0.085000 0.240000 -0.025000
+ {
+ 0.162109375 0.98828125
+ }
+ }
+ 4 {0.073544 0.227744 -0.005546
+ {
+ 0.990234375 0.017578125
+ }
+ }
+ 5 {-0.067932 0.223167 0.018996
+ {
+ 0.98046875 0.46875
+ }
+ }
+ 6 {-0.067932 -0.223167 0.018996
+ {
+ 0.017578125 0.470703125
+ }
+ }
+ 7 {0.073544 -0.227744 -0.005546
+ {
+ 0.01953125 0.013671875
+ }
+ }
+ 8 {0.082372 0.237328 -0.015273
+ {
+ 0.9794921875 0.552734375
+ }
+ }
+ 9 {0.073544 0.227744 -0.005546
+ {
+ 0.9765625 0.57421875
+ }
+ }
+ 10 {0.073544 -0.227744 -0.005546
+ {
+ 0.025390625 0.57421875
+ }
+ }
+ 11 {0.082372 -0.237328 -0.015273
+ {
+ 0.0234375 0.5537109375
+ }
+ }
+ 12 {0.082372 -0.237328 -0.015273
+ {
+ 0.0703125 0.6123046875
+ }
+ }
+ 13 {0.073544 -0.227744 -0.005546
+ {
+ 0.095703125 0.615234375
+ }
+ }
+ 14 {-0.067932 -0.223167 0.018996
+ {
+ 0.13671875 0.97265625
+ }
+ }
+ 15 {-0.080884 -0.235006 0.001122
+ {
+ 0.07421875 0.982421875
+ }
+ }
+ 16 {-0.080884 -0.235006 0.001122
+ {
+ 0.0166015625 0.5361328125
+ }
+ }
+ 17 {-0.067932 -0.223167 0.018996
+ {
+ 0.017578125 0.58203125
+ }
+ }
+ 18 {-0.067932 0.223167 0.018996
+ {
+ 0.978515625 0.580078125
+ }
+ }
+ 19 {-0.080884 0.235006 0.001122
+ {
+ 0.984375 0.5341796875
+ }
+ }
+ 20 {0.082372 0.237328 -0.015273
+ {
+ 0.0703125 0.6123046875
+ }
+ }
+ 21 {0.082953 0.240000 -0.025000
+ {
+ 0.044921875 0.609375
+ }
+ }
+ 22 {-0.085000 0.240000 -0.025000
+ {
+ 0.01171875 0.9921875
+ }
+ }
+ 23 {-0.080884 0.235006 0.001122
+ {
+ 0.07421875 0.982421875
+ }
+ }
+ 24 {0.082953 0.240000 -0.025000
+ {
+ 0.982421875 0.53125
+ }
+ }
+ 25 {0.082372 0.237328 -0.015273
+ {
+ 0.9794921875 0.552734375
+ }
+ }
+ 26 {0.082372 -0.237328 -0.015273
+ {
+ 0.0234375 0.5537109375
+ }
+ }
+ 27 {0.082953 -0.240000 -0.025000
+ {
+ 0.021484375 0.533203125
+ }
+ }
+ 28 {0.082953 -0.240000 -0.025000
+ {
+ 0.044921875 0.609375
+ }
+ }
+ 29 {0.082372 -0.237328 -0.015273
+ {
+ 0.0703125 0.6123046875
+ }
+ }
+ 30 {-0.080884 -0.235006 0.001122
+ {
+ 0.07421875 0.982421875
+ }
+ }
+ 31 {-0.085000 -0.240000 -0.025000
+ {
+ 0.01171875 0.9921875
+ }
+ }
+ 32 {-0.085000 -0.240000 -0.025000
+ {
+ 0.015625 0.490234375
+ }
+ }
+ 33 {-0.080884 -0.235006 0.001122
+ {
+ 0.0166015625 0.5361328125
+ }
+ }
+ 34 {-0.080884 0.235006 0.001122
+ {
+ 0.984375 0.5341796875
+ }
+ }
+ 35 {-0.085000 0.240000 -0.025000
+ {
+ 0.990234375 0.48828125
+ }
+ }
+ 36 {0.073544 0.227744 -0.005546
+ {
+ 0.095703125 0.615234375
+ }
+ }
+ 37 {0.082372 0.237328 -0.015273
+ {
+ 0.0703125 0.6123046875
+ }
+ }
+ 38 {-0.080884 0.235006 0.001122
+ {
+ 0.07421875 0.982421875
+ }
+ }
+ 39 {-0.067932 0.223167 0.018996
+ {
+ 0.13671875 0.97265625
+ }
+ }}
+
+
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.000000 0.000000 -1.000000}
+ { 0 1 2 3 [ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.508027 -0.000000 0.861341}
+ { 4 5 6 7 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.966167 -0.000000 0.257917}
+ { 8 9 10 11 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.028240 -0.996449 0.079322}
+ { 12 13 14 15 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {-0.978036 0.000000 0.208436}
+ { 16 17 18 19 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.001260 0.999752 0.022233}
+ { 20 21 22 23 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.999846 -0.000000 0.017550}
+ { 24 25 26 27 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.001259 -0.999752 0.022233}
+ { 28 29 30 31 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {-0.998928 0.000000 0.046291}
+ { 32 33 34 35 ][ { Cube.001 }}
+ }
+ {
+ { Tex }
+ { takeyga_kb }
+ {0.028241 0.996449 0.079322}
+ { 36 37 38 39 ][ { Cube.001 }}
+ }
+ }
diff --git a/samples/rocket-console/assets/tex/takeyga_kb_diffuse.dds b/samples/rocket-console/assets/tex/takeyga_kb_diffuse.dds
new file mode 100644
index 0000000000..406e689545
Binary files /dev/null and b/samples/rocket-console/assets/tex/takeyga_kb_diffuse.dds differ
diff --git a/samples/rocket-console/assets/tex/takeyga_kb_normal.dds b/samples/rocket-console/assets/tex/takeyga_kb_normal.dds
new file mode 100644
index 0000000000..a949e2be69
Binary files /dev/null and b/samples/rocket-console/assets/tex/takeyga_kb_normal.dds differ
diff --git a/samples/rocket-console/assets/tex/takeyga_kb_specular.dds b/samples/rocket-console/assets/tex/takeyga_kb_specular.dds
new file mode 100644
index 0000000000..a63868f99c
Binary files /dev/null and b/samples/rocket-console/assets/tex/takeyga_kb_specular.dds differ
diff --git a/samples/rocket-console/assets/window.rcss b/samples/rocket-console/assets/window.rcss
new file mode 100755
index 0000000000..0e7adcedf9
--- /dev/null
+++ b/samples/rocket-console/assets/window.rcss
@@ -0,0 +1,56 @@
+body
+{
+ font-family: "MODENINE";
+ font-weight: normal;
+ font-style: normal;
+ font-size: 15;
+
+}
+
+body.window
+{
+ padding-top: 43px;
+ padding-bottom: 20px;
+
+ min-width: 250px;
+
+ min-height: 135px;
+ max-height: 700px;
+
+}
+
+
+
+div#title_bar
+{
+ z-index: 1;
+
+ position: absolute;
+ top: 0px;
+ left: 0px;
+
+ text-align: center;
+
+ color: #fff;
+ background-color: #22f;
+}
+
+
+div#title_bar span
+{
+ padding-top: 17px;
+ padding-bottom: 48px;
+
+ font-size: 32;
+ font-weight: bold;
+
+ outline-font-effect: outline;
+ outline-width: 1px;
+ outline-color: black;
+}
+
+div#title_bar_content
+{
+ text-align: center;
+ color: #cff;
+}
diff --git a/samples/rocket-console/assets/window.rml b/samples/rocket-console/assets/window.rml
new file mode 100755
index 0000000000..47336e7ab2
--- /dev/null
+++ b/samples/rocket-console/assets/window.rml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+ ]
+
+ Rocket Sample
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/rocket-console/console.py b/samples/rocket-console/console.py
new file mode 100644
index 0000000000..e32d2408d4
--- /dev/null
+++ b/samples/rocket-console/console.py
@@ -0,0 +1,153 @@
+"""
+Simple console widget for rocket
+"""
+import sys, os.path
+
+# workaround: https://www.panda3d.org/forums/viewtopic.php?t=10062&p=99697#p99054
+#from panda3d import rocket
+import _rocketcore as rocket
+
+from panda3d.rocket import RocketRegion, RocketInputHandler
+
+class Console(object):
+ def __init__(self, base, context, cols, rows, commandHandler):
+ self.base = base
+
+ self.context = context
+ self.loadFonts()
+ self.cols = cols
+ self.rows = rows
+ self.commandHandler = commandHandler
+
+ self.setupConsole()
+ self.allowEditing(True)
+
+ def getTextContainer(self):
+ return self.textEl
+
+ def setPrompt(self, prompt):
+ self.consolePrompt = prompt
+
+ def allowEditing(self, editMode):
+ self.editMode = editMode
+ if editMode:
+ self.input = ""
+ if not self.lastLine:
+ self.addLine("")
+ self.newEditLine()
+
+ def loadFonts(self):
+ rocket.LoadFontFace("Perfect DOS VGA 437.ttf")
+
+ def setupConsole(self):
+ self.document = self.context.LoadDocument("console.rml")
+ if not self.document:
+ raise AssertionError("did not find console.rml")
+
+ el = self.document.GetElementById('content')
+
+ self.textEl = el
+
+ # roundabout way of accessing the current object through rocket event...
+
+ # add attribute to let Rocket know about the receiver
+ self.context.console = self
+
+ # then reference through the string format (dunno how else to get the event...)
+ self.document.AddEventListener(
+ 'keydown', 'document.context.console.handleKeyDown(event)', True)
+ self.document.AddEventListener(
+ 'textinput', 'document.context.console.handleTextInput(event)', True)
+
+ self.consolePrompt = "C:\\>"
+
+ self.input = ""
+ self.lastLine = None
+
+ self.blinkState = False
+ self.queueBlinkCursor()
+
+ self.document.Show()
+
+ def queueBlinkCursor(self):
+ self.base.taskMgr.doMethodLater(0.2, self.blinkCursor, 'blinkCursor')
+
+ def blinkCursor(self, task):
+ self.blinkState = not self.blinkState
+ if self.editMode:
+ self.updateEditLine(self.input)
+ self.queueBlinkCursor()
+
+ def escape(self, text):
+ return text. \
+ replace('<', '<'). \
+ replace('>', '>'). \
+ replace('"', '"')
+
+ def addLine(self, text):
+ curKids = list(self.textEl.child_nodes)
+ while len(curKids) >= self.rows:
+ self.textEl.RemoveChild(curKids[0])
+ curKids = curKids[1:]
+
+ line = self.document.CreateTextNode(self.escape(text) + '\n')
+ self.textEl.AppendChild(line)
+ self.lastLine = line
+
+ def addLines(self, lines):
+ for line in lines:
+ self.addLine(line)
+
+ def updateEditLine(self, newInput=''):
+ newText = self.consolePrompt + newInput
+ self.lastLine.text = self.escape(newText) + (self.blinkState and '_' or '')
+ self.input = newInput
+
+ def scroll(self):
+ self.blinkState = False
+ self.updateEditLine(self.input + '\n')
+
+ def handleKeyDown(self, event):
+ """
+ Handle control keys
+ """
+ keyId = event.parameters['key_identifier']
+ if not self.editMode:
+ if keyId == rocket.key_identifier.PAUSE:
+ if event.parameters['ctrl_key']:
+ self.commandHandler(None)
+
+ return
+
+ if keyId == rocket.key_identifier.RETURN:
+ # emit line without cursor
+ self.scroll()
+
+ # handle command
+ self.commandHandler(self.input)
+
+ if self.editMode:
+ # start with new "command"
+ self.addLine(self.consolePrompt)
+ self.updateEditLine("")
+
+ elif keyId == rocket.key_identifier.BACK:
+ self.updateEditLine(self.input[0:-1])
+
+ def handleTextInput(self, event):
+ if not self.editMode:
+ return
+
+ # handle normal text character
+ data = event.parameters['data']
+ if 32 <= data < 128:
+ self.updateEditLine(self.input + chr(data))
+
+ def newEditLine(self):
+ self.addLine("")
+ self.updateEditLine()
+
+ def cls(self):
+ curKids = list(self.textEl.child_nodes)
+ for kid in curKids:
+ self.textEl.RemoveChild(kid)
\ No newline at end of file
diff --git a/samples/rocket-console/main.py b/samples/rocket-console/main.py
new file mode 100644
index 0000000000..7269c4b960
--- /dev/null
+++ b/samples/rocket-console/main.py
@@ -0,0 +1,410 @@
+"""
+Show how to use libRocket in Panda3D.
+"""
+import sys
+from panda3d.core import loadPrcFile, loadPrcFileData, Point3,Vec4, Mat4, LoaderOptions # @UnusedImport
+from panda3d.core import DirectionalLight, AmbientLight, PointLight
+from panda3d.core import Texture, PNMImage
+from panda3d.core import PandaSystem
+import random
+from direct.interval.LerpInterval import LerpHprInterval, LerpPosInterval, LerpFunc
+from direct.showbase.ShowBase import ShowBase
+
+# workaround: https://www.panda3d.org/forums/viewtopic.php?t=10062&p=99697#p99054
+#from panda3d import rocket
+import _rocketcore as rocket
+
+from panda3d.rocket import RocketRegion, RocketInputHandler
+
+loadPrcFileData("", "model-path $MAIN_DIR/assets")
+
+import console
+
+global globalClock
+
+class MyApp(ShowBase):
+
+ def __init__(self):
+ ShowBase.__init__(self)
+
+ self.win.setClearColor(Vec4(0.2, 0.2, 0.2, 1))
+
+ self.disableMouse()
+
+ self.render.setShaderAuto()
+
+ dlight = DirectionalLight('dlight')
+ alight = AmbientLight('alight')
+ dlnp = self.render.attachNewNode(dlight)
+ alnp = self.render.attachNewNode(alight)
+ dlight.setColor((0.8, 0.8, 0.5, 1))
+ alight.setColor((0.2, 0.2, 0.2, 1))
+ dlnp.setHpr(0, -60, 0)
+ self.render.setLight(dlnp)
+ self.render.setLight(alnp)
+
+ # Put lighting on the main scene
+ plight = PointLight('plight')
+ plnp = self.render.attachNewNode(plight)
+ plnp.setPos(0, 0, 10)
+ self.render.setLight(plnp)
+ self.render.setLight(alnp)
+
+ self.loadRocketFonts()
+
+ self.loadingTask = None
+
+ #self.startModelLoadingAsync()
+ self.startModelLoading()
+
+ self.inputHandler = RocketInputHandler()
+ self.mouseWatcher.attachNewNode(self.inputHandler)
+
+ self.openLoadingDialog()
+
+ def loadRocketFonts(self):
+ """ Load fonts referenced from e.g. 'font-family' RCSS directives.
+
+ Note: the name of the font as used in 'font-family'
+ is not always the same as the filename;
+ open the font in your OS to see its display name.
+ """
+ rocket.LoadFontFace("modenine.ttf")
+
+
+ def startModelLoading(self):
+ self.monitorNP = None
+ self.keyboardNP = None
+ self.loadingError = False
+
+ self.taskMgr.doMethodLater(1, self.loadModels, 'loadModels')
+
+ def loadModels(self, task):
+ self.monitorNP = self.loader.loadModel("monitor")
+ self.keyboardNP = self.loader.loadModel("takeyga_kb")
+
+ def startModelLoadingAsync(self):
+ """
+ NOTE: this seems to invoke a few bugs (crashes, sporadic model
+ reading errors, etc) so is disabled for now...
+ """
+ self.monitorNP = None
+ self.keyboardNP = None
+ self.loadingError = False
+
+ # force the "loading" to take some time after the first run...
+ options = LoaderOptions()
+ options.setFlags(options.getFlags() | LoaderOptions.LFNoCache)
+
+ def gotMonitorModel(model):
+ if not model:
+ self.loadingError = True
+ self.monitorNP = model
+
+ self.loader.loadModel("monitor", loaderOptions=options, callback=gotMonitorModel)
+
+ def gotKeyboardModel(model):
+ if not model:
+ self.loadingError = True
+ self.keyboardNP = model
+
+ self.loader.loadModel("takeyga_kb", loaderOptions=options, callback=gotKeyboardModel)
+
+ def openLoadingDialog(self):
+ self.userConfirmed = False
+
+ self.windowRocketRegion = RocketRegion.make('pandaRocket', self.win)
+ self.windowRocketRegion.setActive(1)
+
+ self.windowRocketRegion.setInputHandler(self.inputHandler)
+
+ self.windowContext = self.windowRocketRegion.getContext()
+
+ self.loadingDocument = self.windowContext.LoadDocument("loading.rml")
+ if not self.loadingDocument:
+ raise AssertionError("did not find loading.rml")
+
+ self.loadingDots = 0
+ el = self.loadingDocument.GetElementById('loadingLabel')
+ self.loadingText = el.first_child
+ self.stopLoadingTime = globalClock.getFrameTime() + 3
+ self.loadingTask = self.taskMgr.add(self.cycleLoading, 'doc changer')
+
+
+ # note: you may encounter errors like 'KeyError: 'document'"
+ # when invoking events using methods from your own scripts with this
+ # obvious code:
+ #
+ # self.loadingDocument.AddEventListener('aboutToClose',
+ # self.onLoadingDialogDismissed, True)
+ #
+ # A workaround is to define callback methods in standalone Python
+ # files with event, self, and document defined to None.
+ #
+ # see https://www.panda3d.org/forums/viewtopic.php?f=4&t=16412
+ #
+
+ # Or, use this indirection technique to work around the problem,
+ # by publishing the app into the context, then accessing it through
+ # the document's context...
+
+ self.windowContext.app = self
+ self.loadingDocument.AddEventListener('aboutToClose',
+ 'document.context.app.handleAboutToClose()', True)
+
+ self.loadingDocument.Show()
+
+ def handleAboutToClose(self):
+ self.userConfirmed = True
+ if self.monitorNP and self.keyboardNP:
+ self.onLoadingDialogDismissed()
+
+ def attachCustomRocketEvent(self, document, rocketEventName, pandaHandler, once=False):
+ # handle custom event
+
+ # note: you may encounter errors like 'KeyError: 'document'"
+ # when invoking events using methods from your own scripts with this
+ # obvious code:
+ #
+ # self.loadingDocument.AddEventListener('aboutToClose',
+ # self.onLoadingDialogDismissed, True)
+ #
+ # see https://www.panda3d.org/forums/viewtopic.php?f=4&t=16412
+
+
+ # this technique converts Rocket events to Panda3D events
+
+ pandaEvent = 'panda.' + rocketEventName
+
+ document.AddEventListener(
+ rocketEventName,
+ "messenger.send('" + pandaEvent + "', [event])")
+
+ if once:
+ self.acceptOnce(pandaEvent, pandaHandler)
+ else:
+ self.accept(pandaEvent, pandaHandler)
+
+
+ def cycleLoading(self, task):
+ """
+ Update the "loading" text in the initial window until
+ the user presses Space, Enter, or Escape or clicks (see loading.rxml)
+ or sufficient time has elapsed (self.stopLoadingTime).
+ """
+ text = self.loadingText
+
+ now = globalClock.getFrameTime()
+ if self.monitorNP and self.keyboardNP:
+ text.text = "Ready"
+ if now > self.stopLoadingTime or self.userConfirmed:
+ self.onLoadingDialogDismissed()
+ return task.done
+ elif self.loadingError:
+ text.text = "Assets not found"
+ else:
+ count = 5
+ intv = int(now * 4) % count # @UndefinedVariable
+ text.text = "Loading" + ("." * (1+intv)) + (" " * (2 - intv))
+
+ return task.cont
+
+ def onLoadingDialogDismissed(self):
+ """ Once a models are loaded, stop 'loading' and proceed to 'start' """
+ if self.loadingDocument:
+ if self.loadingTask:
+ self.taskMgr.remove(self.loadingTask)
+ self.loadingTask = None
+
+ self.showStarting()
+
+ def fadeOut(self, element, time):
+ """ Example updating RCSS attributes from code
+ by modifying the 'color' RCSS attribute to slowly
+ change from solid to transparent.
+
+ element: the Rocket element whose style to modify
+ time: time in seconds for fadeout
+ """
+
+ # get the current color from RCSS effective style
+ color = element.style.color
+ # convert to RGBA form
+ prefix = color[:color.rindex(',')+1].replace('rgb(', 'rgba(')
+
+ def updateAlpha(t):
+ # another way of setting style on a specific element
+ attr = 'color: ' + prefix + str(int(t)) +');'
+ element.SetAttribute('style', attr)
+
+ alphaInterval = LerpFunc(updateAlpha,
+ duration=time,
+ fromData=255,
+ toData=0,
+ blendType='easeIn')
+
+ return alphaInterval
+
+ def showStarting(self):
+ """ Models are loaded, so update the dialog,
+ fade out, then transition to the console. """
+ self.loadingText.text = 'Starting...'
+
+ alphaInterval = self.fadeOut(self.loadingText, 0.5)
+ alphaInterval.setDoneEvent('fadeOutFinished')
+
+ def fadeOutFinished():
+ if self.loadingDocument:
+ self.loadingDocument.Close()
+ self.loadingDocument = None
+ self.createConsole()
+
+ self.accept('fadeOutFinished', fadeOutFinished)
+
+ alphaInterval.start()
+
+ def createConsole(self):
+ """ Create the in-world console, which displays
+ a RocketRegion in a GraphicsBuffer, which appears
+ in a Texture on the monitor model. """
+
+ self.monitorNP.reparentTo(self.render)
+ self.monitorNP.setScale(1.5)
+
+ self.keyboardNP.reparentTo(self.render)
+ self.keyboardNP.setHpr(-90, 0, 15)
+ self.keyboardNP.setScale(20)
+
+ self.placeItems()
+
+ self.setupRocketConsole()
+
+ # re-enable mouse
+ mat=Mat4(self.camera.getMat())
+ mat.invertInPlace()
+ self.mouseInterfaceNode.setMat(mat)
+ self.enableMouse()
+
+ def placeItems(self):
+ self.camera.setPos(0, -20, 0)
+ self.camera.setHpr(0, 0, 0)
+ self.monitorNP.setPos(0, 0, 1)
+ self.keyboardNP.setPos(0, -5, -2.5)
+
+
+ def setupRocketConsole(self):
+ """
+ Place a new rocket window onto a texture
+ bound to the front of the monitor.
+ """
+ self.win.setClearColor(Vec4(0.5, 0.5, 0.8, 1))
+
+ faceplate = self.monitorNP.find("**/Faceplate")
+ assert faceplate
+
+ mybuffer = self.win.makeTextureBuffer("Console Buffer", 1024, 512)
+ tex = mybuffer.getTexture()
+ tex.setMagfilter(Texture.FTLinear)
+ tex.setMinfilter(Texture.FTLinear)
+
+ faceplate.setTexture(tex, 1)
+
+ self.rocketConsole = RocketRegion.make('console', mybuffer)
+ self.rocketConsole.setInputHandler(self.inputHandler)
+
+ self.consoleContext = self.rocketConsole.getContext()
+ self.console = console.Console(self, self.consoleContext, 40, 13, self.handleCommand)
+
+ self.console.addLine("Panda DOS")
+ self.console.addLine("type 'help'")
+ self.console.addLine("")
+
+ self.console.allowEditing(True)
+
+ def handleCommand(self, command):
+ if command is None:
+ # hack for Ctrl-Break
+ self.spewInProgress = False
+ self.console.addLine("*** break ***")
+ self.console.allowEditing(True)
+ return
+
+ command = command.strip()
+ if not command:
+ return
+
+ tokens = [x.strip() for x in command.split(' ')]
+ command = tokens[0].lower()
+
+ if command == 'help':
+ self.console.addLines([
+ "Sorry, this is utter fakery.",
+ "You won't get much more",
+ "out of this simulation unless",
+ "you program it yourself. :)"
+ ])
+ elif command == 'dir':
+ self.console.addLines([
+ "Directory of C:\\:",
+ "HELP COM 72 05-06-2015 14:07",
+ "DIR COM 121 05-06-2015 14:11",
+ "SPEW COM 666 05-06-2015 15:02",
+ " 2 Files(s) 859 Bytes.",
+ " 0 Dirs(s) 7333 Bytes free.",
+ ""])
+ elif command == 'cls':
+ self.console.cls()
+ elif command == 'echo':
+ self.console.addLine(' '.join(tokens[1:]))
+ elif command == 'ver':
+ self.console.addLine('Panda DOS v0.01 in Panda3D ' + PandaSystem.getVersionString())
+ elif command == 'spew':
+ self.startSpew()
+ elif command == 'exit':
+ self.console.setPrompt("System is shutting down NOW!")
+ self.terminateMonitor()
+ else:
+ self.console.addLine("command not found")
+
+ def startSpew(self):
+ self.console.allowEditing(False)
+ self.console.addLine("LINE NOISE 1.0")
+ self.console.addLine("")
+
+ self.spewInProgress = True
+
+ # note: spewage always occurs in 'doMethodLater';
+ # time.sleep() would be pointless since the whole
+ # UI would be frozen during the wait.
+ self.queueSpew(2)
+
+ def queueSpew(self, delay=0.1):
+ self.taskMgr.doMethodLater(delay, self.spew, 'spew')
+
+ def spew(self, task):
+ # generate random spewage, just like on TV!
+ if not self.spewInProgress:
+ return
+
+ def randchr():
+ return chr(int(random.random() < 0.25 and 32 or random.randint(32, 127)))
+
+ line = ''.join([randchr() for _ in range(40) ])
+
+ self.console.addLine(line)
+ self.queueSpew()
+
+ def terminateMonitor(self):
+ alphaInterval = self.fadeOut(self.console.getTextContainer(), 2)
+
+ alphaInterval.setDoneEvent('fadeOutFinished')
+
+ def fadeOutFinished():
+ sys.exit(0)
+
+ self.accept('fadeOutFinished', fadeOutFinished)
+
+ alphaInterval.start()
+
+app = MyApp()
+app.run()