10 static void parse_cell(struct level *lvl, int x, int y, char c);
12 void init_level(struct level *lvl)
14 memset(lvl, 0, sizeof *lvl);
17 lvl->rects = darr_alloc(0, sizeof *lvl->rects);
20 void destroy_level(struct level *lvl)
22 darr_free(lvl->rects);
25 static int rect_area(struct level_rect *rect)
27 return rect->w * rect->h;
30 static int grow_rect(struct level *lvl, struct level_cell *orgcell, struct level_rect *rect)
32 int i, j, x, y, area_a, area_b;
33 struct level_rect ra, rb;
34 struct level_cell *cell;
38 /* try expanding horizontally first */
41 while(x++ < lvl->xsz && cell->type == CELL_SOLID) {
45 /* then for each line below, expand as long as we have at least ra.w space */
46 cell = orgcell + lvl->xsz;
48 while(y++ < lvl->ysz) {
51 while(x++ < lvl->xsz && cell->type == CELL_SOLID) {
55 if(rowsz < ra.w) break;
57 cell += lvl->xsz - rowsz;
60 /* then try the same thing, but vertical first */
61 cell = orgcell + lvl->xsz;
63 while(y++ < lvl->ysz && cell->type == CELL_SOLID) {
67 /* then for each next column, expand as long as we have at least rb.h space */
72 cell = lvl->cells + y * lvl->xsz + x;
73 while(y++ < lvl->ysz && cell->type == CELL_SOLID) {
77 if(colsz < rb.h) break;
82 /* return the rect with the largest area */
83 area_a = rect_area(&ra);
84 area_b = rect_area(&rb);
86 *rect = area_a > area_b ? ra : rb;
89 for(i=0; i<rect->h; i++) {
90 for(j=0; j<rect->w; j++) {
98 void lvl_gen_rects(struct level *lvl)
101 struct level_cell *cell;
102 struct level_rect rect;
104 darr_clear(lvl->rects);
106 for(i=0; i<lvl->ysz; i++) {
107 for(j=0; j<lvl->xsz; j++) {
114 for(i=0; i<lvl->ysz; i++) {
115 for(j=0; j<lvl->xsz; j++) {
116 if(cell->type == CELL_SOLID && !cell->visited) {
120 if(grow_rect(lvl, cell, &rect) != -1) {
121 rect.dbgcol[0] = (rand() & 0x7f) + 0x7f;
122 rect.dbgcol[1] = (rand() & 0x7f) + 0x7f;
123 rect.dbgcol[2] = (rand() & 0x7f) + 0x7f;
125 darr_push(lvl->rects, &rect);
133 int save_level(const struct level *lvl, const char *fname)
137 struct level_cell *cell;
138 struct level_rect *rect;
140 if(!(fp = fopen(fname, "wb"))) {
141 fprintf(stderr, "save_level: failed to open: %s: %s\n", fname, strerror(errno));
145 fprintf(fp, "RDLEVEL\n");
146 fprintf(fp, "size = %dx%d\n", lvl->xsz, lvl->ysz);
147 fprintf(fp, "scale = %f\n", lvl->scale);
149 fputs("\nMAPSTART\n", fp);
151 for(i=0; i<lvl->ysz; i++) {
152 for(j=0; j<lvl->xsz; j++) {
153 switch(cell->type & 0xff) {
155 if(lvl->sx == j && lvl->sy == i) {
157 } else if((cell->type & CELL_WALK) == 0) {
172 fputs("MAPEND\n", fp);
174 if(!darr_empty(lvl->rects)) {
175 num = darr_size(lvl->rects);
176 fprintf(fp, "\nRECTSTART %d\n", num);
178 for(i=0; i<num; i++) {
179 fprintf(fp, "rect %d %d %d %d\n", rect->x, rect->y, rect->w, rect->h);
182 fprintf(fp, "RECTEND\n\n");
185 fprintf(fp, "SDRSTART\n");
186 fprintf(fp, "float eval_sdf_gen(in vec3 p)\n");
189 for(i=0; i<num; i++) {
190 float cx = (rect->x - 0.5f + rect->w * 0.5f) * lvl->scale;
191 float cy = (rect->y - 0.5f + rect->h * 0.5f) * lvl->scale;
192 float rx = (rect->w + 0.1f) * lvl->scale * 0.5f;
193 float ry = (rect->h + 0.1f) * lvl->scale * 0.5f;
196 fprintf(fp, "\tfloat d = boxdist(p - vec3(%f, 0.0, %f), vec3(%f, 1.0, %f));\n",
199 fprintf(fp, "\td = min(d, boxdist(p - vec3(%f, 0.0, %f), vec3(%f, 1.0, %f)));\n",
204 fprintf(fp, "\treturn d;\n}\n");
205 fprintf(fp, "SDREND\n\n");
212 static char *clean_line(char *s)
216 while(*s && isspace(*s)) s++;
218 if(!(end = strchr(s, '#'))) {
219 end = s + strlen(s) - 1;
221 while(end >= s && isspace(*end)) *end-- = 0;
233 int load_level(struct level *lvl, const char *fname)
237 char *line, *val, *endp;
241 struct level_rect rect;
244 if(!(fp = ass_fopen(fname, "rb"))) {
245 fprintf(stderr, "load_level: failed to open: %s\n", fname);
249 while(ass_fgets(buf, sizeof buf, fp)) {
252 if(memcmp(buf, "RDLEVEL", 7) != 0) {
253 fprintf(stderr, "load_level: invalid level file: %s\n", fname);
261 if(!(line = clean_line(buf)) || *line == '#') {
265 if((val = strchr(line, '='))) {
268 if(!(val = clean_line(val))) {
269 fprintf(stderr, "load_level: ignoring invalid value for %s: %s\n", line, val);
272 if(strcmp(line, "size") == 0) {
274 if(sscanf(val, "%dx%d", &x, &y) != 2) {
275 fprintf(stderr, "load_level: ignoring invalid size: %s\n", val);
280 } else if(strcmp(line, "scale") == 0) {
281 fnum = strtod(val, &endp);
283 fprintf(stderr, "load_level: ignoring invalid scale: %s\n", val);
288 fprintf(stderr, "load_level: ignoring unknown option: %s\n", line);
292 } else if(strcmp(line, "MAPSTART") == 0) {
293 if(!lvl->xsz || !lvl->ysz) {
294 fprintf(stderr, "load_level: missing size before level data\n");
299 lvl->cells = calloc_nf(lvl->xsz * lvl->ysz, sizeof *lvl->cells);
303 } else if(strcmp(line, "SDRSTART") == 0) {
307 sdr = darr_alloc(0, 1);
311 } else if(sscanf(line, "rect %d %d %d %d", &rect.x, &rect.y, &rect.w, &rect.h) == 4) {
312 rect.dbgcol[0] = (rand() & 0x7f) + 0x7f;
313 rect.dbgcol[1] = (rand() & 0x7f) + 0x7f;
314 rect.dbgcol[2] = (rand() & 0x7f) + 0x7f;
315 darr_push(lvl->rects, &rect);
321 if(memcmp(buf, "MAPEND", 6) == 0) {
325 for(i=0; i<lvl->xsz; i++) {
327 parse_cell(lvl, i, nrow, buf[i]);
329 if(++nrow >= lvl->ysz) {
336 if(memcmp(buf, "SDREND", 6) == 0) {
340 for(i=0; buf[i]; i++) {
341 darr_strpush(sdr, buf[i]);
348 lvl->sdf_src = darr_finalize(sdr);
355 static void parse_cell(struct level *lvl, int x, int y, char c)
357 struct level_cell *cell = lvl->cells + y * lvl->xsz + x;
361 cell->type = CELL_OPEN | CELL_WALK;
365 cell->type = CELL_OPEN | CELL_WALK;
372 cell->type = CELL_OPEN;