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