Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /* |
2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
3 | * described in COPYING.txt. |
||
4 | * Portions of this file are copyright Parallax Software and licensed |
||
5 | * according to the Parallax license below. |
||
6 | * See COPYING.txt for license details. |
||
7 | |||
8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
17 | COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
18 | */ |
||
19 | |||
20 | /* |
||
21 | * |
||
22 | * Texture map assignment. |
||
23 | * |
||
24 | */ |
||
25 | |||
26 | #include <stdio.h> |
||
27 | #include <stdlib.h> |
||
28 | #include <stdarg.h> |
||
29 | #include <math.h> |
||
30 | #include <string.h> |
||
31 | #include "inferno.h" |
||
32 | #include "segment.h" |
||
33 | #include "seguvs.h" |
||
34 | #include "editor.h" |
||
35 | #include "editor/esegment.h" |
||
36 | #include "maths.h" |
||
37 | #include "dxxerror.h" |
||
38 | #include "kdefs.h" |
||
39 | |||
40 | #include "compiler-range_for.h" |
||
41 | |||
42 | static uvl compute_uv_side_center(const unique_segment &segp, sidenum_fast_t sidenum); |
||
43 | static void rotate_uv_points_on_side(unique_segment &segp, sidenum_fast_t sidenum, const std::array<fix, 4> &rotmat, const uvl &uvcenter); |
||
44 | |||
45 | // ----------------------------------------------------------- |
||
46 | int TexFlipX() |
||
47 | { |
||
48 | const auto uvcenter = compute_uv_side_center(Cursegp, Curside); |
||
49 | std::array<fix, 4> rotmat; |
||
50 | // Create a rotation matrix |
||
51 | rotmat[0] = -0xffff; |
||
52 | rotmat[1] = 0; |
||
53 | rotmat[2] = 0; |
||
54 | rotmat[3] = 0xffff; |
||
55 | |||
56 | rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter); |
||
57 | |||
58 | Update_flags |= UF_WORLD_CHANGED; |
||
59 | |||
60 | return 1; |
||
61 | } |
||
62 | |||
63 | // ----------------------------------------------------------- |
||
64 | int TexFlipY() |
||
65 | { |
||
66 | const auto uvcenter = compute_uv_side_center(Cursegp, Curside); |
||
67 | std::array<fix, 4> rotmat; |
||
68 | // Create a rotation matrix |
||
69 | rotmat[0] = 0xffff; |
||
70 | rotmat[1] = 0; |
||
71 | rotmat[2] = 0; |
||
72 | rotmat[3] = -0xffff; |
||
73 | |||
74 | rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter); |
||
75 | |||
76 | Update_flags |= UF_WORLD_CHANGED; |
||
77 | |||
78 | return 1; |
||
79 | } |
||
80 | |||
81 | // ----------------------------------------------------------- |
||
82 | static int DoTexSlideLeft(int value) |
||
83 | { |
||
84 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
85 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
86 | uvl duvl03; |
||
87 | fix dist; |
||
88 | auto &vp = Side_to_verts[Curside]; |
||
89 | auto &uvls = Cursegp->unique_segment::sides[Curside].uvls; |
||
90 | |||
91 | auto &vcvertptr = Vertices.vcptr; |
||
92 | dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[3]]), vcvertptr(Cursegp->verts[vp[0]])); |
||
93 | dist *= value; |
||
94 | if (dist < F1_0/(64*value)) |
||
95 | dist = F1_0/(64*value); |
||
96 | |||
97 | duvl03.u = fixdiv(uvls[3].u - uvls[0].u,dist); |
||
98 | duvl03.v = fixdiv(uvls[3].v - uvls[0].v,dist); |
||
99 | |||
100 | range_for (auto &v, uvls) |
||
101 | { |
||
102 | v.u -= duvl03.u; |
||
103 | v.v -= duvl03.v; |
||
104 | } |
||
105 | |||
106 | Update_flags |= UF_WORLD_CHANGED; |
||
107 | |||
108 | return 1; |
||
109 | } |
||
110 | |||
111 | int TexSlideLeft() |
||
112 | { |
||
113 | return DoTexSlideLeft(3); |
||
114 | } |
||
115 | |||
116 | int TexSlideLeftBig() |
||
117 | { |
||
118 | return DoTexSlideLeft(1); |
||
119 | } |
||
120 | |||
121 | // ----------------------------------------------------------- |
||
122 | static int DoTexSlideUp(int value) |
||
123 | { |
||
124 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
125 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
126 | uvl duvl03; |
||
127 | fix dist; |
||
128 | auto &vp = Side_to_verts[Curside]; |
||
129 | auto &uvls = Cursegp->unique_segment::sides[Curside].uvls; |
||
130 | |||
131 | auto &vcvertptr = Vertices.vcptr; |
||
132 | dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[1]]), vcvertptr(Cursegp->verts[vp[0]])); |
||
133 | dist *= value; |
||
134 | |||
135 | if (dist < F1_0/(64*value)) |
||
136 | dist = F1_0/(64*value); |
||
137 | |||
138 | duvl03.u = fixdiv(uvls[1].u - uvls[0].u,dist); |
||
139 | duvl03.v = fixdiv(uvls[1].v - uvls[0].v,dist); |
||
140 | |||
141 | range_for (auto &v, uvls) |
||
142 | { |
||
143 | v.u -= duvl03.u; |
||
144 | v.v -= duvl03.v; |
||
145 | } |
||
146 | |||
147 | Update_flags |= UF_WORLD_CHANGED; |
||
148 | |||
149 | return 1; |
||
150 | } |
||
151 | |||
152 | int TexSlideUp() |
||
153 | { |
||
154 | return DoTexSlideUp(3); |
||
155 | } |
||
156 | |||
157 | int TexSlideUpBig() |
||
158 | { |
||
159 | return DoTexSlideUp(1); |
||
160 | } |
||
161 | |||
162 | |||
163 | // ----------------------------------------------------------- |
||
164 | static int DoTexSlideDown(int value) |
||
165 | { |
||
166 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
167 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
168 | uvl duvl03; |
||
169 | fix dist; |
||
170 | auto &vp = Side_to_verts[Curside]; |
||
171 | auto &uvls = Cursegp->unique_segment::sides[Curside].uvls; |
||
172 | |||
173 | auto &vcvertptr = Vertices.vcptr; |
||
174 | dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[1]]), vcvertptr(Cursegp->verts[vp[0]])); |
||
175 | dist *= value; |
||
176 | if (dist < F1_0/(64*value)) |
||
177 | dist = F1_0/(64*value); |
||
178 | |||
179 | duvl03.u = fixdiv(uvls[1].u - uvls[0].u,dist); |
||
180 | duvl03.v = fixdiv(uvls[1].v - uvls[0].v,dist); |
||
181 | |||
182 | range_for (auto &v, uvls) |
||
183 | { |
||
184 | v.u += duvl03.u; |
||
185 | v.v += duvl03.v; |
||
186 | } |
||
187 | |||
188 | Update_flags |= UF_WORLD_CHANGED; |
||
189 | |||
190 | return 1; |
||
191 | } |
||
192 | |||
193 | int TexSlideDown() |
||
194 | { |
||
195 | return DoTexSlideDown(3); |
||
196 | } |
||
197 | |||
198 | int TexSlideDownBig() |
||
199 | { |
||
200 | return DoTexSlideDown(1); |
||
201 | } |
||
202 | |||
203 | // ----------------------------------------------------------- |
||
204 | // Compute the center of the side in u,v coordinates. |
||
205 | static uvl compute_uv_side_center(const unique_segment &segp, const sidenum_fast_t sidenum) |
||
206 | { |
||
207 | uvl uvcenter{}; |
||
208 | range_for (auto &v, segp.sides[sidenum].uvls) |
||
209 | { |
||
210 | uvcenter.u += v.u; |
||
211 | uvcenter.v += v.v; |
||
212 | } |
||
213 | uvcenter.u /= 4; |
||
214 | uvcenter.v /= 4; |
||
215 | return uvcenter; |
||
216 | } |
||
217 | |||
218 | // ----------------------------------------------------------- |
||
219 | // rotate point *uv by matrix rotmat, return *uvrot |
||
220 | static uvl rotate_uv_point(const std::array<fix, 4> &rotmat, const uvl &uv, const uvl &uvcenter) |
||
221 | { |
||
222 | const auto centered_u = uv.u - uvcenter.u; |
||
223 | const auto centered_v = uv.v - uvcenter.v; |
||
224 | return { |
||
225 | fixmul(centered_u, rotmat[0]) + fixmul(centered_v, rotmat[1]) + uvcenter.u, |
||
226 | fixmul(centered_u, rotmat[2]) + fixmul(centered_v, rotmat[3]) + uvcenter.v, |
||
227 | |||
228 | }; |
||
229 | } |
||
230 | |||
231 | // ----------------------------------------------------------- |
||
232 | // Compute the center of the side in u,v coordinates. |
||
233 | static void rotate_uv_points_on_side(unique_segment &segp, const sidenum_fast_t sidenum, const std::array<fix, 4> &rotmat, const uvl &uvcenter) |
||
234 | { |
||
235 | range_for (auto &v, segp.sides[sidenum].uvls) |
||
236 | { |
||
237 | v = rotate_uv_point(rotmat, v, uvcenter); |
||
238 | } |
||
239 | } |
||
240 | |||
241 | // ----------------------------------------------------------- |
||
242 | // ang is in 0..ffff = 0..359.999 degrees |
||
243 | // rotmat is filled in with 4 fixes |
||
244 | static std::array<fix, 4> create_2d_rotation_matrix(fix ang) |
||
245 | { |
||
246 | const auto &&a = fix_sincos(ang); |
||
247 | const auto &sinang = a.sin; |
||
248 | const auto &cosang = a.cos; |
||
249 | return {{ |
||
250 | cosang, |
||
251 | sinang, |
||
252 | -sinang, |
||
253 | cosang |
||
254 | }}; |
||
255 | } |
||
256 | |||
257 | |||
258 | // ----------------------------------------------------------- |
||
259 | static int DoTexRotateLeft(int value) |
||
260 | { |
||
261 | const auto uvcenter = compute_uv_side_center(Cursegp, Curside); |
||
262 | // Create a rotation matrix |
||
263 | const auto rotmat = create_2d_rotation_matrix(-F1_0/value); |
||
264 | |||
265 | rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter); |
||
266 | |||
267 | Update_flags |= UF_WORLD_CHANGED; |
||
268 | |||
269 | return 1; |
||
270 | } |
||
271 | |||
272 | int TexRotateLeft() |
||
273 | { |
||
274 | return DoTexRotateLeft(192); |
||
275 | } |
||
276 | |||
277 | int TexRotateLeftBig() |
||
278 | { |
||
279 | return DoTexRotateLeft(64); |
||
280 | } |
||
281 | |||
282 | |||
283 | // ----------------------------------------------------------- |
||
284 | static int DoTexSlideRight(int value) |
||
285 | { |
||
286 | auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state(); |
||
287 | auto &Vertices = LevelSharedVertexState.get_vertices(); |
||
288 | uvl duvl03; |
||
289 | fix dist; |
||
290 | auto &vp = Side_to_verts[Curside]; |
||
291 | auto &uvls = Cursegp->unique_segment::sides[Curside].uvls; |
||
292 | |||
293 | auto &vcvertptr = Vertices.vcptr; |
||
294 | dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[3]]), vcvertptr(Cursegp->verts[vp[0]])); |
||
295 | dist *= value; |
||
296 | if (dist < F1_0/(64*value)) |
||
297 | dist = F1_0/(64*value); |
||
298 | |||
299 | duvl03.u = fixdiv(uvls[3].u - uvls[0].u,dist); |
||
300 | duvl03.v = fixdiv(uvls[3].v - uvls[0].v,dist); |
||
301 | |||
302 | range_for (auto &v, uvls) |
||
303 | { |
||
304 | v.u += duvl03.u; |
||
305 | v.v += duvl03.v; |
||
306 | } |
||
307 | |||
308 | Update_flags |= UF_WORLD_CHANGED; |
||
309 | |||
310 | return 1; |
||
311 | } |
||
312 | |||
313 | int TexSlideRight() |
||
314 | { |
||
315 | return DoTexSlideRight(3); |
||
316 | } |
||
317 | |||
318 | int TexSlideRightBig() |
||
319 | { |
||
320 | return DoTexSlideRight(1); |
||
321 | } |
||
322 | |||
323 | // ----------------------------------------------------------- |
||
324 | static int DoTexRotateRight(int value) |
||
325 | { |
||
326 | const auto uvcenter = compute_uv_side_center(Cursegp, Curside); |
||
327 | |||
328 | // Create a rotation matrix |
||
329 | const auto rotmat = create_2d_rotation_matrix(F1_0/value); |
||
330 | |||
331 | rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter); |
||
332 | |||
333 | Update_flags |= UF_WORLD_CHANGED; |
||
334 | |||
335 | return 1; |
||
336 | } |
||
337 | |||
338 | int TexRotateRight() |
||
339 | { |
||
340 | return DoTexRotateRight(192); |
||
341 | } |
||
342 | |||
343 | int TexRotateRightBig() |
||
344 | { |
||
345 | return DoTexRotateRight(64); |
||
346 | } |
||
347 | |||
348 | // ----------------------------------------------------------- |
||
349 | int TexSelectActiveEdge() |
||
350 | { |
||
351 | return 1; |
||
352 | } |
||
353 | |||
354 | // ----------------------------------------------------------- |
||
355 | int TexRotate90Degrees() |
||
356 | { |
||
357 | const auto uvcenter = compute_uv_side_center(Cursegp, Curside); |
||
358 | |||
359 | // Create a rotation matrix |
||
360 | const auto rotmat = create_2d_rotation_matrix(F1_0/4); |
||
361 | |||
362 | rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter); |
||
363 | |||
364 | Update_flags |= UF_WORLD_CHANGED; |
||
365 | |||
366 | return 1; |
||
367 | } |
||
368 | |||
369 | // ----------------------------------------------------------- |
||
370 | int TexSetDefault() |
||
371 | { |
||
372 | Num_tilings = 1; |
||
373 | |||
374 | Stretch_scale_x = F1_0; |
||
375 | Stretch_scale_y = F1_0; |
||
376 | |||
377 | assign_default_uvs_to_side(Cursegp,Curside); |
||
378 | |||
379 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
380 | return 1; |
||
381 | } |
||
382 | |||
383 | // ----------------------------------------------------------- |
||
384 | int TexIncreaseTiling() |
||
385 | { |
||
386 | |||
387 | Num_tilings++; |
||
388 | assign_default_uvs_to_side(Cursegp, Curside); |
||
389 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
390 | |||
391 | return 1; |
||
392 | } |
||
393 | |||
394 | // ----------------------------------------------------------- |
||
395 | int TexDecreaseTiling() |
||
396 | { |
||
397 | |||
398 | if (--Num_tilings < 1) |
||
399 | Num_tilings = 1; |
||
400 | |||
401 | assign_default_uvs_to_side(Cursegp, Curside); |
||
402 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
403 | |||
404 | return 1; |
||
405 | } |
||
406 | |||
407 | |||
408 | // direction = -1 or 1 depending on direction |
||
409 | static int TexStretchCommon(int direction) |
||
410 | { |
||
411 | fix *sptr; |
||
412 | |||
413 | if ((Curedge == 0) || (Curedge == 2)) |
||
414 | sptr = &Stretch_scale_x; |
||
415 | else |
||
416 | sptr = &Stretch_scale_y; |
||
417 | |||
418 | *sptr += direction*F1_0/64; |
||
419 | |||
420 | if (*sptr < F1_0/16) |
||
421 | *sptr = F1_0/16; |
||
422 | |||
423 | if (*sptr > 2*F1_0) |
||
424 | *sptr = 2*F1_0; |
||
425 | |||
426 | stretch_uvs_from_curedge(Cursegp, Curside); |
||
427 | |||
428 | editor_status_fmt("Stretch scale = %7.4f, use Set Default to return to 1.0", f2fl(*sptr)); |
||
429 | |||
430 | Update_flags |= UF_GAME_VIEW_CHANGED; |
||
431 | return 1; |
||
432 | |||
433 | } |
||
434 | |||
435 | int TexStretchDown(void) |
||
436 | { |
||
437 | return TexStretchCommon(-1); |
||
438 | |||
439 | } |
||
440 | |||
441 | int TexStretchUp(void) |
||
442 | { |
||
443 | return TexStretchCommon(1); |
||
444 | |||
445 | } |
||
446 |