rocket: Add sample showing some Panda3D uses of libRocket. (#24)

This commit is contained in:
Ed Swartz 2017-10-31 13:43:28 -05:00 committed by rdb
parent 0493b07f45
commit 34731cd2f4
18 changed files with 1155 additions and 0 deletions

Binary file not shown.

View File

@ -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;
}

View File

@ -0,0 +1,11 @@
<rml>
<head>
<title>Administrative Console</title>
<link type="text/rcss" href="console.rcss"/>
</head>
<!-- events are bound strictly from code -->
<body >
<text id="content" />
</body>
</rml>

View File

@ -0,0 +1 @@
from www.dafont.com/perfect-dos-vga-437.font (info at http://zehfernando.com/2015/revisiting-vga-fonts/)

View File

@ -0,0 +1,54 @@
<rml>
<head >
<title>Main Menu</title>
<link type="text/template" href="window.rml" />
<style>
body
{
width: 400px;
height: 225px;
margin: auto;
background-color: #44f;
}
div#title_bar_content
{
font-size: 48;
//text-align: left;
position: absolute;
top: 40%;
//vertical-align: center;
}
</style>
<script>
import _rocketcore as rocket
# This handler overrides the 'onkeydown' handler from the template
def OnKeyDown(event, document):
keyId = event.parameters['key_identifier']
if keyId in [ rocket.key_identifier.RETURN,
rocket.key_identifier.ESCAPE,
rocket.key_identifier.SPACE ]:
FireClosing(document)
# custom event
def FireClosing(document):
document.DispatchEvent("aboutToClose", { }, False)
</script>
</head>
<body id='window' template="window" onclick='FireClosing(document)'>
<div id="title_bar_content" >
<label id="loadingLabel">Loading...</label>
</div>
</body>
</rml>

View File

@ -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/

Binary file not shown.

Binary file not shown.

View File

@ -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.

View File

@ -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;
}

View File

@ -0,0 +1,316 @@
<CoordinateSystem> { Z-up }
<Material> takeyga_kb {
<Scalar> diffr { 0.800000 }
<Scalar> diffg { 0.800000 }
<Scalar> diffb { 0.800000 }
<Scalar> specr { 0.500000 }
<Scalar> specg { 0.500000 }
<Scalar> specb { 0.500000 }
<Scalar> shininess { 12.5 }
<Scalar> ambr { 1.000000 }
<Scalar> ambg { 1.000000 }
<Scalar> ambb { 1.000000 }
<Scalar> emitr { 0.000000 }
<Scalar> emitg { 0.000000 }
<Scalar> emitb { 0.000000 }
}
<Texture> Texture.001 {
"./tex/takeyga_kb_specular.dds"
<Scalar> envtype { MODULATE }
<Scalar> minfilter { LINEAR_MIPMAP_LINEAR }
<Scalar> magfilter { LINEAR_MIPMAP_LINEAR }
<Scalar> wrap { REPEAT }
}
<Texture> Tex {
"./tex/takeyga_kb_diffuse.dds"
<Scalar> envtype { MODULATE }
<Scalar> minfilter { LINEAR_MIPMAP_LINEAR }
<Scalar> magfilter { LINEAR_MIPMAP_LINEAR }
<Scalar> wrap { REPEAT }
}
<Texture> Texture {
"./tex/takeyga_kb_normal.dds"
<Scalar> envtype { NORMAL }
<Scalar> minfilter { LINEAR_MIPMAP_LINEAR }
<Scalar> magfilter { LINEAR_MIPMAP_LINEAR }
<Scalar> wrap { REPEAT }
}
<Group> Cube.001 {
<Transform> {
<Matrix4> {
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
}
}
<VertexPool> Cube.001 {
<Vertex> 0 {0.082953 0.240000 -0.025000
<UV> {
0.158203125 0.595703125
}
}
<Vertex> 1 {0.082953 -0.240000 -0.025000
<UV> {
0.98828125 0.6015625
}
}
<Vertex> 2 {-0.085000 -0.240000 -0.025000
<UV> {
0.98828125 0.986328125
}
}
<Vertex> 3 {-0.085000 0.240000 -0.025000
<UV> {
0.162109375 0.98828125
}
}
<Vertex> 4 {0.073544 0.227744 -0.005546
<UV> {
0.990234375 0.017578125
}
}
<Vertex> 5 {-0.067932 0.223167 0.018996
<UV> {
0.98046875 0.46875
}
}
<Vertex> 6 {-0.067932 -0.223167 0.018996
<UV> {
0.017578125 0.470703125
}
}
<Vertex> 7 {0.073544 -0.227744 -0.005546
<UV> {
0.01953125 0.013671875
}
}
<Vertex> 8 {0.082372 0.237328 -0.015273
<UV> {
0.9794921875 0.552734375
}
}
<Vertex> 9 {0.073544 0.227744 -0.005546
<UV> {
0.9765625 0.57421875
}
}
<Vertex> 10 {0.073544 -0.227744 -0.005546
<UV> {
0.025390625 0.57421875
}
}
<Vertex> 11 {0.082372 -0.237328 -0.015273
<UV> {
0.0234375 0.5537109375
}
}
<Vertex> 12 {0.082372 -0.237328 -0.015273
<UV> {
0.0703125 0.6123046875
}
}
<Vertex> 13 {0.073544 -0.227744 -0.005546
<UV> {
0.095703125 0.615234375
}
}
<Vertex> 14 {-0.067932 -0.223167 0.018996
<UV> {
0.13671875 0.97265625
}
}
<Vertex> 15 {-0.080884 -0.235006 0.001122
<UV> {
0.07421875 0.982421875
}
}
<Vertex> 16 {-0.080884 -0.235006 0.001122
<UV> {
0.0166015625 0.5361328125
}
}
<Vertex> 17 {-0.067932 -0.223167 0.018996
<UV> {
0.017578125 0.58203125
}
}
<Vertex> 18 {-0.067932 0.223167 0.018996
<UV> {
0.978515625 0.580078125
}
}
<Vertex> 19 {-0.080884 0.235006 0.001122
<UV> {
0.984375 0.5341796875
}
}
<Vertex> 20 {0.082372 0.237328 -0.015273
<UV> {
0.0703125 0.6123046875
}
}
<Vertex> 21 {0.082953 0.240000 -0.025000
<UV> {
0.044921875 0.609375
}
}
<Vertex> 22 {-0.085000 0.240000 -0.025000
<UV> {
0.01171875 0.9921875
}
}
<Vertex> 23 {-0.080884 0.235006 0.001122
<UV> {
0.07421875 0.982421875
}
}
<Vertex> 24 {0.082953 0.240000 -0.025000
<UV> {
0.982421875 0.53125
}
}
<Vertex> 25 {0.082372 0.237328 -0.015273
<UV> {
0.9794921875 0.552734375
}
}
<Vertex> 26 {0.082372 -0.237328 -0.015273
<UV> {
0.0234375 0.5537109375
}
}
<Vertex> 27 {0.082953 -0.240000 -0.025000
<UV> {
0.021484375 0.533203125
}
}
<Vertex> 28 {0.082953 -0.240000 -0.025000
<UV> {
0.044921875 0.609375
}
}
<Vertex> 29 {0.082372 -0.237328 -0.015273
<UV> {
0.0703125 0.6123046875
}
}
<Vertex> 30 {-0.080884 -0.235006 0.001122
<UV> {
0.07421875 0.982421875
}
}
<Vertex> 31 {-0.085000 -0.240000 -0.025000
<UV> {
0.01171875 0.9921875
}
}
<Vertex> 32 {-0.085000 -0.240000 -0.025000
<UV> {
0.015625 0.490234375
}
}
<Vertex> 33 {-0.080884 -0.235006 0.001122
<UV> {
0.0166015625 0.5361328125
}
}
<Vertex> 34 {-0.080884 0.235006 0.001122
<UV> {
0.984375 0.5341796875
}
}
<Vertex> 35 {-0.085000 0.240000 -0.025000
<UV> {
0.990234375 0.48828125
}
}
<Vertex> 36 {0.073544 0.227744 -0.005546
<UV> {
0.095703125 0.615234375
}
}
<Vertex> 37 {0.082372 0.237328 -0.015273
<UV> {
0.0703125 0.6123046875
}
}
<Vertex> 38 {-0.080884 0.235006 0.001122
<UV> {
0.07421875 0.982421875
}
}
<Vertex> 39 {-0.067932 0.223167 0.018996
<UV> {
0.13671875 0.97265625
}
}}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.000000 0.000000 -1.000000}
<VertexRef> { 0 1 2 3 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.508027 -0.000000 0.861341}
<VertexRef> { 4 5 6 7 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.966167 -0.000000 0.257917}
<VertexRef> { 8 9 10 11 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.028240 -0.996449 0.079322}
<VertexRef> { 12 13 14 15 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {-0.978036 0.000000 0.208436}
<VertexRef> { 16 17 18 19 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.001260 0.999752 0.022233}
<VertexRef> { 20 21 22 23 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.999846 -0.000000 0.017550}
<VertexRef> { 24 25 26 27 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.001259 -0.999752 0.022233}
<VertexRef> { 28 29 30 31 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {-0.998928 0.000000 0.046291}
<VertexRef> { 32 33 34 35 <Ref> { Cube.001 }}
}
<Polygon> {
<TRef> { Tex }
<MRef> { takeyga_kb }
<Normal> {0.028241 0.996449 0.079322}
<VertexRef> { 36 37 38 39 <Ref> { Cube.001 }}
}
}

View File

@ -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;
}

View File

@ -0,0 +1,42 @@
<template name="window" content="content">
<head>
<link type="text/rcss" href="rkt.rcss"/>
<link type="text/rcss" href="window.rcss"/>
<script>
import _rocketcore as rocket
def OnLoad(document):
print "Rocket document loaded"
# event handlers from templates can be overridden in windows using them
def OnKeyDown(event, document):
keyId = event.parameters['key_identifier']
print "Base keydown: unhandled key ",keyId
</script>
</head>
<body class="window" onload='OnLoad(document)' onkeydown='OnKeyDown(event, document)'>
<div id="title_bar">
<handle move_target="#document">
<span id="title">Rocket Sample</span>
<div id="title_bar_content">
</div>
</handle>
</div>
<div id="window">
<div id="content">
</div>
</div>
<!-- drag and drop of window -->
<handle size_target="#document"
style="position: absolute; width: 16px; height: 16px; bottom: 0px; right: 0px;">
</handle>
</body>
</template>

View File

@ -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('<', '&lt;'). \
replace('>', '&gt;'). \
replace('"', '&quot;')
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)

View File

@ -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()