3 Additional code by Dave
16 To compile this on unixen, do
18 cc -lm curve.c -o curve
22 #define MAX_HELP_TXTS 17
25 #define M_PI 3.14159265358979323846
31 int innerdrop, outerdrop, hill;
45 const char *helptxt[MAX_HELP_TXTS] = {
49 " -The inner radius can be any number from zero on up.\n"
50 " -You might choose a value of 0, if you wanted to do a disc-shaped\n"
51 " platform, or filled circle (you could join all of the lumps\n"
52 " together in gtkradiant to keep the lump count low...)",
55 " -The outer radius can be any number as long as it is larger than\n"
58 /* 3: choice on radii */
59 " -You may specify an entirely different set of radii for the ending\n"
60 " portion of your curve. If you do so, it will be smoothly transitioned\n"
61 " between the beginning and the end.\n"
62 " -By using this feature, it is easy to create swirls, and spirals.",
64 /* 4: ending inner radius */
65 " -The ending inner radius can be any number from zero on up.\n"
66 " -It can smaller than, larger than, or exactly equal to the\n"
67 " beginning inner radius.",
69 /* 5: ending outer radius */
70 " -The ending outer radius can be any number as long as it is\n"
71 " larger than the ending inner radius.\n"
72 " -It can smaller than, larger than, or exactly equal to the\n"
73 " beginning outer radius.",
75 /* 6: number of lumps */
76 " -The number of lumps will determine the \"coarseness\" of the curve.\n"
77 " Less lumps = coarser - More lumps = smoother\n"
78 " Be careful not to use too many lumps, though, as this can actually\n"
79 " lead to certain sloped curves being even more coarse due to the alignment\n"
80 " on the 1-unit grid.\n"
81 " -If you go into the \"advanced\" curve settings, the number of lumps you\n"
82 " specify in this step will be doubled, as each lump will be split into\n"
83 " two triangular sections. This can be desirable even when you are not going\n"
84 " to create a sloped/angled/hilled curve, if you plan on rotating your curve\n"
85 " in gtkradiant in some other fashion than the typical 90-degree angles.",
87 /* 7: beginning angle */
88 " -The beginning angle is given in degrees and can be any value(+ or -).",
90 /* 8: ending radius */
91 " -The ending angle is given in degrees and can be any value(+ or -).\n"
92 " -You can specify greater than 360 degrees, most useful for creating spirals-\n"
93 " simple \"snail-shell\"-style spirals, or sloped \"cork screw\"-style spirals.",
96 " -Thickness can be any value greater than zero.\n"
97 " -If you plan on doing an angled curve(with inner or outer drop), or hill,\n"
98 " you should take into account how much drop or hill value you desire, as\n"
99 " that figure will be subtracted from the thickness you specify in this step.",
101 /* 10: advanced or not? */
102 " -In the advanced settings, you can specify slope, inner an outer drop,\n"
103 " hill value, and whether or not to use constant thickness.\n"
104 " -Also, if you go into the advanced settings section of the questions, the\n"
105 " number of lumps will automatically double, as each lump will be split in\n"
106 " two triangular pieces.\n"
107 " -You do not have to use any of the advanced settings available if you\n"
108 " go into that section - you might just want the lumps split in two.\n"
109 " This is useful if you plan on rotating your curve in some other fashion\n"
110 " than the typical 90-degree angles.",
113 " -The slope of the curve specifies the number of vertical units total,\n"
114 " from the start to the end, that you wish the curve to ascend or descend.\n"
115 " -This number can be positive(ascend), negative(descend), or zero.\n"
116 " -Best results are achieved when the number of units specified in this step\n"
117 " is a multiple of the number of lumps (e.g. lumps = 8, slope = 64),\n"
118 " although it will still produce a very even slope if the numbers don't\n"
119 " have this relationship.\n"
120 " -To create a loop de loop, simply create a sloped, 360 degree curve where\n"
121 " the slope value is higher than the thickness of the curve.\n"
122 " Then rotate it on the x or y axis in gtkradiant.",
125 " -Inner drop must be at least one unit smaller than the thickness value.\n"
126 " It can also be zero.\n"
127 " -This determines how much to \"drop\" the inner, top portion of the curve.\n"
128 " This results in a curve which is angled inwards.\n"
129 " -You can combine this option with the \"hill\" option to get banked curves,\n"
130 " similar to those you might find at a race-track.",
133 " -Outer drop must be at least one unit smaller than the thickness value.\n"
134 " It can also be zero.\n"
135 " -This determines how much to \"drop\" the outer, top portion of the curve.\n"
136 " This results in a curve which is angled outwards.",
139 " -Hill must be at least one unit smaller than the thickness value.\n"
140 " It can also be zero.\n"
141 " -This figure determines how much to lower the ends of the curve. They will\n"
142 " rise from the ends toward the middle, in a smooth sine-wave shaped hill.\n"
143 " -This can be combined with the inner or outer drop option, creating a \"hill\"\n"
144 " which rises on only one side. In this case, it is best to use the same\n"
145 " value for \"hill\" as you did for inner or outer drop.",
147 /* 15: constant thickness */
148 " -By default, the curve generator will attempt to give a constant thickness\n"
149 " in the lumps, by raising or lowering opposite corners by similar amounts.\n"
150 " -By deselecting this feature, the bottom portions of the lump will not be\n"
151 " adjusted, which can be desirable for variety of reasons, which is why\n"
152 " this option is available.\n"
153 " -The best way to understand how this feature works is to create either\n"
154 " an angled(inner or outer drop) or hill-shaped curve, and do one with\n"
155 " constant thickness on, and then another one with it turned off.",
158 " -It is recommended to end your filename with \".map\", so that you can\n"
159 " import immediately into gtkradiant. You can, of course, rename the file\n"
160 " manually after it is created.\n"
161 " -Do not include spaces when entering the filename, or your filename will\n"
162 " only be that which occurs before the first space.\n"
163 " -If you specify a filename which already exists, it will be overwritten.\n"
164 " Be aware that if you have already imported that file into gtkradiant,\n"
165 " you will either need to rename the file, or close and re-open your map,\n"
166 " in order to avoid the \"cached\" version of the file used by gtkradiant."
169 void showhelp(int which)
171 if (which > 0 && which < MAX_HELP_TXTS)
172 printf("\n%s\n\n", helptxt[which]);
175 void showusage(FILE *fp, char *fn)
177 fprintf(fp, "Usage: %s <r0> <r1> <n> <a0> <a1> <t> <r2> <r3> <s> <id> <od> <h> <ct> \n"
178 "r0 - inner radius\n"
179 "r1 - outer radius\n"
180 "n - number of lumps (will be doubled if sloped,angled,or hill-shaped)\n"
181 "a0 - beginning angle\n"
182 "a1 - ending angle\n"
183 "t - thickness of curve\n"
184 "r2 - ending inner radius(can be >,<, or = r0)\n"
185 "r3 - ending outer radius(can be >,<, or = r1)\n"
186 "s - vertical slope from beginning to end\n"
187 "id - vertical drop of curve's inner radius(inward angled)\n"
188 "od - vertical drop of curve's outer radius(outward angled)\n"
189 "h - vertical drop for both ends of curve (hill)\n"
190 "ct - zero will override default of constant thickness for angle/hill curves\n",fn );
196 get_input_num(char *name, int defaultval, int helpnum, int minval, int maxval, int *retval)
202 printf("\nPlease enter %s (default = %d) -> ", name, defaultval);
205 if (str[0] == 'x') return 1;
207 if (str[0] == '?') showhelp(helpnum);
208 else if (isdigit(str[0]) || (str[0] == '-') || str[0] == 'd') {
209 if (str[0] == 'd') i = defaultval;
211 if (i < minval || i > maxval) printf("Please enter \"?\", \"x\", \"d\" or an integer value between %d and %d.", minval, maxval);
216 } else printf("Please enter \"?\", \"x\", \"d\" or an integer value between %d and %d.", minval, maxval);
221 get_input_yn(char *question, char defval, int helpnum)
226 printf("\n%s? (y/n/?) -> ", question);
229 if (str[0] == '?') showhelp(helpnum);
230 else if (str[0] == 'y' || str[0] == 'n') return str[0];
235 static int rndnum(int low, int high)
239 srand((unsigned int) time(NULL));
243 return (rand() % ((high-low) +1)) + low;
246 static void side(double x0, double y0, double z0,
247 double x1, double y1, double z1,
248 double x2, double y2, double z2, char *tex)
250 double modx, mody, modz; /*for doing a grid of curves*/
259 modz = ((row + col) % 2) * 256.0;
263 printf("( %f %f %f ) ( %f %f %f ) ( %f %f %f ) "
264 "%s 0 0 0 0.500000 0.500000 0 0 0\n",
265 x0+modx, y0+mody, z0+modz,
266 x1+modx, y1+mody, z1+modz,
267 x2+modx, y2+mody, z2+modz, tex);
270 static void lump(int r0, int r1, double a0, double a1, int i, int n)
272 double x00 = (r0+((double)(r2-r0)*((i)/(double)n))) * cos(M_PI * a0 / 180.0);
273 double y00 = (r0+((double)(r2-r0)*((i)/(double)n))) * sin(M_PI * a0 / 180.0);
275 double x10 = (r1+((double)(r3-r1)*((i)/(double)n))) * cos(M_PI * a0 / 180.0);
276 double y10 = (r1+((double)(r3-r1)*((i)/(double)n))) * sin(M_PI * a0 / 180.0);
278 double x01 = (r0+((double)(r2-r0)*((i+1.0f)/(double)n))) * cos(M_PI * a1 / 180.0);
279 double y01 = (r0+((double)(r2-r0)*((i+1.0f)/(double)n))) * sin(M_PI * a1 / 180.0);
281 double x11 = (r1+((double)(r3-r1)*((i+1.0f)/(double)n))) * cos(M_PI * a1 / 180.0);
282 double y11 = (r1+((double)(r3-r1)*((i+1.0f)/(double)n))) * sin(M_PI * a1 / 180.0);
285 double z1 = thickness;
291 /*just use rlk's code */
292 side(x00, y00, z0, x01, y01, z0, x00, y00, z1, intex);
293 side(x10, y10, z1, x11, y11, z1, x10, y10, z0, outtex);
294 side(x00, y00, z1, x10, y10, z1, x00, y00, z0, blanktex);
295 side(x01, y01, z0, x11, y11, z0, x01, y01, z1, blanktex);
297 side(0, 0, z0, 1, 0, z0, 0, 1, z0, bottex);
298 side(0, 0, z1, 0, 1, z1, 1, 0, z1, toptex);
302 /*use Dave's code! */
303 double stepsize = totalstep/(double)n;
304 double zmod0=(double)i * stepsize;
305 double zmod1=(double)(i+1) * stepsize; /*this goes up! */
306 double hillmodinside=0,hillmodoutside=0;
307 double hmi2=0,hmo2=0;
308 double cthi1=0,cthi2=0,ctho1=0,ctho2=0;
312 /*do one based on sinewave. */
313 double mult1=((sin((((360.0f/(double)n)*(double)i)-90.0) * M_PI / 180.0)+1.0)/2.0);
314 double mult2=((sin((((360.0f/(double)n)*(double)(i+1))-90.0) * M_PI / 180.0)+1.0)/2.0);
315 if (innerdrop>=outerdrop)
317 /*then it's the outside needs altered */
318 hillmodoutside=hill-(mult1*(double)hill) ;
319 hmo2=hill-(mult2*(double)hill) ;
320 ctho1=hill-hillmodoutside;
323 if (outerdrop>=innerdrop)
325 hillmodinside=hill-(mult1*(double)hill) ;
326 hmi2=hill-(mult2*(double)hill) ;
327 cthi1=hill-hillmodinside;
330 /*end of sinewave hill code*/
331 if (innerdrop>outerdrop)
333 cthi1-=hillmodoutside; cthi2-=hmo2;
336 if (outerdrop>innerdrop )
337 {ctho1-=hillmodinside; ctho2-=hmi2;
339 } /*end of "hill" code */
348 side(x11, y11, ((z1+zmod1)-outerdrop)-hmo2, x10, y10, ((z1+zmod0)-outerdrop)-hillmodoutside, x00, y00, ((z1+zmod0)-innerdrop)-hillmodinside, toptex);
349 side(x00, y00, z0+zmod0+((outerdrop+ctho1)*ct), x10, y10, z0+zmod0+((innerdrop+cthi1)*ct), x11, y11, z0+zmod1+((innerdrop+cthi2)*ct), bottex);
350 side(x11, y11, ((z1+zmod1)-outerdrop)-hmo2, x11, y11, z0+zmod1+((innerdrop+cthi2)*ct), x10, y10, z0+zmod0+((innerdrop+cthi1)*ct), outtex);
351 side(x10, y10, ((z1+zmod0)-outerdrop)-hillmodoutside, x10, y10, z0+zmod0+((innerdrop+cthi1)*ct), x00, y00, z0+zmod0+((outerdrop+ctho1)*ct), blanktex);
352 side(x11, y11, ((z1+zmod1)-outerdrop)-hmo2, x00, y00, z0+zmod0+((outerdrop+ctho1)*ct), x11, y11, z0+zmod1+((innerdrop+cthi2)*ct), blanktex);
354 printf("}\n{\n"); /*next one... */
356 side(x00, y00, ((z1+zmod0)-innerdrop)-hillmodinside, x01, y01, ((z1+zmod1)-innerdrop)-hmi2, x11, y11, ((z1+zmod1)-outerdrop)-hmo2, toptex);
357 side(x11, y11, z0+zmod1+((innerdrop+cthi2)*ct), x01, y01, z0+zmod1+((outerdrop+ctho2)*ct), x00, y00, z0+zmod0+((outerdrop+ctho1)*ct), bottex);
358 side(x00, y00, ((z1+zmod0)-innerdrop)-hillmodinside, x00, y00, z0+zmod0+((outerdrop+ctho1)*ct), x01, y01, z0+zmod1+((outerdrop+ctho2)*ct), intex);
359 side(x01, y01, ((z1+zmod1)-innerdrop)-hmi2, x01, y01, z0+zmod1+((outerdrop+ctho2)*ct), x11, y11, z0+zmod1+((innerdrop+cthi2)*ct), blanktex);
360 side(x00, y00, ((z1+zmod0)-innerdrop)-hillmodinside, x11, y11, z0+zmod1+((innerdrop+cthi2)*ct), x00, y00, z0+zmod0+((outerdrop+ctho1)*ct), blanktex);
362 /*end of Dave's code! */
368 void gettextures(void)
370 /*default = mtrl/invisible*/
372 char c1[256],c2[256];
374 strcpy(toptex,"mtrl/invisible");
375 strcpy(bottex,"mtrl/invisible");
376 strcpy(intex, "mtrl/invisible");
377 strcpy(outtex,"mtrl/invisible");
378 strcpy(blanktex,"mtrl/invisible");
380 fp = fopen("textures.txt","r");
385 for (i = 0; i<4; i++)
387 huh = fscanf(fp,"%s %s",c1,c2);
390 if (strcmp(c1,"TOP") == 0) sprintf(toptex,"mtrl/%s",c2);
391 if (strcmp(c1,"BOT") == 0) sprintf(bottex,"mtrl/%s",c2);
392 if (strcmp(c1,"IN") == 0) sprintf(intex, "mtrl/%s",c2);
393 if (strcmp(c1,"OUT") == 0) sprintf(outtex,"mtrl/%s",c2);
402 int main(int argc, char *argv[])
425 if (argc > 1 && strcmp(argv[1], "-?") == 0)
427 showusage(stderr, argv[0]);
428 fprintf(stderr, "\nOther ways to use this program :\n"
429 "%s -? : This help screen.\n"
430 "%s -readme : creates a readme.txt file with detailed help information.\n"
431 "%s -textures : creates a textures.txt, editable for auto-texture placement.\n"
432 "%s -random : creates a random curve; add -lots for a grid of 16 curves.\n"
433 "%s : (no parameters) runs a basic user-interface to aid your curve creation.\n",
434 argv[0],argv[0],argv[0],argv[0],argv[0]);
436 else if (argc > 1 && strcmp(argv[1], "-readme") == 0)
438 fprintf(stderr, "Detailed information about each setting has been placed in readme.txt\n");
439 freopen("readme.txt", "w" ,stdout);
440 showusage(stdout,argv[0]);
441 for ( i=0; i<MAX_HELP_TXTS; i++) showhelp(i);
443 else if (argc > 1 && strcmp(argv[1], "-textures") == 0)
446 fprintf(stderr, "textures.txt can be edited to specify the textures that you wish to apply to\n"
447 "the top, bottom, inside, and outside of the subsequently generated curves.");
448 f = fopen("textures.txt", "w");
449 fprintf(f,"TOP invisible\n"
459 /*Engage the so called user-interface... */
466 printf("During the input process, typing a lowercase \"x\" and pressing Enter will\n");
467 printf(" accept the default for that question and all of the remaining questions,\n"
468 " and proceed to the file output step.\n");
469 printf("Typing \"d\" and Enter will accept the default for that particular question.\n");
470 printf("Typing a \"?\" and pressing Enter will give you a description of that variable.\n\n");
472 okay = get_input_num("INNER RADIUS", r0, 1, 0, 65536, &retval);
473 if (okay) goto getfilename;
474 r0 = retval; r2 = r0;
476 okay = get_input_num("OUTER RADIUS", r1, 2, r0+1, 65535, &retval);
477 if (okay) goto getfilename;
478 r1 = retval; r3 = r1;
480 ynchar = get_input_yn("Do you wish to have the same radii from beginning to end", 'y', 3);
482 okay = get_input_num("ENDING INNER RADIUS", r2, 4, 0, 65535, &retval);
483 if (okay) goto getfilename;
486 okay = get_input_num("ENDING OUTER RADIUS", r3, 5, r2+1, 65535, &retval);
487 if (okay) goto getfilename;
491 okay = get_input_num("NUMBER OF LUMPS", n, 6, 1, 65535, &retval);
492 if (okay) goto getfilename;
495 okay = get_input_num("BEGINNING ANGLE", a0, 7, -65535, 65535, &retval);
496 if (okay) goto getfilename;
499 okay = get_input_num("ENDING ANGLE", a1, 8, -65535, 65535, &retval);
500 if (okay) goto getfilename;
503 okay = get_input_num("THICKNESS", thickness, 9, 1, 65536, &retval);
504 if (okay) goto getfilename;
507 ynchar = get_input_yn("Do you wish to use any advanced curve settings", 'n', 10);
508 if (ynchar == 'n') goto getfilename;
510 okay = get_input_num("SLOPE", totalstep, 11, -65535, 65535, &retval);
512 if (okay) goto getfilename;
515 okay = get_input_num("INNER DROP", innerdrop, 12, 0, thickness - 1, &retval);
516 if (okay) goto getfilename;
519 okay = get_input_num("OUTER DROP", outerdrop, 13, 0, thickness - 1, &retval);
520 if (okay) goto getfilename;
523 okay = get_input_num("HILL", hill, 14, 0, thickness - 1, &retval);
524 if (okay) goto getfilename;
527 ynchar = get_input_yn("Would you like to use the CONSTANT THICKNESS feature", 'y', 15);
528 ct = (ynchar == 'y') ? 1 : 0;
534 printf("\nPlease enter filename for your curve -> ");
539 okay=1; /*accept what they typed... */
542 freopen(str, "w", stdout); /*setup stdout redirect */
544 } /* end of interactive user input */
547 if (strcmp(argv[1],"-random") != 0)
548 { /* use the command line inputs... */
551 r0 = atoi(argv[1]); r2=r0;
555 r1 = atoi(argv[2]); r3=r1;
564 thickness = atoi(argv[6]);
570 { /*can specify 0, for segmentation, but no slope. */
571 totalstep = atoi(argv[9]); usesteps=1;
574 innerdrop= atoi(argv[10]);
576 outerdrop= atoi(argv[11]);
578 hill= atoi(argv[12]);
580 ct=atoi(argv[13]); /*any non-zero number keeps curves constant thickness.. */
586 /*it's the random curve generator */
587 lots = 1; /*just an indicator that we need a random number*/
588 if ((argc > 2) && (strcmp(argv[2],"-lots")==0))
592 } /* end of command line input */
598 r0 = rndnum(0, 256/8) * 8; r2=r0;
600 r1 = r0 + rndnum(8/8, 256/8) * 8; r3=r1;
602 if (rndnum(1,100)<=40)
603 r2 = rndnum(0,256/8) * 8;
604 if (rndnum(1,100)<=40)
605 r3 = r2 + rndnum(8/8,256/8) * 8;
607 a0 = rndnum(0,7) * 45;
608 a1 = a0 + (rndnum(2,16) * 45);
612 if (rndnum(1,100)<=50)
613 thickness = rndnum(8/8,64/8) * 8;
615 thickness = rndnum(1,2) * 128;
617 if (rndnum(1,100)<=40)
618 totalstep = rndnum(1,16) * 32;
624 if (rndnum(1,100)<=40)
626 if (rndnum(1,100)<=50)
630 innerdrop = rndnum(1,(thickness - 8)/8) * 8;
638 outerdrop = rndnum(1,(thickness - 8)/8) * 8;
645 if (rndnum(1,100)<=40)
649 hill = rndnum(2,(thickness - 16)/8) * 8;
655 if (rndnum(1,100)<=25)
660 printf("\"classname\" \"worldspawn\"\n");
661 printf("// This curve was created with the following parameters :\n"
662 "// curve %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
663 r0,r1,n,a0,a1,thickness,r2,r3,totalstep,innerdrop,outerdrop,hill,ct);
665 for (i = 0; i < n; i++)
667 double ai0 = (double) (i ) * (a1 - a0) / n + a0;
668 double ai1 = (double) (i + 1) * (a1 - a0) / n + a0;
670 lump(r0, r1, ai0, ai1, i, n);
675 } while (iter < lots);