About to draw chunk
This commit is contained in:
@@ -9,7 +9,8 @@ from OpenGL.GLU import *
|
||||
from editortool.maptool import MapWindow
|
||||
from editortool.langtool import LangToolWindow
|
||||
|
||||
DEFAULT_TOOL = None # Set to "map" or "language" to auto-select for testing
|
||||
# DEFAULT_TOOL = None
|
||||
DEFAULT_TOOL = "map"
|
||||
|
||||
TOOLS = [
|
||||
("Map Editor", "map", MapWindow),
|
||||
|
||||
28
tools/editortool/map/camera.py
Normal file
28
tools/editortool/map/camera.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import math
|
||||
from OpenGL.GL import *
|
||||
from OpenGL.GLU import *
|
||||
from dusk.defs import defs
|
||||
|
||||
pixelsPerUnit = float(defs.get('RPG_CAMERA_PIXELS_PER_UNIT'))
|
||||
yOffset = float(defs.get('RPG_CAMERA_Z_OFFSET'))
|
||||
fov = float(defs.get('RPG_CAMERA_FOV'))
|
||||
scale = 8.0
|
||||
|
||||
def setupCamera(vw, vh):
|
||||
z = (vh / 2.0) / (
|
||||
(pixelsPerUnit * scale) * math.tan(math.radians(fov / 2.0))
|
||||
)
|
||||
lookAt = ( 0, 0, 0 )
|
||||
aspectRatio = vw / vh
|
||||
position = lookAt[0], lookAt[1] - yOffset, lookAt[2] + z
|
||||
|
||||
glMatrixMode(GL_PROJECTION)
|
||||
glLoadIdentity()
|
||||
gluPerspective(fov, aspectRatio, 0.1, 1000.0)
|
||||
glMatrixMode(GL_MODELVIEW)
|
||||
glLoadIdentity()
|
||||
gluLookAt(
|
||||
position[0], position[1], position[2],
|
||||
lookAt[0], lookAt[1], lookAt[2],
|
||||
0.0, 1.0, 0.0
|
||||
)
|
||||
0
tools/editortool/map/chunk.py
Normal file
0
tools/editortool/map/chunk.py
Normal file
@@ -2,104 +2,39 @@ from PyQt5.QtCore import QTimer
|
||||
from PyQt5.QtWidgets import QOpenGLWidget
|
||||
from OpenGL.GL import *
|
||||
from OpenGL.GLU import *
|
||||
from editortool.map.selectbox import drawSelectBox
|
||||
from editortool.map.tile import drawTile
|
||||
from editortool.map.camera import setupCamera
|
||||
|
||||
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)
|
||||
self.timer.timeout.connect(self.update)
|
||||
self.timer.start(16) # ~60 FPS
|
||||
|
||||
def initializeGL(self):
|
||||
version = glGetString(GL_VERSION)
|
||||
print("GL version:", version)
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0)
|
||||
glClearColor(0.392, 0.584, 0.929, 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)
|
||||
pass
|
||||
|
||||
|
||||
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()
|
||||
|
||||
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()
|
||||
w = self.width()
|
||||
h = self.height()
|
||||
if h <= 0:
|
||||
h = 1
|
||||
if w <= 0:
|
||||
w = 1
|
||||
|
||||
def startRotation(self):
|
||||
if not self.timer.isActive():
|
||||
self.timer.start(30)
|
||||
glViewport(0, 0, w, h)
|
||||
setupCamera(self.width(), self.height()) # <-- Add this here
|
||||
|
||||
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()
|
||||
# Draw test quad at 0,0,0 to 1,1,0
|
||||
drawTile(0, 0, 0)
|
||||
drawSelectBox(0, 0, 0)
|
||||
48
tools/editortool/map/selectbox.py
Normal file
48
tools/editortool/map/selectbox.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import OpenGL.GL as gl
|
||||
from dusk.defs import defs
|
||||
import colorsys
|
||||
|
||||
hue = [0.0] # Mutable container for static hue
|
||||
|
||||
def drawSelectBox(x, y, z):
|
||||
w = float(defs.get('TILE_WIDTH'))
|
||||
h = float(defs.get('TILE_HEIGHT'))
|
||||
d = float(defs.get('TILE_DEPTH'))
|
||||
|
||||
x = x * w
|
||||
y = y * h
|
||||
z = z * d
|
||||
|
||||
# Center box.
|
||||
x -= w / 2.0
|
||||
y -= h / 2.0
|
||||
z -= d / 2.0
|
||||
|
||||
# Define the 8 vertices of the cube with w=h=d=1
|
||||
vertices = [
|
||||
(x, y, z), # 0: min corner
|
||||
(x+w, y, z), # 1
|
||||
(x+w, y+h, z), # 2
|
||||
(x, y+h, z), # 3
|
||||
(x, y, z+d), # 4
|
||||
(x+w, y, z+d), # 5
|
||||
(x+w, y+h, z+d), # 6
|
||||
(x, y+h, z+d) # 7
|
||||
]
|
||||
# List of edges as pairs of vertex indices
|
||||
edges = [
|
||||
(0, 1), (1, 2), (2, 3), (3, 0), # bottom face
|
||||
(4, 5), (5, 6), (6, 7), (7, 4), # top face
|
||||
(0, 4), (1, 5), (2, 6), (3, 7) # vertical edges
|
||||
]
|
||||
|
||||
# Cycle hue
|
||||
hue[0] = (hue[0] + 0.01) % 1.0
|
||||
r, g, b = colorsys.hsv_to_rgb(hue[0], 1.0, 1.0)
|
||||
gl.glColor3f(r, g, b)
|
||||
gl.glLineWidth(2.0)
|
||||
gl.glBegin(gl.GL_LINES)
|
||||
for edge in edges:
|
||||
for vertex in edge:
|
||||
gl.glVertex3f(*vertices[vertex])
|
||||
gl.glEnd()
|
||||
25
tools/editortool/map/tile.py
Normal file
25
tools/editortool/map/tile.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from OpenGL.GL import *
|
||||
from dusk.defs import defs
|
||||
|
||||
def drawTile(x, y, z):
|
||||
w = float(defs.get('TILE_WIDTH'))
|
||||
h = float(defs.get('TILE_HEIGHT'))
|
||||
d = float(defs.get('TILE_DEPTH'))
|
||||
|
||||
x = x * w
|
||||
y = y * h
|
||||
z = z * d
|
||||
|
||||
# Center tile.
|
||||
x -= w / 2.0
|
||||
y -= h / 2.0
|
||||
z -= d / 2.0
|
||||
|
||||
# Draw the tile as a flat square on the X-Y plane at depth z.
|
||||
glColor3f(1.0, 0.0, 0.0) # Red color
|
||||
glBegin(GL_QUADS)
|
||||
glVertex3f(x, y, z) # Bottom-left
|
||||
glVertex3f(x + w, y, z) # Bottom-right
|
||||
glVertex3f(x + w, y + h, z) # Top-right
|
||||
glVertex3f(x, y + h, z) # Top-left
|
||||
glEnd()
|
||||
@@ -1,11 +1,12 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
from PyQt5.QtCore import Qt, QTimer
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QMainWindow, QWidget,
|
||||
QHBoxLayout, QVBoxLayout, QPushButton,
|
||||
QLabel, QSlider, QDialog, QRadioButton, QDialogButtonBox,
|
||||
QAction, QFileDialog, QLineEdit
|
||||
QAction, QFileDialog, QLineEdit, QMessageBox
|
||||
)
|
||||
from editortool.map.glwidget import GLWidget
|
||||
|
||||
@@ -36,6 +37,8 @@ class MapWindow(QMainWindow):
|
||||
action_save_as.triggered.connect(self.saveFileAs)
|
||||
|
||||
self.current_file = None
|
||||
self.dirty = False
|
||||
self.highlighted_pos = [0, 0, 0] # x, y, z
|
||||
|
||||
central = QWidget()
|
||||
self.setCentralWidget(central)
|
||||
@@ -46,6 +49,22 @@ class MapWindow(QMainWindow):
|
||||
left_panel = QVBoxLayout()
|
||||
chunk_info_label = QLabel("CHUNK INFO")
|
||||
left_panel.addWidget(chunk_info_label)
|
||||
|
||||
# Movement controls
|
||||
move_label = QLabel("Move Selection")
|
||||
left_panel.addWidget(move_label)
|
||||
btn_n = QPushButton("N")
|
||||
btn_s = QPushButton("S")
|
||||
btn_e = QPushButton("E")
|
||||
btn_w = QPushButton("W")
|
||||
btn_up = QPushButton("Up")
|
||||
btn_down = QPushButton("Down")
|
||||
left_panel.addWidget(btn_n)
|
||||
left_panel.addWidget(btn_s)
|
||||
left_panel.addWidget(btn_e)
|
||||
left_panel.addWidget(btn_w)
|
||||
left_panel.addWidget(btn_up)
|
||||
left_panel.addWidget(btn_down)
|
||||
left_panel.addStretch()
|
||||
|
||||
# Right panel
|
||||
@@ -53,9 +72,9 @@ class MapWindow(QMainWindow):
|
||||
map_info_label = QLabel("Map Information")
|
||||
right_panel.addWidget(map_info_label)
|
||||
map_title_label = QLabel("Map Title")
|
||||
map_title_input = QLineEdit()
|
||||
self.map_title_input = QLineEdit()
|
||||
right_panel.addWidget(map_title_label)
|
||||
right_panel.addWidget(map_title_input)
|
||||
right_panel.addWidget(self.map_title_input)
|
||||
right_panel.addStretch()
|
||||
|
||||
# Add panels to main layout
|
||||
@@ -73,9 +92,23 @@ class MapWindow(QMainWindow):
|
||||
right_widget.setFixedWidth(250)
|
||||
main_layout.addWidget(right_widget)
|
||||
|
||||
self.map_title_input.textChanged.connect(self._on_map_title_changed)
|
||||
|
||||
# Connect movement buttons
|
||||
btn_n.clicked.connect(lambda: self.move_highlight(0, 1, 0))
|
||||
btn_s.clicked.connect(lambda: self.move_highlight(0, -1, 0))
|
||||
btn_e.clicked.connect(lambda: self.move_highlight(1, 0, 0))
|
||||
btn_w.clicked.connect(lambda: self.move_highlight(-1, 0, 0))
|
||||
btn_up.clicked.connect(lambda: self.move_highlight(0, 0, 1))
|
||||
btn_down.clicked.connect(lambda: self.move_highlight(0, 0, -1))
|
||||
|
||||
def _on_map_title_changed(self):
|
||||
self.dirty = True
|
||||
|
||||
def newFile(self):
|
||||
# Implement new file logic here
|
||||
self.current_file = None
|
||||
self.map_title_input.setText("")
|
||||
self.dirty = False
|
||||
# ...clear relevant data...
|
||||
|
||||
def openFile(self):
|
||||
@@ -83,12 +116,18 @@ class MapWindow(QMainWindow):
|
||||
fname, _ = QFileDialog.getOpenFileName(self, "Open JSON File", default_dir, "JSON Files (*.json)")
|
||||
if fname:
|
||||
self.current_file = fname
|
||||
# ...load file logic...
|
||||
try:
|
||||
with open(fname, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
self.map_title_input.setText(data.get("mapName", ""))
|
||||
self.dirty = False
|
||||
except Exception as e:
|
||||
self.map_title_input.setText("")
|
||||
# Optionally show error dialog
|
||||
|
||||
def saveFile(self):
|
||||
if self.current_file:
|
||||
# ...save logic...
|
||||
pass
|
||||
self._save_to_file(self.current_file)
|
||||
else:
|
||||
self.saveFileAs()
|
||||
|
||||
@@ -97,4 +136,43 @@ class MapWindow(QMainWindow):
|
||||
fname, _ = QFileDialog.getSaveFileName(self, "Save JSON File As", default_dir, "JSON Files (*.json)")
|
||||
if fname:
|
||||
self.current_file = fname
|
||||
# ...save logic...
|
||||
self._save_to_file(fname)
|
||||
|
||||
def _save_to_file(self, fname):
|
||||
data = {
|
||||
"mapName": self.map_title_input.text()
|
||||
}
|
||||
try:
|
||||
with open(fname, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
self.dirty = False
|
||||
except Exception as e:
|
||||
# Optionally show error dialog
|
||||
pass
|
||||
|
||||
def move_highlight(self, dx, dy, dz):
|
||||
self.highlighted_pos[0] += dx
|
||||
self.highlighted_pos[1] += dy
|
||||
self.highlighted_pos[2] += dz
|
||||
self.gl_widget.set_highlighted_pos(self.highlighted_pos)
|
||||
self.dirty = True
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.dirty:
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"Unsaved Changes",
|
||||
"You have unsaved changes. Do you want to save before closing?",
|
||||
QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
|
||||
QMessageBox.Save
|
||||
)
|
||||
if reply == QMessageBox.Save:
|
||||
self.saveFile()
|
||||
if self.dirty:
|
||||
event.ignore()
|
||||
return
|
||||
elif reply == QMessageBox.Cancel:
|
||||
event.ignore()
|
||||
return
|
||||
# Discard: continue closing
|
||||
event.accept()
|
||||
Reference in New Issue
Block a user