1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package my3d;
import java.util.ArrayList;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
import my3d._math3d.*;
import my3d._shape3d.*;
public class _viewport3d2 extends _viewport3d {
private static final int ALLOC_RD_BUF_SIZE = 50;
public _viewport3d2(Canvas view) {
super(view);
render_flag = 0;
for (int i = 0; i < alloc_rd_buf.length; i++)
alloc_rd_buf[i] = new _render_data();
pick_color = Color.RED;
}
private boolean b_zsort;
public boolean is_zsort_enable() { return b_zsort; }
public void set_zsort_enable(boolean b) { b_zsort = b; }
private static final int RENDER_ZSORT = 0x1;
private int render_flag;
private int shape_index;
@Override public void begin_render() {
super.begin_render();
if (b_zsort)
render_flag |= RENDER_ZSORT;
if (render_flag != 0) {
rd_list.clear();
alloc_rd_clear();
}
shape_index = 0;
}
protected boolean is_picked(_shape3d shape, _face face) {
return pick_mode != _pick_mode.None &&
(shape_index == pick_shape_index) &&
(pick_mode == _pick_mode.Shape ||
shape.faces.indexOf(face) == pick_face_index);
}
@Override
protected Color get_color(_shape3d shape, _face face) {
if (is_picked(shape, face)) return pick_color;
return super.get_color(shape, face);
}
@Override
public void end_render() {
while (render_flag != 0) {
// Zソート法
if ((render_flag & RENDER_ZSORT) != 0) {
rd_list.sort((rd1, rd2) -> (int)Math.signum(rd2.z - rd1.z));
render_flag &= ~RENDER_ZSORT;
}
// ピック処理
else if ((render_flag & RENDER_PICK) != 0) {
pick_listener.picked(pick_shape_index, pick_face_index);
render_flag &= ~RENDER_PICK;
}
// 描画情報を再送
for (_render_data rd : rd_list) {
tf_curr = rd.tf;
shape_index = rd.index;
render_shape(rd.shape);
}
}
}
@Override
public void render_shape(_shape3d shape) {
if (pre_render_shape(shape)) return;
super.render_shape(shape);
}
protected boolean pre_render_shape(_shape3d shape) {
if ((render_flag & RENDER_ZSORT) != 0) { // Zソート法
_vector v = shape.center;
v = (v != null) ?
_math3d.mul(tf_curr, v, v_buf1) : tf_curr.position;
add_render_data(shape, tf_curr, v.z);
return true;
} else if ((render_flag & RENDER_PICK) != 0) { // ビック処理
_vector[] vertices = shape.vertices;
for (int i = 0; i < vertices.length; i++)
_math3d.mul(tf_curr, vertices[i], va_buf[i]);
ArrayList<_face> faces = shape.faces;
for (_face face : faces) {
if (pick_face(face, va_buf)) {
pick_shape_index = shape_index;
pick_face_index = faces.indexOf(face);
break;
}
}
add_render_data(shape, tf_curr, 0);
return true;
}
return false;
}
private static class _render_data {
public _shape3d shape;
public _transform tf;
public double z;
public int index;
public _render_data set(_shape3d shape, _transform tf, double z, int index) {
this.shape = shape; this.tf = tf; this.z = z; this.index = index;
return this;
}
}
private _render_data[] alloc_rd_buf = new _render_data[ALLOC_RD_BUF_SIZE];
private int alloc_rd_pos = 0;
private void alloc_rd_clear() { alloc_rd_pos = 0; }
private _render_data alloc_rd() { return alloc_rd_buf[alloc_rd_pos++]; }
private ArrayList<_render_data> rd_list = new ArrayList<>();
private void add_render_data(_shape3d shape, _transform tf, double z) {
if (shape_index < rd_list.size()) return;
_render_data rd = alloc_rd();
rd.set(shape, tf, z, shape_index++);
rd_list.add(rd);
}
// ピック処理
public static enum _pick_mode {
Shape, Face, None
}
public static interface _pick_listener {
public void picked(int shape_index, int face_index);
}
private static final int RENDER_PICK = 0x2;
private int pick_shape_index = -1, pick_face_index = -1;
private _vector v_pick = new _vector();
private _pick_mode pick_mode = _pick_mode.None;
public void set_pick_mode(_pick_mode pick_mode) {
this.pick_mode = pick_mode;
}
private Color pick_color;
private _pick_listener pick_listener;
public void pick(double x, double y, _pick_listener lis) {
pick_shape_index = -1;
pick_face_index = -1;
_math3d.mul(get_ray(x, y, v_pick), clip_back, v_pick);
render_flag |= RENDER_PICK;
pick_listener = lis;
}
private boolean pick_face(_face face, _vector[] vertices) {
int n = get_vertices(face.vertex_indices, vertices, va, v_buf_normal);
if (n == 0) return false;
double len = _math3d.dot(va[0], v_buf_normal);
double k = len / _math3d.dot(v_pick, v_buf_normal);
if (k > 1 || k < 0) return false;
_math3d.mul(v_pick, k, v_buf1);
int index = get_max_index(v_buf_normal);
_vector v1, v2, v3;
double s1, s2, s3;
for (int i = 0; i < n - 2; i++) {
v1 = va[0];
v2 = va[i + 1];
v3 = va[i + 2];
s1 = get_square(v_buf1, v2, v3, index);
s2 = get_square(v_buf1, v3, v1, index);
s3 = get_square(v_buf1, v1, v2, index);
if ((s1 < 0 == s2 < 0) && (s2 < 0 == s3 < 0)) {
v_pick.set(v_buf1);
return true;
}
}
return false;
}
protected double get_square(
_vector v1, _vector v2, _vector v3,
int index) {
double x1, x2, y1, y2;
if (index == 0) {
x1 = v2.y - v1.y; x2 = v3.y - v1.y;
y1 = v2.z - v1.z; y2 = v3.z - v1.z;
} else if (index == 1) {
x1 = v2.z - v1.z; x2 = v3.z - v1.z;
y1 = v2.x - v1.x; y2 = v3.x - v1.x;
} else {
x1 = v2.x - v1.x; x2 = v3.x - v1.x;
y1 = v2.y - v1.y; y2 = v3.y - v1.y;
}
return x1 * y2 - x2 * y1;
}
protected int get_max_index(_vector v) {
double x = Math.abs(v.x), y = Math.abs(v.y), z = Math.abs(v.z);
return (x > y) ?
(x > z ? 0 : 2) :
(y > z ? 1 : 2);
}
}