proclib/ktkProgram.c

325 lines
12 KiB
C

#include "ktkProgram.h"
#include <stdlib.h>
int ktk_current_depth = 0;
const struct ktkProgram ktk_PROGRAM_DEFAULT = {
NULL, // *structures
NULL, // **char of structure names
0 // count of above fields
};
int ktk_freeProgram(struct ktkProgram *program) {
int i;
if (program->structure_count < 1) return 1;
for (i = 0; i < program->structure_count; i++) {
//ktk_deleteStructure(program->structures[i]);
free(program->structure_name[i]);
}
free(program->structures);
free(program->structure_name);
return 0;
}
int ktk_runProgram(struct ktkProgram *program, struct ktkMap *map) {
int i, j;
for (i = 0; i < program->structure_count; i++) {
printf("%d: %s\n", i, program->structure_name[i]);
printf("x(%d-%d): %d\n", program->structures[i].x.a, program->structures[i].x.b, ktk_rollNumber(program->structures[i].x));
printf(" rel: ");
for (j = 0; j < program->structures[i].relation_count; j++) {
printf(" %d: %s\n", j, program->structures[i].relations[j].name);
}
printf("\n");
}
return 0;
}
struct ktkStructure *ktk_getStructure(struct ktkProgram *program, const char *structure_name) {
int i;
for (i = 0; i < program->structure_count; i++) {
if (strcmp(program->structure_name[i], structure_name) == 0) {
return &program->structures[i];
}
}
return NULL;
}
struct ktkMap *ktk_buildStructure(struct ktkProgram *program, struct ktkStructure *structure, struct ktkMap *orig_map) {
// limit our depth to avoid endless processing / seg fault
ktk_current_depth++;
if (ktk_current_depth >= ktk_LIMIT_DEPTH) {
printf("WARNING, depth limit %d exceeded, trashing structure %s\n", ktk_LIMIT_DEPTH, structure->name);
return orig_map;
}
int retry_limit = 64;
int retry_count = 0;
// retry is used if the structure is not allowed to overlap/replace/etc.
while (retry_count < retry_limit) {
retry_count++;
int x, y; // outcome structure position
int w, h; // outcome structure size
int id_1, id_2; // outcome structure ids
// roll our position
x = ktk_rollNumber(structure->x);
y = ktk_rollNumber(structure->y);
// resize according to parent's size if we're using percentages
if (structure->x.type & ktk_PERCENT) {
x = x * orig_map->w / 100;
}
if (structure->y.type & ktk_PERCENT) {
y = y * orig_map->h / 100;
}
// roll our size
w = ktk_rollNumber(structure->size_x);
h = ktk_rollNumber(structure->size_y);
// reposition according to parent's size if we're using percentages
if (structure->size_x.type & ktk_PERCENT) {
w = w * orig_map->w / 100;
}
if (structure->size_y.type & ktk_PERCENT) {
h = h * orig_map->h / 100;
}
// *** step 1: create basic shape
// generate the shape map
struct ktkMap shape_map = ktk_MAP_DEFAULT;
ktk_resizeMap(&shape_map, w, h);
// now we generate the basic "shape map" we want
if (structure->flags & ktk_STRUCTURE_CIRCLE) {
ktk_fillEllipse(&shape_map, 0, 0, w-1, h-1);
} else if (structure->flags & ktk_STRUCTURE_RECT) {
ktk_fillRect(&shape_map, 0, 0, w, h);
}
// *** step 2: manipulate basic shape
// apply post-processing to the shape map for borders, etc.
if (structure->flags & ktk_STRUCTURE_BORDER) {
struct ktkMap temp_map = ktk_MAP_DEFAULT;
temp_map.flags |= ktk_MAP_RESIZE;
// use the shape's cells to generate a border to temp
ktk_borderCells(&shape_map, &temp_map);
// delete shape map and replace with the temp
ktk_deleteMap(&shape_map);
ktk_resizeMap(&shape_map, w, h);
ktk_copyMap(&temp_map, &shape_map);
// delete temp
ktk_deleteMap(&temp_map);
}
// *** step 3: create map from shape map, rolling IDs as we do
struct ktkMap structure_map = ktk_MAP_DEFAULT;
ktk_resizeMap(&structure_map, w, h);
int px, py;
for (px = 0; px < w; px++) {
for (py = 0; py < h; py++) {
if (shape_map.cell[px][py].flags & ktk_CELL_EMPTY) continue;
structure_map.cell[px][py].id_1 = ktk_rollNumberSet(structure->id_1);
structure_map.cell[px][py].id_2 = ktk_rollNumberSet(structure->id_2);
structure_map.cell[px][py].flags &= ~ktk_CELL_EMPTY;
}
}
ktk_deleteMap(&shape_map);
// *** step 4: recursively create sub-structures
int i;
for (i = 0; i < structure->relation_count; i++) {
struct ktkRelation *relation = &structure->relations[i];
int roll_count = ktk_rollNumber(relation->count);
int r;
for (r = 0; r < roll_count; r++) {
struct ktkStructure *get_structure = ktk_getStructure(program, relation->name);
if (get_structure == NULL) continue; // TODO: add error
struct ktkStructure rel_structure = *get_structure;
// inherit structure flags from relation
rel_structure.flags |= relation->flags;
if (relation->x.type & ktk_ISSET) {
rel_structure.x = relation->x;
}
if (relation->y.type & ktk_ISSET) {
rel_structure.y = relation->y;
}
//rel_structure.size_x = relation->size_x;
//rel_structure.size_y = relation->size_y;
ktk_buildStructure(program, &rel_structure, &structure_map);
//ktk_buildStructure(program, &rel_structure, &structure_map);
}
}
// *** step 5: retry if we've overlapped when we're not supposed to
// set offset x,y for later merge
structure_map.x = x;
structure_map.y = y;
if (structure->flags & ktk_STRUCTURE_ORIGIN) {
structure_map.x -= w/2;
structure_map.y -= h/2;
}
if (structure->replace_id_1.count > 0) {
// TEMP
int px, py;
for (px = 0; px < structure_map.w; px++) {
if (x+px >= orig_map->w) continue;
for (py = 0; py < structure_map.h; py++) {
if (y+py >= orig_map->h) continue;
int r_i;
for (r_i = 0; r_i < structure->replace_id_1.count; r_i++) {
int r_s = structure->replace_id_1.sets[r_i].a;
int r_e = structure->replace_id_1.sets[r_i].b;
int r_id;
for (r_id = r_s; r_id <= r_e; r_id++) {
if (orig_map->cell[x+px][y+py].id_1 == r_id) {
orig_map->cell[x+px][y+py].id_1 = structure_map.cell[px][py].id_1;
}
}
}
}
}
} else if (structure->flags & ktk_STRUCTURE_OVERLAP) {
ktk_mergeMaps(orig_map, &structure_map);
ktk_deleteMap(&structure_map);
break;
} else if (ktk_checkMapOverlap(orig_map, &structure_map) == 0) {
ktk_mergeMaps(orig_map, &structure_map);
ktk_deleteMap(&structure_map);
break;
}
// if we reached here, that means we could not find a spot to draw
ktk_deleteMap(&structure_map);
}
ktk_current_depth--;
return orig_map;
}
/*
struct ktkMap *ktk_buildStructure(struct ktkProgram *program, struct ktkStructure *structure, struct ktkMap *orig_map) {
if (ktk_current_depth >= ktk_LIMIT_DEPTH) return orig_map;
ktk_current_depth++;
struct ktkMap map = ktk_MAP_DEFAULT;
map.flags |= ktk_MAP_RESIZE;
if (structure == NULL) {
return orig_map;
}
// If a structure does not have a placement flag, it will be attempted to be placed multiple times.
int retry_limit = 8;
int retry = 0;
while(retry < retry_limit) {
int x, y, size_x, size_y;
// positioning logic
x = ktk_rollNumber(structure->x);
if (structure->x.type & ktk_PERCENT) {
x = x * orig_map->w / 100;
}
y = ktk_rollNumber(structure->y);
if (structure->y.type & ktk_PERCENT) {
y = y * orig_map->h / 100;
}
map.x = x;
map.y = y;
size_x = ktk_rollNumber(structure->size_x);
printf("prex: %d * %d / 100\n", size_x, orig_map->w);
if (structure->size_x.type & ktk_PERCENT) {
size_x = size_x * orig_map->w / 100;
}
size_y = ktk_rollNumber(structure->size_y);
printf("prey: %d * %d / 100\n", size_y, orig_map->h);
if (structure->size_y.type & ktk_PERCENT) {
size_y = size_y * orig_map->h / 100;
}
printf("creating: %dx%d\n", size_x, size_y);
// begin generation
ktk_resizeMap(&map, size_x, size_y);
// position logic
if (structure->flags & ktk_STRUCTURE_ORIGIN) {
map.x += size_x/2;
map.y += size_y/2;
}
// shape logic
// we use a separate shape map to get the workable area before drawing
//struct ktkMap shape_map = ktk_MAP_DEFAULT;
//ktk_resizeMap(&shape_map, size_x+1, size_y+1);
if (structure->flags & ktk_STRUCTURE_CIRCLE) {
ktk_fillEllipse(&map, 0, 0, size_x-1, size_y-1);
} else if (structure->flags & ktk_STRUCTURE_RECT) {
ktk_fillRect(&map, 0, 0, size_x, size_y);
}
if (structure->flags & ktk_STRUCTURE_BORDER) {
struct ktkMap border_map = ktk_MAP_DEFAULT;
border_map.flags |= ktk_MAP_RESIZE;
ktk_borderCells(&map, &border_map);
ktk_deleteMap(&map);
ktk_resizeMap(&map, size_x, size_y);
//map->flags &= ~ktk_MAP_RESIZE;
ktk_mergeMaps(&map, &border_map);
//map->flags |= ktk_MAP_RESIZE;
ktk_deleteMap(&border_map);
}
// fill logic
// if (structure->flags & ktk_STRUCTURE_FILL) {
int px, py;
for (px = 0; px < size_x; px++) {
for (py = 0; py < size_y; py++) {
if (map.cell[px][py].flags & ktk_CELL_EMPTY) continue;
map.cell[px][py].id_1 = ktk_rollNumberSet(structure->id_1);
map.cell[px][py].id_2 = ktk_rollNumberSet(structure->id_2);
map.cell[px][py].flags &= ~ktk_CELL_EMPTY;
}
}
// relations
int i;
int r_x, r_y; // relation x, y
int r_size_x, r_size_y; // relation size
struct ktkMap snapshot = ktk_MAP_DEFAULT;
ktk_resizeMap(&snapshot, map.w, map.h);
printf("snapshot wxh: %dx%d\n", snapshot.w, snapshot.h);
ktk_mergeMaps(&snapshot, &map);
snapshot.flags |= ktk_MAP_RESIZE;
for (i = 0; i < structure->relation_count; i++) {
struct ktkRelation *relation = &structure->relations[i];
printf("running relation: %d:%s\n", i, relation->name);
// we tack on relation's flags to a new structure based on the target
struct ktkStructure *get_structure = ktk_getStructure(program, relation->name);
if (get_structure == NULL) continue; // TODO: add error
struct ktkStructure rel_structure = *get_structure;
rel_structure.flags |= relation->flags;
rel_structure.x = relation->x;
rel_structure.y = relation->y;
printf("--dump--\n");
ktk_dumpStructure(&rel_structure);
int roll_count = ktk_rollNumber(relation->count);
int r;
for (r = 0; r < roll_count; r++) {
int retry_limit = 8;
struct ktkMap temp = ktk_MAP_DEFAULT;
ktk_resizeMap(&temp, snapshot.w, snapshot.h);
ktk_mergeMaps(&temp, &snapshot);
//temp.flags |= ktk_MAP_RESIZE;
printf("temp wxh: %dx%d\n", temp.w, temp.h);
//temp.x = snapshot.x;
//temp.y = snapshot.y;
ktk_buildStructure(program, &rel_structure, &temp);
if (rel_structure.flags & ktk_STRUCTURE_CONSTRAIN) {
map.flags &= ~ktk_MAP_RESIZE;
}
if (rel_structure.flags & ktk_STRUCTURE_OVERLAP || ktk_checkMapOverlap(&map, &temp) == 0) {
ktk_mergeMaps(&map, &temp);
}
if (rel_structure.flags & ktk_STRUCTURE_CONSTRAIN) {
map.flags |= ktk_MAP_RESIZE;
}
ktk_deleteMap(&temp);
}
}
ktk_deleteMap(&snapshot);
if (structure->flags & ktk_STRUCTURE_OVERLAP || ktk_checkMapOverlap(orig_map, &map) == 0) {
ktk_mergeMaps(orig_map, &map);
printf("no overlap found or flag is set\n");
break;
} else {
printf("overlap found\n");
retry++;
ktk_deleteMap(&map);
}
}
ktk_deleteMap(&map);
ktk_current_depth--;
return orig_map;
}*/