About to draw chunk
All checks were successful
Build Dusk / build-linux (push) Successful in 1m5s
Build Dusk / build-psp (push) Successful in 1m5s

This commit is contained in:
2025-11-16 09:11:58 -06:00
parent be422d0a1e
commit 7c194ab4b4
10 changed files with 221 additions and 100 deletions

3
assets/map/map.json Normal file
View File

@@ -0,0 +1,3 @@
{
"mapName": "Some Map"
}

View File

@@ -11,4 +11,8 @@ TILE_WIDTH = 16.0
TILE_HEIGHT = 16.0
TILE_DEPTH = 16.0
RPG_CAMERA_FOV = 70
RPG_CAMERA_PIXELS_PER_UNIT = 1.0
RPG_CAMERA_Z_OFFSET = 24.0
ASSET_LANG_CHUNK_CHAR_COUNT = 6144

View File

@@ -15,10 +15,7 @@
#include "display/screen.h"
#include "rpg/rpgcamera.h"
#include "util/memory.h"
#define TILE_WIDTH 16.0f
#define TILE_HEIGHT 16.0f
#define TILE_DEPTH 11.36f
#include "duskdefs.h"
errorret_t sceneMapInit(scenedata_t *data) {
// Init the camera.
@@ -26,7 +23,7 @@ errorret_t sceneMapInit(scenedata_t *data) {
data->sceneMap.camera.projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED;
data->sceneMap.camera.viewType = CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT;
glm_vec3_zero(data->sceneMap.camera.lookatPixelPerfect.offset);
data->sceneMap.camera.lookatPixelPerfect.offset[1] = TILE_HEIGHT;
data->sceneMap.camera.lookatPixelPerfect.offset[1] = RPG_CAMERA_Z_OFFSET;
glm_vec3_copy(
(vec3){ 0.0f, 0.0f, 0.0f },
data->sceneMap.camera.lookatPixelPerfect.target
@@ -35,8 +32,10 @@ errorret_t sceneMapInit(scenedata_t *data) {
(vec3){ 0.0f, 1.0f, 0.0f },
data->sceneMap.camera.lookatPixelPerfect.up
);
data->sceneMap.camera.lookatPixelPerfect.pixelsPerUnit = 1.0f;
data->sceneMap.camera.perspective.fov = glm_rad(90.0f);
data->sceneMap.camera.lookatPixelPerfect.pixelsPerUnit = (
RPG_CAMERA_PIXELS_PER_UNIT
);
data->sceneMap.camera.perspective.fov = glm_rad(RPG_CAMERA_FOV);
errorOk();
}

View File

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

View 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
)

View File

View 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)

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

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

View File

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