Commit | Line | Data |
---|---|---|
852fb5ae | 1 | from panda3d.core import CullFaceAttrib, Point3, NodePath, Point2, Texture, \ |
bdfa6dda | 2 | Plane, Vec3, BitMask32 |
06af3aa9 | 3 | from panda3d.bullet import BulletBoxShape, BulletRigidBodyNode, BulletGhostNode |
7850ccc4 | 4 | from direct.gui.OnscreenText import OnscreenText |
13263131 | 5 | from lib.lib.p3d.gfx import P3dGfxMgr |
1be87278 | 6 | |
852fb5ae | 7 | |
1be87278 FC |
8 | class Box: |
9 | ||
7850ccc4 | 10 | def __init__(self, world, plane_node, count, cb_inst): |
c8d8653f | 11 | self._world = world |
7850ccc4 FC |
12 | self._plane_node = plane_node |
13 | self._count = count | |
14 | self._cb_inst = cb_inst | |
a0acba9a | 15 | self._paused = False |
06af3aa9 FC |
16 | self._shape = BulletBoxShape((.5, .5, .5)) |
17 | self.node = BulletGhostNode('box') | |
18 | self.node.add_shape(self._shape) | |
c8d8653f | 19 | self._np = render.attach_new_node(self.node) |
06af3aa9 FC |
20 | world.attach_ghost(self.node) |
21 | self._model = loader.load_model('assets/gltf/box/box.gltf') | |
22 | self._model.flatten_light() | |
23 | self._model.reparent_to(self._np) | |
c8d8653f | 24 | self._set_outline_model() |
bdfa6dda FC |
25 | self._model.hide(BitMask32(0x01)) |
26 | self._outline_model.hide(BitMask32(0x01)) | |
c8d8653f | 27 | self._start_drag_pos = None |
9ba5488b | 28 | self._prev_rot_info = None |
7850ccc4 | 29 | self._instantiated = False |
5964572b | 30 | self._box_tsk = taskMgr.add(self.on_frame, 'on_frame') |
651713a9 | 31 | self._repos() |
7850ccc4 | 32 | |
651713a9 | 33 | def _repos(self): |
13263131 | 34 | p_from, p_to = P3dGfxMgr.world_from_to((-1, 1)) |
7850ccc4 FC |
35 | for hit in self._world.ray_test_all(p_from, p_to).get_hits(): |
36 | if hit.get_node() == self._plane_node: | |
37 | pos = hit.get_hit_pos() | |
13263131 | 38 | corner = P3dGfxMgr.screen_coord(pos) |
7850ccc4 | 39 | bounds = self._np.get_tight_bounds() |
651713a9 | 40 | bounds = bounds[0] - self._np.get_pos(), bounds[1] - self._np.get_pos() |
13263131 | 41 | self._np.set_pos(pos) |
852fb5ae FC |
42 | plane = Plane(Vec3(0, 1, 0), bounds[0][1]) |
43 | pos3d, near_pt, far_pt = Point3(), Point3(), Point3() | |
44 | margin, ar = .04, base.get_aspect_ratio() | |
45 | margin_x = margin / ar if ar >= 1 else margin | |
46 | margin_z = margin * ar if ar < 1 else margin | |
47 | base.camLens.extrude((-1 + margin_x, 1 - margin_z), near_pt, far_pt) | |
48 | plane.intersects_line( | |
49 | pos3d, render.get_relative_point(base.camera, near_pt), | |
50 | render.get_relative_point(base.camera, far_pt)) | |
51 | delta = Vec3(bounds[1][0], bounds[1][1], bounds[0][2]) | |
52 | self._np.set_pos(pos3d + delta) | |
651713a9 FC |
53 | if not hasattr(self, '_txt'): |
54 | font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') | |
55 | font.clear() | |
56 | font.set_pixels_per_unit(60) | |
57 | font.set_minfilter(Texture.FTLinearMipmapLinear) | |
58 | font.set_outline((0, 0, 0, 1), .8, .2) | |
59 | self._txt = OnscreenText( | |
60 | str(self._count), font=font, scale=0.06, fg=(.9, .9, .9, 1)) | |
13263131 FC |
61 | pos = self._np.get_pos() + (bounds[1][0], bounds[0][1], bounds[0][2]) |
62 | p2d = P3dGfxMgr.screen_coord(pos) | |
63 | self._txt['pos'] = p2d | |
64 | ||
65 | def get_corner(self): | |
66 | bounds = self._np.get_tight_bounds() | |
67 | return bounds[1][0], bounds[1][1], bounds[0][2] | |
37ba71d8 | 68 | |
c8d8653f | 69 | def _set_outline_model(self): |
37ba71d8 FC |
70 | self._outline_model = loader.load_model('assets/gltf/box/box.gltf') |
71 | clockw = CullFaceAttrib.MCullClockwise | |
72 | self._outline_model.set_attrib(CullFaceAttrib.make(clockw)) | |
c8d8653f | 73 | self._outline_model.reparent_to(self._np) |
37ba71d8 FC |
74 | self._outline_model.set_scale(-1.08, -1.08, -1.08) |
75 | self._outline_model.set_light_off() | |
76 | self._outline_model.set_color(.4, .4, .4, 1) | |
77 | self._outline_model.set_color_scale(.4, .4, .4, 1) | |
78 | self._outline_model.hide() | |
1be87278 | 79 | |
49c79300 FC |
80 | def on_frame(self, task): |
81 | self._np.set_y(0) | |
82 | return task.cont | |
83 | ||
c8d8653f | 84 | def play(self): |
06af3aa9 FC |
85 | if not self._instantiated: |
86 | return | |
c8d8653f FC |
87 | self._world.remove_rigid_body(self.node) |
88 | self.node.set_mass(1) | |
89 | self._world.attach_rigid_body(self.node) | |
90 | ||
49c79300 | 91 | def on_click_l(self, pos): |
a0acba9a | 92 | if self._paused: return |
c8d8653f | 93 | self._start_drag_pos = pos, self._np.get_pos() |
54a1397e | 94 | loader.load_sfx('assets/audio/sfx/grab.ogg').play() |
7850ccc4 | 95 | if not self._instantiated: |
06af3aa9 FC |
96 | self._world.remove_ghost(self.node) |
97 | pos = self._np.get_pos() | |
98 | self._np.remove_node() | |
99 | self.node = BulletRigidBodyNode('box') | |
100 | self.node.add_shape(self._shape) | |
101 | self._np = render.attach_new_node(self.node) | |
102 | self._world.attach_rigid_body(self.node) | |
103 | self._model.reparent_to(self._np) | |
104 | self._np.set_pos(pos) | |
105 | self._set_outline_model() | |
bdfa6dda FC |
106 | self._model.show(BitMask32(0x01)) |
107 | self._outline_model.show(BitMask32(0x01)) | |
7850ccc4 FC |
108 | self._instantiated = True |
109 | self._txt.destroy() | |
110 | self._count -= 1 | |
111 | if self._count: | |
112 | box = Box(self._world, self._plane_node, self._count, self._cb_inst) | |
113 | self._cb_inst(box) | |
c8d8653f | 114 | |
49c79300 | 115 | def on_click_r(self, pos): |
a0acba9a | 116 | if self._paused: return |
9ba5488b | 117 | self._prev_rot_info = pos, self._np.get_pos(), self._np.get_r() |
54a1397e | 118 | loader.load_sfx('assets/audio/sfx/grab.ogg').play() |
49c79300 | 119 | |
c8d8653f | 120 | def on_release(self): |
9ba5488b | 121 | if self._start_drag_pos or self._prev_rot_info: |
54a1397e | 122 | loader.load_sfx('assets/audio/sfx/release.ogg').play() |
9ba5488b | 123 | self._start_drag_pos = self._prev_rot_info = None |
37ba71d8 FC |
124 | |
125 | def on_mouse_on(self): | |
a0acba9a FC |
126 | if not self._paused: |
127 | self._outline_model.show() | |
37ba71d8 FC |
128 | |
129 | def on_mouse_off(self): | |
9ba5488b | 130 | if self._start_drag_pos or self._prev_rot_info: return |
37ba71d8 | 131 | self._outline_model.hide() |
c8d8653f FC |
132 | |
133 | def on_mouse_move(self, pos): | |
49c79300 FC |
134 | if self._start_drag_pos: |
135 | d_pos = pos - self._start_drag_pos[0] | |
136 | self._np.set_pos(self._start_drag_pos[1] + d_pos) | |
9ba5488b FC |
137 | if self._prev_rot_info: |
138 | start_vec = self._prev_rot_info[0] - self._prev_rot_info[1] | |
139 | curr_vec = pos - self._prev_rot_info[1] | |
49c79300 | 140 | d_angle = curr_vec.signed_angle_deg(start_vec, (0, -1, 0)) |
9ba5488b FC |
141 | self._np.set_r(self._prev_rot_info[2] + d_angle) |
142 | self._prev_rot_info = pos, self._np.get_pos(), self._np.get_r() | |
651713a9 FC |
143 | |
144 | def on_aspect_ratio_changed(self): | |
145 | if not self._instantiated: | |
146 | self._repos() | |
a0acba9a FC |
147 | |
148 | def store_state(self): | |
149 | self._paused = True | |
150 | self._model.set_transparency(True) | |
151 | self._model.set_alpha_scale(.3) | |
152 | self._txt.set_alpha_scale(.3) | |
153 | ||
154 | def restore_state(self): | |
155 | self._paused = False | |
156 | self._model.set_alpha_scale(1) | |
157 | self._txt.set_alpha_scale(1) | |
5964572b FC |
158 | |
159 | def destroy(self): | |
160 | self._np.remove_node() | |
161 | taskMgr.remove(self._box_tsk) | |
162 | self._txt.destroy() |