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