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