// PoVRay 3.8 include File " collections.inc" // author: Bruno Cabasson // date: Jan 2022 // // Pratical primitives. #ifndef (PROOF_PRIMITIVES_INC) #declare PROOF_PRIMITIVES_INC = version; #version 3.8; #declare None = false; #declare eol = -pi; // "End Of List" index marker. Whatever non-integral value in order to be distiguished from integrals (lists indexes). Equivalent to Python's ":" syntax for lists. #declare magic_number = int(rand(seed(10191)) * 1000000); #declare magic_string = str(magic_number, -6, 0); #declare _code_filename = concat("code_", magic_string, ".inc"); // Swap. Only suitable when v1 and v2 are identifiers for anything but dictionaries. #macro swap(v1, v2) #local tmp = v1; #local v1 = v2; #local v2 = tmp; #end #macro exec(code) //#debug concat("exec'ing : \"", code, "\"\n") #fopen _tmpfile _code_filename write #write (_tmpfile, code) #fclose _tmpfile #include _code_filename #end #macro truefalse(bool) #if (bool) "true" #else "false" #end #end #macro onoff(bool) #if (bool) "on" #else "off" #end #end #macro yesno(bool) #if (bool) "yes" #else "no" #end #end #declare NB_INDENT_LEVELS = 8; #declare indent_string = " "; #declare indent = array[NB_INDENT_LEVELS]; #declare indent[0] = ""; #for (i, 1, dimension_size(indent, 1) - 1) #declare indent[i] = concat(indent[i-1], indent_string); #end #macro tovector(value) #local tmp = rgb value; #end // + ----------+ // | Sequences | // + ----------+ #macro sequence(start, step) dictionary { .dicttype : "Sequence", .next : start, .step : step } #end #macro next(sequence) #if (sequence.dicttype = "Sequence") #local ret = sequence.next; #local sequence.next = sequence.next + sequence.step; #else #error "Not a sequence." #end ret #end // + ---------------------------------------------+ // | Dictionaries as enums : template declaration | // + ---------------------------------------------+ /* #declare MY_ENUM = dictionary { .dicttype : "Enum", .collection_type : COLLECTION_TYPES.enum, .entry1 : 0, .entry2 : 1, .../... .entryN : N-1, ._names : array [N] {"entry1", "entry2", ..., "entryN"} } */ // Provided Enums // TYPES : all types in the scope of POV-Sdl, that can be "#declared" and #hecked for. #declare _type_names = array {"bool", "int", "float", "vector", "uv", "color", "string", "object", "material", "texture", "pigment", "normal", "finish", "color_map", "pigment_map", "slope_map", "transform", "density", "function", "interior", "media", "camera", "light_source", "light_group", "spline", "array", "dictionary", "rainbow", "fog", "sky_sphere", "instance", "function"}; #declare _types_seq = sequence(0, 1); #declare TYPES = dictionary { .dicttype : "Enum", ._names : _type_names } #for (i, 0, dimension_size(_type_names, 1) - 1) #local entry = concat("_", _type_names[i],"_"); #declare TYPES[entry] = next(_types_seq); #end #macro enum_name(enum_dict, value) enum_dict._names[value] #end // + ----------+ // | Intervals | // + ----------+ #macro interval(inf, sup) array {inf, sup} #end #macro in(value, interval) ((interval[0] <= value) & (value <= interval[1])) #end // + --------------+ // | Type checking | // + --------------+ // The purpose is to validate 'value' as compatible with 'type_'. // Not sure all is pertinent... // Could not find a way to check the given value is a function (due to default x, y, z parameters). // Fake genericity. #macro check(value, type_) #local junk = None; #switch(type_) #case (TYPES._bool_) #local junk = value; #if (value != 0 & value != 1) #error "Wrong type for value, expected bool (0 or 1, or equivalent)" #end #break #case (TYPES._int_) #local junk = value; #if (int(value) != value) #error "Wrong type for value, expected integer, got float." #end #break #case (TYPES._float_) #local junk = str(value, 0, -1); #break #case (TYPES._vector_) #local junk = vstr(3, value, "", 0, -1); #break #case (TYPES._uv_) #local junk = vstr(2, value, "", 0, -1); #break #case (TYPES._color_) #local junk = color(value); #break #case (TYPES._string_) #local junk = strlen(value); #break #case (TYPES._object_) #local junk = object {value}; #break #case (TYPES._material_) #local junk = material {value}; #break #case (TYPES._texture_) #local junk = texture {value}; #break #case (TYPES._pigment_) #local junk = pigment {value}; #break #case (TYPES._normal_) #local junk = normal {value}; #break #case (TYPES._finish_) #local junk = finish {value}; #break #case (TYPES._color_map_) #local junk = color_map {value}; #break #case (TYPES._pigment_map_) #local junk = pigment_map {value}; #break #case (TYPES._slope_map_) #local junk = slope_map {value}; #break #case (TYPES._transform_) #local junk = transform {value}; #break #case (TYPES._density_) #local junk = density {value}; #break #case (TYPES._function_) #local junk = function {value}; #break #case (TYPES._interior_) #local junk = interior {value}; #break #case (TYPES._media_) #local junk = media {value}; #break #case (TYPES._camera_) #local junk = camera {value}; #break #case (TYPES._light_source_) #local junk = light_source {value}; #break #case (TYPES._light_group_) #local junk = light_group {value}; #break #case (TYPES._spline_) #local junk = spline {value}; #break #case (TYPES._array_) #local junk = dimension_size(value, 1); #break #case (TYPES._dictionary_) #declare value["____xj6T&m%ZZq$$*@=qn____"] = 0; #undef value["____xj6T&m%ZZq$$*@=qn____"] #break #case (TYPES._rainbow_) #local junk = rainbow {value}; #break #case (TYPES._fog_) #local junk = fog {value}; #break #case (TYPES._sky_sphere_) #local junk = sky_sphere {value}; #break #case (TYPES._instance_) #local junk = value.classname; #break #else #error "check() : unknown type for value." #end #undef junk value #end // + -------------------------------------+ // | To-string conversion for basic types | // + -------------------------------------+ // Fake genericity. #macro tostring(value, type_) #local ret = ""; #switch(type_) #case (TYPES._bool_) #if (value != 0 & value != 1) #error "Wrong type for value, expected bool (0 or 1)" #end #local ret = truefalse(value) #break #case (TYPES._int_) #if (int(value) != value) #error "Wrong type for value, expected integer, got float." #end #local ret = str(value, 0, 0); #break #case (TYPES._float_) #local ret = str(value, 0, -1); #break #case (TYPES._vector_) // vstr() seems to promote to instead of . // The "rgb" primitive makes the correct promotion. #local tmp = rgb value; #local ret = concat("<", vstr(3, tmp, ", ", 0, -1), ">"); #break #case (TYPES._uv_) // vstr() seems to promote to instead of . // The "rgb" primitive makes the correct promotion. #local tmp = rgb value; #local ret = concat("<", vstr(2, , ", ", 0, -1), ">"); #break #case (TYPES._color_) // vstr() seems to promote to instead of . // The "rgbft" primitive makes the correct promotion. #local tmp = rgbft value; #local ret = concat("rgbft <", vstr(5, tmp, ", ", 0, -1), ">"); #break #case (TYPES._string_) #local ret = value; #break #else #error "tostring : unknown type for value." #end ret #end #declare DEFAULT_TEXTURE = pigment {White}; #version PROOF_PRIMITIVES_INC; #end