210 lines
7.5 KiB
C
210 lines
7.5 KiB
C
#include "ktkProgram.h"
|
|
#include <stdlib.h>
|
|
#include <string.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 ktkLive *live_parent, 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;
|
|
}
|
|
|
|
// our live structure - this is copied to live_parent if structure is successful
|
|
struct ktkLive live = ktk_LIVE_DEFAULT;
|
|
live.parent = live_parent;
|
|
ktk_setLiveName(&live, structure->name);
|
|
|
|
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;
|
|
}
|
|
// create our live structure's position, etc.
|
|
live.x = x;
|
|
live.y = y;
|
|
live.size_x = w;
|
|
live.size_y = h;
|
|
// *** 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;
|
|
}
|
|
ktk_buildStructure(program, &live, &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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ktk_addLiveChild(live_parent, &live);
|
|
} else if (structure->flags & ktk_STRUCTURE_OVERLAP) {
|
|
ktk_mergeMaps(orig_map, &structure_map);
|
|
ktk_deleteMap(&structure_map);
|
|
ktk_addLiveChild(live_parent, &live);
|
|
break;
|
|
} else if (ktk_checkMapOverlap(orig_map, &structure_map) == 0) {
|
|
ktk_mergeMaps(orig_map, &structure_map);
|
|
ktk_deleteMap(&structure_map);
|
|
ktk_addLiveChild(live_parent, &live);
|
|
break;
|
|
}
|
|
// if we reached here, that means we could not find a spot to draw
|
|
ktk_deleteLive(&live);
|
|
ktk_deleteMap(&structure_map);
|
|
}
|
|
ktk_current_depth--;
|
|
return orig_map;
|
|
}
|
|
|
|
int ktk_linkStructures(struct ktkProgram *program, struct ktkLive *live_parent, struct ktkMap *orig_map) {
|
|
if (live_parent->parent != NULL) {
|
|
printf("%s: parent is: %s\n", live_parent->name, live_parent->parent->name);
|
|
}
|
|
int i;
|
|
for (i = 0; i < live_parent->child_count; i++) {
|
|
struct ktkLive *child = &(live_parent->children[i]);
|
|
ktk_linkStructures(program, child, orig_map);
|
|
}
|
|
return 0;
|
|
}
|