1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * jbaird Wed Jul 18 03:52:41 PM CDT 2001
17 * Author: Jayson Baird
18 * E-Mail: jbaird@ncsa.uiuc.edu
19 *
20 * If you make any changes to this, drop me a line, patch, etc.
21 * I'm curious to seen what improvements can be made.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <math.h>
30
31 /** this is the class that holds our pixel type. Arbitrary to say the least. **/
32 #include "MapSquare.cc"
33
34 /**
35 catch SIGINT and deal with it...
36 **/
37 void signal_handler(int signum)
38 {
39 switch(signum) {
40 case SIGINT:
41 printf("\nRecieved interrupt signal. Exiting.\n");
42 exit(0);
43 default:
44 printf("\nUnknown signal recieved. Ignoring.\n");
45 }
46 }
47
48 /**
49 a random number generator that generates a double between 0.0 and 1.0
50 **/
51 double doubleNoise(double x, double y)
52 {
53 int n = 0;
54 n = int(x) + int(y) * (57 * rand());
55 int nShift = n << 13;
56 n = nShift ^ n;
57 return (1.0 - ((int)(n * (n * n * 15731 + 789221) + 1376312589) & 0xffffff) / 1073741824.0);
58 }
59
60 /**
61 interpolate the points v0 and v1 with relation to x
62 **/
63 double cosineInterpolation(double v0, double v1, double x)
64 {
65 double ft = x * M_PI;
66 double f = (1 - cos(ft)) * 0.5;
67
68 return v0 * (1 - f) + (v1 * f);
69 }
70
71 /**
72 smooth the points based on the grid specifics
73 **/
74 double smoothNoise(double x, double y)
75 {
76 x = int(x);
77 y = int(y);
78 double corners = (doubleNoise(x-1, y-1) + doubleNoise(x+1, y-1) + doubleNoise(x-1, y+1) +
79 doubleNoise(x+1, y+1)) / 16;
80 double sides = (doubleNoise(x-1, y) + doubleNoise(x+1, y) + doubleNoise(x, y-1) +
81 doubleNoise(x, y+1)) / 8;
82 double center = doubleNoise(x, y) / 4;
83
84 return corners + sides + center;
85 }
86
87 /**
88 create the noise, smooth it and return the interpolated point.
89 **/
90 double InterpolateNoise(double x, double y)
91 {
92 int intX = int(x);
93 double fracX = x - intX;
94
95 int intY = int(y);
96 double fracY = y - intY;
97
98 double v1, v2, v3, v4, i1, i2;
99 v1 = smoothNoise(intX, intY);
100 v2 = smoothNoise(intX + 1, intY);
101 v3 = smoothNoise(intX, intY + 1);
102 v4 = smoothNoise(intX + 1, intY + 1);
103
104 i1 = cosineInterpolation(v1, v2, fracX);
105 i2 = cosineInterpolation(v3, v4, fracX);
106
107 return cosineInterpolation(i1, i2, fracY);
108 }
109
110 /**
111 the function that generates the entire map with Perlin Noise.
112 try playing with the persistence and numOctaves variables or the
113 gridSize
114 **/
115 double perlinNoise2D(double x, double y)
116 {
117 double persistence = 1/4;
118 int numOctaves = 4;
119 int gridSize = 20;
120 double total = 0.0;
121 for(int i = 0; i < numOctaves; i++) {
122 double frequency = pow(2, (double)i);
123 double amplitude = pow(persistence, (double)i);
124 total = total + InterpolateNoise((x / gridSize) * frequency, (y / gridSize) * amplitude) * amplitude;
125 }
126
127 return total;
128 }
129
130 /**
131 do it already...
132 **/
133 int main(int argc, char *argv[])
134 {
135 if(argc < 2) {
136 printf("Useage: %s <map size>\n", argv[0]);
137 exit(1);
138 }
139
140 signal(SIGINT, signal_handler);
141
142 int mapSize;
143 mapSize = atoi(argv[1]);
144
145 MapSquare *map[mapSize][mapSize];
146
147 /* place holders for world building timing */
148 time_t starttime, endtime;
149
150 /**
151 build the world
152 NOTE: this is extremely memory and computationally expensive,
153 but hey, it works. If you find any better way to do it, let
154 me know.
155 **/
156 starttime = time(NULL);
157 for(int i = 0; i < mapSize; i++) {
158 for(int j = 0; j < mapSize; j++) {
159 /**
160 .9920 is an arbitrary threshold value that can be
161 changed to the users liking. I picked .9920...
162 **/
163 if(perlinNoise2D((double)i, (double)j) < .9920) {
164 map[i][j] = new MapSquare(i, j, 'g');
165 } else {
166 map[i][j] = new MapSquare(i, j, 'w');
167 }
168 }
169 }
170 endtime = time(NULL);
171
172 /* report on the world building statistics ... */
173 printf("World built in %d sec(s) using %d KB worth of memory.\n", (endtime - starttime), sizeof(map) / 1024);
174
175 //add here functions to save the map to a file, or display it with SDL, etc.
176
177 return 0;
178 }