import sys import os from PyQt5.QtCore import Qt, QTimer from PyQt5.QtWidgets import ( QApplication, QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, QSlider, QOpenGLWidget, QDialog, QRadioButton, QDialogButtonBox, QAction, QFileDialog, QLineEdit ) from OpenGL.GL import * from OpenGL.GLU import * class GLWidget(QOpenGLWidget): def __init__(self, parent=None): super().__init__(parent) self.xRot = 20.0 self.yRot = 30.0 self.zRot = 0.0 self.rotation_speed = 2.0 self.timer = QTimer(self) self.timer.timeout.connect(self.updateRotation) # ---------- OpenGL lifecycle ---------- def initializeGL(self): # Check that context is valid version = glGetString(GL_VERSION) print("GL version:", version) glClearColor(0.1, 0.1, 0.1, 1.0) glEnable(GL_DEPTH_TEST) glShadeModel(GL_SMOOTH) glEnable(GL_COLOR_MATERIAL) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) light_position = [4.0, 4.0, 8.0, 1.0] glLightfv(GL_LIGHT0, GL_POSITION, light_position) def resizeGL(self, w, h): if h == 0: h = 1 glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glLoadIdentity() gluPerspective(45.0, float(w) / float(h), 0.1, 100.0) glMatrixMode(GL_MODELVIEW) def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(0.0, 0.0, -7.0) glRotatef(self.xRot, 1.0, 0.0, 0.0) glRotatef(self.yRot, 0.0, 1.0, 0.0) glRotatef(self.zRot, 0.0, 0.0, 1.0) self.drawCube() # ---------- 3D object ---------- def drawCube(self): glBegin(GL_QUADS) # Front (red) glColor3f(1.0, 0.0, 0.0) glVertex3f(-1.0, -1.0, 1.0) glVertex3f( 1.0, -1.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glVertex3f(-1.0, 1.0, 1.0) # Back (green) glColor3f(0.0, 1.0, 0.0) glVertex3f(-1.0, -1.0, -1.0) glVertex3f(-1.0, 1.0, -1.0) glVertex3f( 1.0, 1.0, -1.0) glVertex3f( 1.0, -1.0, -1.0) # Top (blue) glColor3f(0.0, 0.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glVertex3f(-1.0, 1.0, 1.0) glVertex3f( 1.0, 1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0) # Bottom (yellow) glColor3f(1.0, 1.0, 0.0) glVertex3f(-1.0, -1.0, -1.0) glVertex3f( 1.0, -1.0, -1.0) glVertex3f( 1.0, -1.0, 1.0) glVertex3f(-1.0, -1.0, 1.0) # Right (magenta) glColor3f(1.0, 0.0, 1.0) glVertex3f( 1.0, -1.0, -1.0) glVertex3f( 1.0, 1.0, -1.0) glVertex3f( 1.0, 1.0, 1.0) glVertex3f( 1.0, -1.0, 1.0) # Left (cyan) glColor3f(0.0, 1.0, 1.0) glVertex3f(-1.0, -1.0, -1.0) glVertex3f(-1.0, -1.0, 1.0) glVertex3f(-1.0, 1.0, 1.0) glVertex3f(-1.0, 1.0, -1.0) glEnd() # ---------- Animation control ---------- def startRotation(self): if not self.timer.isActive(): self.timer.start(30) # ms def stopRotation(self): if self.timer.isActive(): self.timer.stop() def resetView(self): self.xRot = 20.0 self.yRot = 30.0 self.zRot = 0.0 self.update() def updateRotation(self): self.xRot += self.rotation_speed self.yRot += self.rotation_speed * 0.8 self.zRot += self.rotation_speed * 0.5 self.update() class MapWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("3D Cube with GUI Buttons (QOpenGLWidget)") self.resize(1280, 720) # File menu setup menubar = self.menuBar() file_menu = menubar.addMenu("File") action_new = QAction("New", self) action_open = QAction("Open", self) action_save = QAction("Save", self) action_save_as = QAction("Save As", self) file_menu.addAction(action_new) file_menu.addAction(action_open) file_menu.addAction(action_save) file_menu.addAction(action_save_as) action_new.triggered.connect(self.newFile) action_open.triggered.connect(self.openFile) action_save.triggered.connect(self.saveFile) action_save_as.triggered.connect(self.saveFileAs) self.current_file = None central = QWidget() self.setCentralWidget(central) main_layout = QHBoxLayout(central) # Left panel left_panel = QVBoxLayout() chunk_info_label = QLabel("CHUNK INFO") left_panel.addWidget(chunk_info_label) left_panel.addStretch() # Right panel right_panel = QVBoxLayout() map_info_label = QLabel("Map Information") right_panel.addWidget(map_info_label) map_title_label = QLabel("Map Title") map_title_input = QLineEdit() right_panel.addWidget(map_title_label) right_panel.addWidget(map_title_input) right_panel.addStretch() # Add panels to main layout left_widget = QWidget() left_widget.setLayout(left_panel) left_widget.setFixedWidth(200) main_layout.addWidget(left_widget) # Center panel (GLWidget + controls) self.gl_widget = GLWidget(self) main_layout.addWidget(self.gl_widget, stretch=3) right_widget = QWidget() right_widget.setLayout(right_panel) right_widget.setFixedWidth(250) main_layout.addWidget(right_widget) def newFile(self): # Implement new file logic here self.current_file = None # ...clear relevant data... def openFile(self): default_dir = os.path.join(os.path.dirname(__file__), '../../assets/map/') fname, _ = QFileDialog.getOpenFileName(self, "Open JSON File", default_dir, "JSON Files (*.json)") if fname: self.current_file = fname # ...load file logic... def saveFile(self): if self.current_file: # ...save logic... pass else: self.saveFileAs() def saveFileAs(self): default_dir = os.path.join(os.path.dirname(__file__), '../../assets/map/') fname, _ = QFileDialog.getSaveFileName(self, "Save JSON File As", default_dir, "JSON Files (*.json)") if fname: self.current_file = fname # ...save logic...