Gravity, sun-disc, voxel picking, hand indicator
dkl9

dkl9 commited on 2025-177 00:03:49
Showing 8 changed files, with 46 additions and 66 deletions.

... ...
@@ -18,7 +18,7 @@ class Entity:
18 18
 
19 19
     def norm_list(self):
20 20
         l = []
21
-        if self.draw_mode == GL_TRIANGLE_STRIP:
21
+        if self.draw_mode == GL_TRIANGLE_STRIP or self.draw_mode == GL_TRIANGLE_FAN:
22 22
             l.append(norm_tri(self.verts[:3]))
23 23
             for i in range(1, len(self.verts) - 1):
24 24
                 l.append(norm_tri(self.verts[i - 1:i + 2]))
... ...
@@ -60,7 +60,7 @@ class Entity:
60 60
         ]) @ self.orient
61 61
 
62 62
     def click(self, button, face, hand=1):
63
-        self.onclick(self, button, face, hand)
63
+        return self.onclick(self, button, face, hand)
64 64
 
65 65
     def raycast(self, ro, rd):
66 66
         if self.hud or self.draw_mode == GL_LINES:
... ...
@@ -1,51 +0,0 @@
1
-from OpenGL.GL import *
2
-from OpenGL.GLU import *
3
-from OpenGL.GLUT import *
4
-import sys
5
-import time
6
-
7
-lf = time.time()
8
-fc = 0
9
-
10
-def reshape(width, height):
11
-    glViewport(0, 0, width, height)
12
-    glMatrixMode(GL_PROJECTION)
13
-    glLoadIdentity()
14
-    gluPerspective(45, width / float(height or 1), 1, 50)
15
-    glMatrixMode(GL_MODELVIEW)
16
-
17
-def draw_cube():
18
-    glutWireCube(1)
19
-
20
-def display():
21
-    global lf, fc
22
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
23
-    glLoadIdentity()
24
-    glTranslatef(0, 0, -5)
25
-    glRotatef((60 * time.time()) % 360, 2, 1, 0)
26
-    draw_cube()
27
-    glutSwapBuffers()
28
-    fc += 1
29
-    now = time.time()
30
-    if now - lf >= 1.0:
31
-        print(f"{fc} FPS")
32
-        fc = 0
33
-        lf = now
34
-
35
-def keyboard(key, x, y):
36
-    if key == b'\x1b':  # ESC
37
-        glutLeaveMainLoop()
38
-
39
-glutInit(sys.argv)
40
-glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
41
-glutInitWindowSize(500, 500)
42
-glutInitWindowPosition(100, 100)
43
-glutCreateWindow("PyOpenGL Cube")
44
-glEnable(GL_DEPTH_TEST)
45
-
46
-glutDisplayFunc(display)
47
-glutIdleFunc(display)
48
-glutReshapeFunc(reshape)
49
-glutKeyboardFunc(keyboard)
50
-
51
-glutMainLoop()
... ...
@@ -8,6 +8,8 @@ VOXEL_TYPE = np.uint8
8 8
 VERTEX_ATTRS = ["vec3 position", "vec4 col", "vec3 normal", "vec4 refls"]
9 9
 UNIFORMS = {"MVP": ["vert", "mat4", None], "lightPos": ["frag", "vec4", None], "camPos": ["frag", "vec3", None]}
10 10
 
11
+LIGHT_POS = [5, 30, 10]
12
+GRAVITY = 1
11 13
 VIEW_DIST = 30
12 14
 FPS = 60
13 15
 ARROWS = [pygame.K_RIGHT, pygame.K_LEFT, pygame.K_SPACE, pygame.K_LSHIFT, pygame.K_UP, pygame.K_DOWN]
... ...
@@ -5,6 +5,7 @@ from mapgen import MapGen
5 5
 from mesh import SquareMesh
6 6
 from player import Player
7 7
 from region import WorldRegion
8
+import os
8 9
 
9 10
 VS = f"""
10 11
 #version 120
... ...
@@ -49,7 +50,7 @@ def in_view(wr, cam):
49 50
 
50 51
 def main():
51 52
     pygame.init()
52
-    pygame.display.set_mode((640, 480), pygame.DOUBLEBUF | pygame.OPENGL | pygame.FULLSCREEN | pygame.SCALED, vsync=1)
53
+    pygame.display.set_mode((640, 480), pygame.DOUBLEBUF | pygame.OPENGL | (pygame.FULLSCREEN | pygame.SCALED if os.environ.get("FULLSCREEN") else pygame.RESIZABLE), vsync=1)
53 54
     pygame.event.set_allowed([pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION, pygame.QUIT, pygame.WINDOWRESIZED, pygame.WINDOWSIZECHANGED])
54 55
     pygame.display.set_caption("Voxels")
55 56
     sp = shaders.compileProgram(
... ...
@@ -63,7 +64,7 @@ def main():
63 64
     glEnable(GL_BLEND)
64 65
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
65 66
     glClearColor(0.1, 0.1, 0.1, 1.0)
66
-    glUniform4fv(UNIFORMS["lightPos"][2], 1, vec([5, 30, 10, 100]))
67
+    glUniform4fv(UNIFORMS["lightPos"][2], 1, vec([*LIGHT_POS, 100]))
67 68
     mg = build_scene()
68 69
     clock = pygame.time.Clock()
69 70
     cam = Player(speed=6/FPS)
... ...
@@ -38,8 +38,8 @@ class SquareMesh(entity.Entity):
38 38
             case 1:
39 39
                 return (vec([*np.add(0.5, axis2offset(axis, 0.5)), 1.0]), vec([1.0, 0.0, 0.1, 128.0]))
40 40
             case 2:
41
-                top = (vec([0.5, 0.5, 1.0, 1.0]), vec([1.0, 0.0, 0.0, 1.0]))
42
-                bottom = (vec([0.0, 0.0, 0.5, 1.0]), vec([1.0, 0.0, 0.0, 1.0]))
41
+                top = (vec([0.2, 0.2, 1.0, 1.0]), vec([1.0, 0.0, 0.0, 1.0]))
42
+                bottom = (vec([0.0, 0.0, 0.2, 1.0]), vec([1.0, 0.0, 0.0, 1.0]))
43 43
                 match axis:
44 44
                     case 2:
45 45
                         return top
... ...
@@ -58,7 +58,7 @@ class SquareMesh(entity.Entity):
58 58
                     case -2:
59 59
                         return bottom
60 60
                     case a:
61
-                        return bottom if corner & (2 >> ((a % 4) // 2)) else top
61
+                        return bottom if corner & (1 << ((a % 4) // 2)) else top
62 62
                 return 
63 63
             case 5:
64 64
                 core = (vec([1.0, 1.0, 0.8, 1.0]), vec([0.4, 1.6, 0.0, 1.0]))
... ...
@@ -16,12 +16,26 @@ class Player(interactive.InteractiveCamera):
16 16
             roll_vec3(offset, 1)
17 17
             for s in range(2):
18 18
                 self.hud["skybox"].add_sq((d + 1) * (-1) ** s, 2 * VIEW_DIST, (-1) ** s * vec(offset), 2)
19
+        self.hud["sun"] = entity.Entity(
20
+            [[0.0, 0.0, 0.0], *[[2 * np.cos(2 * np.pi * k), 0, 2 * np.sin(2 * np.pi * k)] for k in np.arange(0, 1.01, 0.05)]],
21
+            [1.0, 1.0, 0.8, 1.0], normalise(LIGHT_POS) * VIEW_DIST, mode=GL_TRIANGLE_FAN
22
+        )
23
+        h = mesh.SquareMesh(hud=True)
24
+        self.hud["hand"] = h
25
+        h.add_sq(1, 1, [0.5, 0, 0], 1)
26
+        h.add_sq(2, 1, [0, 0.5, 0], 1)
27
+        h.add_sq(3, 1, [0, 0, 0.5], 1)
28
+        h.pos = [0.8, -0.8, 0.5]
29
+        h.rotate(2, [0, 1, 0])
30
+        h.rotate(-0.1, [1, 0, 0])
31
+        h.orient[:3, :3] *= 0.2
19 32
         self.hud["shl"] = mesh.SquareMesh()
20 33
         self.hud["shl"].draw_mode = GL_LINE_STRIP
21
-        self.hud["shl"].add_sq(2, 0.96, [0, 0, 0], 2)
34
+        self.hud["shl"].add_sq(-2, 0.96, [0, 0, 0], 2)
22 35
         self.hud["shl"].verts[:] = self.hud["shl"].verts[[0, 1, 3, 2, 0, 3]]
23 36
         self.hand = 1
24 37
         self.collides = True
38
+        self.falls = True
25 39
 
26 40
     def update_motion(self, pk, mg):
27 41
         netv = [pk[a] - pk[b] for (a, b) in zip(ARROWS[::2], ARROWS[1::2])]
... ...
@@ -29,10 +43,20 @@ class Player(interactive.InteractiveCamera):
29 43
             for i in range(len(netv)):
30 44
                 for s in range(2):
31 45
                     o = (-1) ** s * self.vdof()[i]
32
-                    if mg.voxel_at(self.pos + o):
46
+                    va = mg.voxel_at(self.pos + o)
47
+                    if va:
33 48
                         netv[i] = (max if s else min)(netv[i], 0)
49
+                    elif self.falls and i == 1 and s == 1:
50
+                        netv[i] = self.rv[i] - GRAVITY / FPS
34 51
         self.rv = vec(netv)
35 52
 
53
+    def set_hand(self, nh):
54
+        nh = int(nh)
55
+        self.hand = nh
56
+        self.hud["hand"].faces = [(a, self.hand) for (a, _) in self.hud["hand"].faces]
57
+        for i in range(1, 4, 2):
58
+            update_attr(self.hud["hand"], i)
59
+
36 60
     def handle_event(self, ev, mg, scene):
37 61
         super().handle_event(ev, mg)
38 62
         match ev.type:
... ...
@@ -40,15 +64,19 @@ class Player(interactive.InteractiveCamera):
40 64
                 if ev.unicode == "\x1b":
41 65
                     self.set_focus(False)
42 66
                 elif "1" <= ev.unicode <= "9":
43
-                    self.hand = int(ev.unicode)
67
+                    self.set_hand(int(ev.unicode))
44 68
                 elif ev.unicode == "n":
45 69
                     self.collides = not self.collides
70
+                elif ev.unicode == "f":
71
+                    self.falls = not self.falls
46 72
             case pygame.MOUSEBUTTONUP if ev.button == 1:
47 73
                 self.set_focus(True)
48 74
             case pygame.MOUSEBUTTONDOWN if self.get_focus():
49 75
                 t, n = self.target(scene)
50 76
                 if t:
51
-                    t.click(ev.button, n, self.hand)
77
+                    cr = t.click(ev.button, n, self.hand)
78
+                    if cr is not None:
79
+                        cr(self)
52 80
 
53 81
     def draw_hud(self, wrs, perf):
54 82
         self.hud["skybox"].pos = self.pos
... ...
@@ -57,8 +57,8 @@ class WorldRegion(mesh.SquareMesh):
57 57
                         bp, bc = bool(prev), bool(curr)
58 58
                         if bp ^ bc:
59 59
                             sq = vec([
60
-                                [0, 1, 1], [0, -1, 1], [0, 1, -1],
61
-                                [0, -1, -1], [0, 1, -1], [0, -1, 1]
60
+                                [0, 1, 1], [0, 1, -1], [0, -1, 1],
61
+                                [0, -1, -1], [0, -1, 1], [0, 1, -1]
62 62
                             ])
63 63
                             sq /= 2
64 64
                             if bp:
... ...
@@ -15,7 +15,7 @@ class WorldHolder():
15 15
             self.regions[pos] = wr
16 16
             self.world_natural(wr)
17 17
             wr.remesh()
18
-            wr.onclick = lambda s, b, c, h: self.click_region(s, b, c, h)
18
+            wr.onclick = (lambda s, b, c, h: self.click_region(s, b, c, h))
19 19
             return wr
20 20
 
21 21
     def voxel_at(self, pos, vt=None):
... ...
@@ -36,7 +36,7 @@ class WorldHolder():
36 36
             case 1:
37 37
                 wr.set_voxel(coords[1])
38 38
             case 2:
39
-                print(f"coords {coords}")
39
+                return (lambda pl: pl.set_hand(wr.grid[*coords[1]]))
40 40
             case 3:
41 41
                 offset = axis2offset(coords[0])
42 42
                 p = wr.set_voxel(coords[1] + offset, hand)
43 43