Subversion Repositories Games.Descent

Rev

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
 * Functions for sizing segments
23
 *
24
 */
25
 
26
#include <stdlib.h>
27
#include "inferno.h"
28
#include "editor.h"
29
#include "editor/esegment.h"
30
#include "dxxerror.h"
31
#include "gameseg.h"
32
#include "kdefs.h"
33
 
34
#include "compiler-range_for.h"
35
#include "d_range.h"
36
 
37
#define XDIM    0
38
#define YDIM    1
39
#define ZDIM    2
40
 
41
#define MAX_MODIFIED_VERTICES   32
42
static std::array<int, MAX_MODIFIED_VERTICES>           Modified_vertices;
43
int             Modified_vertex_index = 0;
44
 
45
namespace dsx {
46
 
47
// ------------------------------------------------------------------------------------------
48
static void validate_modified_segments(void)
49
{
50
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
51
        auto &Vertices = LevelSharedVertexState.get_vertices();
52
        int     v0;
53
        visited_segment_bitarray_t modified_segments;
54
        auto &vcvertptr = Vertices.vcptr;
55
        for (int v=0; v<Modified_vertex_index; v++) {
56
                v0 = Modified_vertices[v];
57
 
58
                range_for (const auto &&segp, vmsegptridx)
59
                {
60
                        if (segp->segnum != segment_none)
61
                        {
62
                                if (modified_segments[segp])
63
                                        continue;
64
                                range_for (const auto w, segp->verts)
65
                                        if (w == v0)
66
                                        {
67
                                                modified_segments[segp] = true;
68
                                                validate_segment(vcvertptr, segp);
69
                                                for (unsigned s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
70
                                                        Num_tilings = 1;
71
                                                        assign_default_uvs_to_side(segp, s);
72
                                                }
73
                                                break;
74
                                        }
75
                        }
76
                }
77
        }
78
}
79
 
80
// ------------------------------------------------------------------------------------------
81
//      Scale vertex *vertp by vector *vp, scaled by scale factor scale_factor
82
static void scale_vert_aux(const unsigned vertex_ind, const vms_vector &vp, const fix scale_factor)
83
{
84
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
85
        auto &Vertices = LevelSharedVertexState.get_vertices();
86
        auto &vmvertptr = Vertices.vmptr;
87
        auto &vertp = *vmvertptr(vertex_ind);
88
 
89
        vertp.x += fixmul(vp.x,scale_factor)/2;
90
        vertp.y += fixmul(vp.y,scale_factor)/2;
91
        vertp.z += fixmul(vp.z,scale_factor)/2;
92
 
93
        Assert(Modified_vertex_index < MAX_MODIFIED_VERTICES);
94
        Modified_vertices[Modified_vertex_index++] = vertex_ind;
95
}
96
 
97
// ------------------------------------------------------------------------------------------
98
static void scale_vert(const shared_segment &sp, const unsigned vertex_ind, const vms_vector &vp, const fix scale_factor)
99
{
100
        auto &verts = sp.verts;
101
        switch (SegSizeMode) {
102
                case SEGSIZEMODE_FREE:
103
                        if (is_free_vertex(vertex_ind))
104
                                scale_vert_aux(vertex_ind, vp, scale_factor);
105
                        break;
106
                case SEGSIZEMODE_ALL:
107
                        scale_vert_aux(vertex_ind, vp, scale_factor);
108
                        break;
109
                case SEGSIZEMODE_CURSIDE: {
110
                        range_for (const auto v, Side_to_verts[Curside])
111
                                if (verts[v] == vertex_ind)
112
                                        scale_vert_aux(vertex_ind, vp, scale_factor);
113
                        break;
114
                }
115
                case SEGSIZEMODE_EDGE: {
116
                        range_for (const int v, xrange(2u))
117
                                if (verts[Side_to_verts[Curside][(Curedge+v)%4]] == vertex_ind)
118
                                        scale_vert_aux(vertex_ind, vp, scale_factor);
119
                        break;
120
                }
121
                case SEGSIZEMODE_VERTEX:
122
                        if (verts[Side_to_verts[Curside][Curvert]] == vertex_ind)
123
                                scale_vert_aux(vertex_ind, vp, scale_factor);
124
                        break;
125
                default:
126
                        Error("Unsupported SegSizeMode in ksegsize.c/scale_vert = %i\n", SegSizeMode);
127
        }
128
 
129
}
130
 
131
// ------------------------------------------------------------------------------------------
132
static void scale_free_verts(const vmsegptr_t sp, const vms_vector &vp, int side, fix scale_factor)
133
{
134
        int             vertex_ind;
135
        range_for (auto &v, Side_to_verts[side])
136
        {
137
                vertex_ind = sp->verts[v];
138
                if (SegSizeMode || is_free_vertex(vertex_ind))
139
                        scale_vert(sp, vertex_ind, vp, scale_factor);
140
        }
141
 
142
}
143
 
144
 
145
// -----------------------------------------------------------------------------
146
//      Make segment *sp bigger in dimension dimension by amount amount.
147
static void med_scale_segment_new(const vmsegptr_t sp, int dimension, fix amount)
148
{
149
        vms_matrix      mat;
150
 
151
        Modified_vertex_index = 0;
152
 
153
        med_extract_matrix_from_segment(sp, mat);
154
 
155
        const vms_vector *vec;
156
        unsigned side0, side1;
157
        switch (dimension) {
158
                case XDIM:
159
                        side0 = WLEFT;
160
                        side1 = WRIGHT;
161
                        vec = &mat.rvec;
162
                        break;
163
                case YDIM:
164
                        side0 = WBOTTOM;
165
                        side1 = WTOP;
166
                        vec = &mat.uvec;
167
                        break;
168
                case ZDIM:
169
                        side0 = WFRONT;
170
                        side1 = WBACK;
171
                        vec = &mat.fvec;
172
                        break;
173
                default:
174
                        return;
175
        }
176
        scale_free_verts(sp, *vec, side0, -amount);
177
        scale_free_verts(sp, *vec, side1, +amount);
178
 
179
        validate_modified_segments();
180
}
181
 
182
// ------------------------------------------------------------------------------------------
183
//      Extract a vector from a segment.  The vector goes from the start face to the end face.
184
//      The point on each face is the average of the four points forming the face.
185
static void extract_vector_from_segment_side(const vmsegptr_t sp, const unsigned side, vms_vector &vp, const unsigned vla, const unsigned vlb, const unsigned vra, const unsigned vrb)
186
{
187
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
188
        auto &Vertices = LevelSharedVertexState.get_vertices();
189
        auto &sv = Side_to_verts[side];
190
        auto &verts = sp->verts;
191
        auto &vcvertptr = Vertices.vcptr;
192
        const auto v1 = vm_vec_sub(vcvertptr(verts[sv[vra]]), vcvertptr(verts[sv[vla]]));
193
        const auto v2 = vm_vec_sub(vcvertptr(verts[sv[vrb]]), vcvertptr(verts[sv[vlb]]));
194
        vm_vec_add(vp, v1, v2);
195
        vm_vec_scale(vp, F1_0/2);
196
}
197
 
198
// ------------------------------------------------------------------------------------------
199
//      Extract the right vector from segment *sp, return in *vp.
200
//      The forward vector is defined to be the vector from the the center of the left face of the segment
201
// to the center of the right face of the segment.
202
void med_extract_right_vector_from_segment_side(const vmsegptr_t sp, int sidenum, vms_vector &vp)
203
{
204
        extract_vector_from_segment_side(sp, sidenum, vp, 3, 2, 0, 1);
205
}
206
 
207
// ------------------------------------------------------------------------------------------
208
//      Extract the up vector from segment *sp, return in *vp.
209
//      The forward vector is defined to be the vector from the the center of the bottom face of the segment
210
// to the center of the top face of the segment.
211
void med_extract_up_vector_from_segment_side(const vmsegptr_t sp, int sidenum, vms_vector &vp)
212
{
213
        extract_vector_from_segment_side(sp, sidenum, vp, 1, 2, 0, 3);
214
}
215
 
216
 
217
// -----------------------------------------------------------------------------
218
//      Increase the size of Cursegp in dimension dimension by amount
219
static int segsize_common(int dimension, fix amount)
220
{
221
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
222
        auto &Vertices = LevelSharedVertexState.get_vertices();
223
        vms_vector      uvec, rvec, fvec, scalevec;
224
 
225
        Degenerate_segment_found = 0;
226
 
227
        med_scale_segment_new(Cursegp, dimension, amount);
228
 
229
        med_extract_up_vector_from_segment_side(Cursegp, Curside, uvec);
230
        med_extract_right_vector_from_segment_side(Cursegp, Curside, rvec);
231
        auto &vcvertptr = Vertices.vcptr;
232
        extract_forward_vector_from_segment(vcvertptr, Cursegp, fvec);
233
 
234
        scalevec.x = vm_vec_mag(rvec);
235
        scalevec.y = vm_vec_mag(uvec);
236
        scalevec.z = vm_vec_mag(fvec);
237
 
238
        if (Degenerate_segment_found) {
239
                Degenerate_segment_found = 0;
240
                editor_status("Applying scale would create degenerate segments.  Aborting scale.");
241
                med_scale_segment_new(Cursegp, dimension, -amount);
242
                return 1;
243
        }
244
 
245
        med_create_new_segment(scalevec);
246
 
247
        //      For all segments to which Cursegp is connected, propagate tmap (uv coordinates) from the connected
248
        //      segment back to Cursegp.  This will meaningfully propagate uv coordinates to all sides which havve
249
        //      an incident edge.  It will also do some sides more than once.  And it is probably just not what you want.
250
        std::array<int, MAX_SIDES_PER_SEGMENT> propagated = {};
251
        for (int i=0; i<MAX_SIDES_PER_SEGMENT; i++)
252
        {
253
                const auto c = Cursegp->children[i];
254
                if (IS_CHILD(c))
255
                {
256
                        range_for (auto &s, propagated)
257
                                ++s;
258
                        propagated[static_cast<int>(Side_opposite[i])]--;
259
                        med_propagate_tmaps_to_segments(vmsegptridx(c), Cursegp, 1);
260
                }
261
        }
262
 
263
        //      Now, for all sides that were not adjacent to another side, and therefore did not get tmaps
264
        //      propagated to them, treat as a back side.
265
        for (int i=0; i<MAX_SIDES_PER_SEGMENT; i++)
266
                if (!propagated[i]) {
267
                        med_propagate_tmaps_to_back_side(Cursegp, i, 1);
268
                }
269
 
270
        //      New stuff, assign default texture to all affected sides.
271
 
272
        Update_flags |= UF_WORLD_CHANGED;
273
        mine_changed = 1;
274
        return 1;
275
}
276
 
277
// -----------------------------------------------------------------------------
278
// ---------- segment size control ----------
279
 
280
int IncreaseSegLength()
281
{
282
        return segsize_common(ZDIM,+F1_0);
283
}
284
 
285
int DecreaseSegLength()
286
{
287
        return segsize_common(ZDIM,-F1_0);
288
}
289
 
290
int DecreaseSegWidth()
291
{
292
        return segsize_common(XDIM,-F1_0);
293
}
294
 
295
int IncreaseSegWidth()
296
{
297
        return segsize_common(XDIM,+F1_0);
298
}
299
 
300
int IncreaseSegHeight()
301
{
302
        return segsize_common(YDIM,+F1_0);
303
}
304
 
305
int DecreaseSegHeight()
306
{
307
        return segsize_common(YDIM,-F1_0);
308
}
309
 
310
 
311
int IncreaseSegLengthBig()
312
{
313
        return segsize_common(ZDIM,+5 * F1_0);
314
}
315
 
316
int DecreaseSegLengthBig()
317
{
318
        return segsize_common(ZDIM,-5 * F1_0);
319
}
320
 
321
int DecreaseSegWidthBig()
322
{
323
        return segsize_common(XDIM,-5 * F1_0);
324
}
325
 
326
int IncreaseSegWidthBig()
327
{
328
        return segsize_common(XDIM,+5 * F1_0);
329
}
330
 
331
int IncreaseSegHeightBig()
332
{
333
        return segsize_common(YDIM,+5 * F1_0);
334
}
335
 
336
int DecreaseSegHeightBig()
337
{
338
        return segsize_common(YDIM,-5 * F1_0);
339
}
340
 
341
 
342
int IncreaseSegLengthDefault()
343
{
344
        return segsize_common(ZDIM,+40 *F1_0);
345
}
346
 
347
int DecreaseSegLengthDefault()
348
{
349
        return segsize_common(ZDIM,-40*F1_0);
350
}
351
 
352
int IncreaseSegWidthDefault()
353
{
354
        return segsize_common(XDIM,+40*F1_0);
355
}
356
 
357
int DecreaseSegWidthDefault()
358
{
359
        return segsize_common(XDIM,-40*F1_0);
360
}
361
 
362
int IncreaseSegHeightDefault()
363
{
364
        return segsize_common(YDIM,+40 * F1_0);
365
}
366
 
367
int DecreaseSegHeightDefault()
368
{
369
        return segsize_common(YDIM,-40 * F1_0);
370
}
371
 
372
 
373
//      ---------------------------------------------------------------------------
374
int ToggleSegSizeMode(void)
375
{
376
        SegSizeMode++;
377
        if (SegSizeMode > SEGSIZEMODE_MAX)
378
                SegSizeMode = SEGSIZEMODE_MIN;
379
 
380
        return 1;
381
}
382
 
383
//      ---------------------------------------------------------------------------
384
static int      PerturbCursideCommon(fix amount)
385
{
386
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
387
        auto &Vertices = LevelSharedVertexState.get_vertices();
388
        int                     saveSegSizeMode = SegSizeMode;
389
        vms_vector      fvec, rvec, uvec;
390
        fix                     fmag, rmag, umag;
391
        SegSizeMode = SEGSIZEMODE_CURSIDE;
392
 
393
        Modified_vertex_index = 0;
394
 
395
        auto &vcvertptr = Vertices.vcptr;
396
        extract_forward_vector_from_segment(vcvertptr, Cursegp, fvec);
397
        extract_right_vector_from_segment(vcvertptr, Cursegp, rvec);
398
        extract_up_vector_from_segment(vcvertptr, Cursegp, uvec);
399
 
400
        fmag = vm_vec_mag(fvec);
401
        rmag = vm_vec_mag(rvec);
402
        umag = vm_vec_mag(uvec);
403
 
404
        range_for (const auto v, Side_to_verts[Curside])
405
        {
406
                vms_vector perturb_vec;
407
                perturb_vec.x = fixmul(rmag, d_rand()*2 - 32767);
408
                perturb_vec.y = fixmul(umag, d_rand()*2 - 32767);
409
                perturb_vec.z = fixmul(fmag, d_rand()*2 - 32767);
410
                scale_vert(Cursegp, Cursegp->verts[v], perturb_vec, amount);
411
        }
412
 
413
//      validate_segment(Cursegp);
414
//      if (SegSizeMode) {
415
//              for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
416
//                      if (Cursegp->children[i] != -1)
417
//                              validate_segment(&Segments[Cursegp->children[i]]);
418
//      }
419
 
420
        validate_modified_segments();
421
        SegSizeMode = saveSegSizeMode;
422
 
423
        Update_flags |= UF_WORLD_CHANGED;
424
        mine_changed = 1;
425
 
426
        return 1;
427
}
428
 
429
//      ---------------------------------------------------------------------------
430
int     PerturbCurside(void)
431
{
432
        PerturbCursideCommon(F1_0/10);
433
 
434
        return 1;
435
}
436
 
437
//      ---------------------------------------------------------------------------
438
int     PerturbCursideBig(void)
439
{
440
        PerturbCursideCommon(F1_0/2);
441
 
442
        return 1;
443
}
444
 
445
}