rendering.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import numpy as np
  2. from PyQt5.QtCore import Qt
  3. from PyQt5.QtGui import QImage, QPixmap, QPainter, QColor, QPolygon
  4. from PyQt5.QtCore import QPoint, QSize, QRect
  5. from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QTextEdit
  6. from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QFrame
  7. class Window(QMainWindow):
  8. """
  9. Simple application window to render the environment into
  10. """
  11. def __init__(self):
  12. super().__init__()
  13. self.setWindowTitle('MiniGrid Gym Environment')
  14. # Image label to display the rendering
  15. self.imgLabel = QLabel()
  16. self.imgLabel.setFrameStyle(QFrame.Panel | QFrame.Sunken)
  17. # Text box for the mission
  18. self.missionBox = QTextEdit()
  19. self.missionBox.setReadOnly(True)
  20. self.missionBox.setMinimumSize(400, 100)
  21. # Center the image
  22. hbox = QHBoxLayout()
  23. hbox.addStretch(1)
  24. hbox.addWidget(self.imgLabel)
  25. hbox.addStretch(1)
  26. # Arrange widgets vertically
  27. vbox = QVBoxLayout()
  28. vbox.addLayout(hbox)
  29. vbox.addWidget(self.missionBox)
  30. # Create a main widget for the window
  31. mainWidget = QWidget(self)
  32. self.setCentralWidget(mainWidget)
  33. mainWidget.setLayout(vbox)
  34. # Show the application window
  35. self.show()
  36. self.setFocus()
  37. self.closed = False
  38. # Callback for keyboard events
  39. self.keyDownCb = None
  40. def closeEvent(self, event):
  41. self.closed = True
  42. def setPixmap(self, pixmap):
  43. self.imgLabel.setPixmap(pixmap)
  44. def setText(self, text):
  45. self.missionBox.setPlainText(text)
  46. def setKeyDownCb(self, callback):
  47. self.keyDownCb = callback
  48. def keyPressEvent(self, e):
  49. if self.keyDownCb == None:
  50. return
  51. keyName = None
  52. if e.key() == Qt.Key_Left:
  53. keyName = 'LEFT'
  54. elif e.key() == Qt.Key_Right:
  55. keyName = 'RIGHT'
  56. elif e.key() == Qt.Key_Up:
  57. keyName = 'UP'
  58. elif e.key() == Qt.Key_Down:
  59. keyName = 'DOWN'
  60. elif e.key() == Qt.Key_Space:
  61. keyName = 'SPACE'
  62. elif e.key() == Qt.Key_Return:
  63. keyName = 'RETURN'
  64. elif e.key() == Qt.Key_Alt:
  65. keyName = 'ALT'
  66. elif e.key() == Qt.Key_Control:
  67. keyName = 'CTRL'
  68. elif e.key() == Qt.Key_PageUp:
  69. keyName = 'PAGE_UP'
  70. elif e.key() == Qt.Key_PageDown:
  71. keyName = 'PAGE_DOWN'
  72. elif e.key() == Qt.Key_Backspace:
  73. keyName = 'BACKSPACE'
  74. elif e.key() == Qt.Key_Escape:
  75. keyName = 'ESCAPE'
  76. if keyName == None:
  77. return
  78. self.keyDownCb(keyName)
  79. class Renderer:
  80. def __init__(self, width, height, ownWindow=False):
  81. self.width = width
  82. self.height = height
  83. self.img = QImage(width, height, QImage.Format_RGB888)
  84. self.painter = QPainter()
  85. self.window = None
  86. if ownWindow:
  87. self.app = QApplication([])
  88. self.window = Window()
  89. def close(self):
  90. """
  91. Deallocate resources used
  92. """
  93. pass
  94. def beginFrame(self):
  95. self.painter.begin(self.img)
  96. self.painter.setRenderHint(QPainter.Antialiasing, False)
  97. # Clear the background
  98. self.painter.setBrush(QColor(0, 0, 0))
  99. self.painter.drawRect(0, 0, self.width - 1, self.height - 1)
  100. def endFrame(self):
  101. self.painter.end()
  102. if self.window:
  103. if self.window.closed:
  104. self.window = None
  105. else:
  106. self.window.setPixmap(self.getPixmap())
  107. self.app.processEvents()
  108. def getPixmap(self):
  109. return QPixmap.fromImage(self.img)
  110. def getArray(self):
  111. """
  112. Get a numpy array of RGB pixel values.
  113. The array will have shape (height, width, 3)
  114. """
  115. numBytes = self.width * self.height * 3
  116. buf = self.img.bits().asstring(numBytes)
  117. output = np.frombuffer(buf, dtype='uint8')
  118. output = output.reshape((self.height, self.width, 3))
  119. return output
  120. def push(self):
  121. self.painter.save()
  122. def pop(self):
  123. self.painter.restore()
  124. def rotate(self, degrees):
  125. self.painter.rotate(degrees)
  126. def translate(self, x, y):
  127. self.painter.translate(x, y)
  128. def scale(self, x, y):
  129. self.painter.scale(x, y)
  130. def setLineColor(self, r, g, b, a=255):
  131. self.painter.setPen(QColor(r, g, b, a))
  132. def setColor(self, r, g, b, a=255):
  133. self.painter.setBrush(QColor(r, g, b, a))
  134. def setLineWidth(self, width):
  135. pen = self.painter.pen()
  136. pen.setWidthF(width)
  137. self.painter.setPen(pen)
  138. def drawLine(self, x0, y0, x1, y1):
  139. self.painter.drawLine(x0, y0, x1, y1)
  140. def drawCircle(self, x, y, r):
  141. center = QPoint(x, y)
  142. self.painter.drawEllipse(center, r, r)
  143. def drawPolygon(self, points):
  144. """Takes a list of points (tuples) as input"""
  145. points = map(lambda p: QPoint(p[0], p[1]), points)
  146. self.painter.drawPolygon(QPolygon(points))
  147. def drawPolyline(self, points):
  148. """Takes a list of points (tuples) as input"""
  149. points = map(lambda p: QPoint(p[0], p[1]), points)
  150. self.painter.drawPolyline(QPolygon(points))
  151. def fillRect(self, x, y, width, height, r, g, b, a=255):
  152. self.painter.fillRect(QRect(x, y, width, height), QColor(r, g, b, a))