分形/MandelMachine
外观
< 分形
Mandel Machine Mandel Machine 是由 Botond Kósa 开发的高效 Mandelbrot 集浏览器。[1]
- c++ 部分 (mm64.cpp) 仅用于声明在汇编语言中实现的函数,其余部分使用 java 编写。
- FractalCanvas.java 是最重要的文件
FractalCanvas.java 第 1996 行及以后
if(itTransferFunction==1) ;
else if(itTransferFunction==2) it = Math.sqrt(it+1);
else if(itTransferFunction==3) it = Math.cbrt(it+1);
else if(itTransferFunction==4) it = Math.sqrt(Math.sqrt(it+1));
else if(itTransferFunction==5) it = Math.log(it+1);
else if(itTransferFunction==6) it = Math.log(Math.log(it+1)+1);
else if(itTransferFunction==7) it = Math.atan(it);
else it = -1;
"凹凸贴图。它允许对以前隐藏在调色板中缓慢渐变的细微细节进行假 3D 可视化。
凹凸贴图由 3 个参数控制
- 照明方向(以度为单位):指定模拟照明角度。面向光线的表面会被突出显示,而被光线遮挡的表面会被变暗。
- 深度:控制结构从缓慢渐变的背景中突出的程度。较小的深度会导致浮雕/压花外观。较大的深度值会导致结构之间出现更深的谷底(参见下面的示例)。
- 强度:控制高光和阴影引起的色彩变化量。
这些参数可以连续调整,以提供即时反馈。" [2]
"Mandel Machine MMIT 压缩迭代数据文件格式
- 每个数据类型都需要以大端序写入。
- 以下内容通过 Deflater(原始 zlib 格式)流式传输" Dinkydau[3]
<int 4 bytes> Program Version <int 4 bytes> Canvas Width <int 4 bytes> Canvas Height <byte> Supersampling <double> Magnification <double> Rotation <int 4 bytes> Number of coordinate digits represented by long ints <long long array> array 2 times as long as the above int <int 4 bytes> Iteration limit <byte> Bytes per sample <double> minimum iteration count <double> granularity (equal to iterRange / (2^(bytes_per_sample*8) - 6), where iterRange is maxIt - minIt) <int array> row by row encoded samples (one int value per pixel)
源代码(使用 C 编写),依赖于来自 kf-extras 的 kfb.h 和 kfb.c
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "kfb.h"
void asserts(){
assert(sizeof(char)==1);
assert(sizeof(short)==2);
assert(sizeof(int)==4);
assert(sizeof(float)==4);
assert(sizeof(double)==8);
assert(sizeof(long)==4);
assert(sizeof(long long)==8);
return;
}
//data_size counts how large the mmit data is before zlib formatting
int data_size = 0;
const char one = 1;
union DoubleBytes {//to interpret double as char array and inverse byte order
double d;
char b[8];
};
union IntBytes {//to interpret int as char array
int i;
char b[4];
};
//functions to write data in big endian notation
int le_to_be_int(int input){
int num = input;
int b0,b1,b2,b3;
int res;
b0 = (num & 0x000000ff) << 24u;
b1 = (num & 0x0000ff00) << 8u;
b2 = (num & 0x00ff0000) >> 8u;
b3 = (num & 0xff000000) >> 24u;
res = b0 | b1 | b2 | b3;
return res;
}
void write_be_int(int input, FILE *outfile){
int res = le_to_be_int(input);
fwrite(&res, 4, 1, outfile);
data_size += 4;
}
void write_be_char(char input, FILE *outfile){
fwrite(&input, 1, 1, outfile);
data_size += 1;
}
void write_be_double(double input, FILE *outfile){
union DoubleBytes doublebytes;
doublebytes.d = input;
for(int i=0; i<4; i++){//reverse byte order in the double with char array interpretation
char temp = doublebytes.b[i];
doublebytes.b[i] = doublebytes.b[7-i];
doublebytes.b[7-i] = temp;
}
fwrite(&doublebytes.d, 8, 1, outfile);
data_size += 8;
}
int main(int argc, char **argv) {
//Check and load KFB file-----------------------------------------------------------------------------------
asserts();
if (argc < 2)
{
printf("This program converts a given KFB file to MMIT. Program version: 1.0
");
printf("Usage: "); printf(argv[0]); printf(" path_to_KFB [path_to_MMIT]
");
printf("Default for path_to_MMIT: MMIT-convert.mmit
");
return 1;
}
printf("Loading KFB file...
");
kfb *in = kfb_load(argv[1]);
if (! in) { printf("Loading KFB file failed.
"); return 1; }
int width = kfb_width(in);
int height = kfb_height(in);
//Writing all relevant mmit data to tempoutfile without zlib format--------------------------------------------
FILE *tempoutfile;
tempoutfile=fopen("tempoutfile", "wb");
//Get min and max iteration values present in KFB
double max_iters = 0;
double min_iters = 800100100;
for(int i=0; i<height; i++){
for(int j=0; j<width; j++){
double ij = kfb_get(in, j, i);
if(ij<min_iters) min_iters = ij;
if(ij>max_iters) max_iters = ij;
}
}
printf("Lowest iteration count: %lf
", min_iters);
printf("Highest iteration count: %lf
", max_iters);
//Parameters and settings
write_be_int(one, tempoutfile); //Program version
write_be_int(width, tempoutfile); //Canvas width
write_be_int(height, tempoutfile); //Canvas height
char supersampling = 0; write_be_char(supersampling, tempoutfile); //Supersampling (Always 0 for no supersampling)
double magnification = 512; write_be_double(magnification, tempoutfile); //Fake magnification default to arbitrary value;
double rotation = 256; write_be_double(rotation, tempoutfile); //Fake rotation default to arbitrary value;
int coord_digits = 11; write_be_int(coord_digits, tempoutfile); //Fake number of coordinate digits
int coords[44] = {-1, -1, -1, -1, -1768346623, 1239184185, -1450836726, -1610156628, -1160793342, 1122682978, 1750969101, 1468815386, -86691575, -319241320, -141699069, 731720154, -1302511102, 2092147506, 1358717447, -121412270, -362838523, 1906712988, 218032387, 147395776, 1528659973, -1874890155, 1817790991, 431114295, 1763611407, -389200653, 1363516937, 1455562147, 707986444, -847133922, 1130970381, 1568324293, 1567881485, -580086891, 1843248142, 1016614712, 1950251523, -75377623, -1674907892, 1914116203};
for(int i=0; i<44; i++){ //Fake array of coordinate digits
fwrite(&coords[i], 4, 1, tempoutfile);
data_size += 4;
}
int iteration_limit = 799999999; write_be_int(iteration_limit, tempoutfile); //default one below MM's 800M limit, seems safe
char bytesPerSample = 4; write_be_char(bytesPerSample, tempoutfile); //always 4 (the max) for simplicity
write_be_double(min_iters, tempoutfile); //minimum number of iterations in the data
double granularity = (799999999 - min_iters)/4294967290; write_be_double(granularity, tempoutfile); //(equal to iterRange / 4294967290, where iterRange is maxIt - minIt)
printf("Writing iteration data...
");
//Iteration data
double granRec = 0; if(granularity != 0) granRec = 1/granularity;
long long prevEncoded = 0;
char buffer[width*4];
union IntBytes intbytes;
for(int row=0; row<height; row++){
for(int col=0; col<width; col++){
double it = kfb_get(in, col, row);
long long encoded;
if (it == max_iters) encoded = 3; //Point inside minibrot
else encoded = round((it-min_iters)*granRec) + 5; //encodeSample
int diff = encoded - prevEncoded;
//writeSample:
intbytes.i = diff;
buffer[col+3*width] = intbytes.b[3];
buffer[col+2*width] = intbytes.b[2];
buffer[col+width] = intbytes.b[1];
buffer[col] = intbytes.b[0];
//
prevEncoded = encoded;
}
fwrite(&buffer, width*4, 1, tempoutfile);
data_size += width*4;
}
fclose(tempoutfile);
kfb_free(in);
printf ("Total data size: %d
", data_size);
//read uncompressed MMIT data into array a---------------------------------------------------------------------
char* a = malloc(data_size);
if(a==NULL){ printf ("Allocation of memory failed.
"); return 1;}
FILE *readbackfile;
readbackfile=fopen("tempoutfile", "rb");
fread(a, data_size, 1, readbackfile);
printf("Writing zlib format...
");
//Convert to zlib format and write to file---------------------------------------------------------------------
FILE *outfile;
if(argc > 2) outfile=fopen(argv[2], "wb");
else outfile=fopen("MMIT-convert.mmit", "wb");
int bytes_written = 0;
char header_more[] = {0, 86, 129, 169, 126}; // hardcoded zlib header for a block size of 33110;
while(bytes_written<data_size)
{
if(data_size - bytes_written > 33110)
{ //not the last block header
fwrite(&header_more, 5, 1, outfile);
for(int j=0; j<33110; j++)
{
fwrite(&a[bytes_written+j], 1, 1, outfile);
}
bytes_written += 33110;
}
else
{ //the last block header
short to_go = data_size - bytes_written;
short complement = 65535 - to_go;
fwrite(&one, 1, 1, outfile);
fwrite(&to_go, 2, 1, outfile);
fwrite(&complement, 2, 1, outfile);
for(int j=0; j<to_go; j++)
{
fwrite(&a[bytes_written+j], 1, 1, outfile);
}
bytes_written += to_go;
}
}
//-----------------------------------------------------------------------------------
fclose(readbackfile);
if(remove("tempoutfile") != 0) printf("Deleting the temporary file failed.");
printf ("Done");
return 0;
}