├── .gitignore ├── CMakeLists.txt ├── README.md ├── format_and_count.py ├── png ├── card.png ├── miniray_0.1.png ├── miniray_0.2.png ├── miniray_0.3.png ├── miniray_0.4.png ├── miniray_0.5.png ├── miniray_0.6.png ├── miniray_1.0.png ├── miniray_1.1.png ├── miniray_1.2.png ├── miniray_1.3.png ├── miniray_1.4.png ├── miniray_1.4_commented.png ├── miniray_2.0.png ├── miniray_2.1.png ├── miniray_2.2.png ├── miniray_2.3.png ├── miniray_2.4.png ├── miniray_3.0.png ├── miniray_3.1.png ├── miniray_4.0.png ├── miniray_4.1.png ├── miniray_4.2.png ├── miniray_4.3.png ├── miniray_4.4.png ├── miniray_4.5.png ├── miniray_4.6.png ├── miniray_4.6_commented.png └── zucker.png ├── ppm ├── card.ppm ├── miniray_0.1.ppm ├── miniray_0.2.ppm ├── miniray_0.3.ppm ├── miniray_0.4.ppm ├── miniray_0.5.ppm ├── miniray_0.6.ppm ├── miniray_1.0.ppm ├── miniray_1.1.ppm ├── miniray_1.2.ppm ├── miniray_1.3.ppm ├── miniray_1.4.ppm ├── miniray_1.4_commented.ppm ├── miniray_2.0.ppm ├── miniray_2.1.ppm ├── miniray_2.2.ppm ├── miniray_2.3.ppm ├── miniray_2.4.ppm ├── miniray_3.0.ppm ├── miniray_3.1.ppm ├── miniray_4.0.ppm ├── miniray_4.1.ppm ├── miniray_4.2.ppm ├── miniray_4.3.ppm ├── miniray_4.4.ppm ├── miniray_4.5.ppm ├── miniray_4.6.ppm ├── miniray_4.6_commented.ppm └── zucker.ppm └── src ├── CMakeLists.txt ├── card.cpp ├── encode.cpp ├── miniray_0.1.cpp ├── miniray_0.2.cpp ├── miniray_0.3.cpp ├── miniray_0.4.cpp ├── miniray_0.5.cpp ├── miniray_0.6.cpp ├── miniray_1.0.cpp ├── miniray_1.1.cpp ├── miniray_1.2.cpp ├── miniray_1.3.cpp ├── miniray_1.4.cpp ├── miniray_1.4_commented.cpp ├── miniray_2.0.cpp ├── miniray_2.1.cpp ├── miniray_2.2.cpp ├── miniray_2.3.cpp ├── miniray_2.4.cpp ├── miniray_3.0.cpp ├── miniray_3.1.cpp ├── miniray_4.0.c ├── miniray_4.1.c ├── miniray_4.2.c ├── miniray_4.3.c ├── miniray_4.4.c ├── miniray_4.5.c ├── miniray_4.6.c ├── miniray_4.6_commented.c └── zucker.c /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | build/* 4 | nogit/* 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(miniray) 3 | 4 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) 5 | 6 | add_subdirectory(src) 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | miniray 2 | ======= 3 | Business card raytracer / eventual IOCCC winner. See full writeup at 4 | 5 | Building 6 | ======== 7 | 8 | To build: 9 | 10 | cd /path/to/miniray 11 | mkdir build 12 | cd build 13 | cmake .. -DCMAKE_BUILD_TYPE=Release 14 | make 15 | make ppm_images #optional, takes a while 16 | 17 | 18 | Using the software 19 | ================== 20 | 21 | For all versions, you can pipe the output to a PPM image (displayable with ImageMagick `display` command among other apps): 22 | 23 | ./miniray > image.ppm 24 | 25 | For versions 4.2 and after, you can input your own text: 26 | 27 | ./miniray "my text" > image.ppm 28 | ./miniray "my text" -preview > image.ppm # faster, reflections & AA disabled 29 | 30 | See also 31 | ======== 32 | 33 | - 34 | -------------------------------------------------------------------------------- /format_and_count.py: -------------------------------------------------------------------------------- 1 | import ply.lex as lex 2 | import sys 3 | import re 4 | 5 | ###################################################################### 6 | 7 | def get_tokens(istr): 8 | 9 | tokens = ['CPPLINE', 'INT', 'DOUBLE', 'STRING', 'COMMENT', 10 | 'IDENTIFIER', 'OP', 'WHITESPACE'] 11 | 12 | t_CPPLINE = r'\#.*?\n' 13 | t_COMMENT = r'(?s)(/\*.*?\*/|//[^\n]*\n)' 14 | t_INT = r'[0-9]+[uUlL]*' 15 | t_DOUBLE = r'([0-9]*\.[0-9]+|[0-9]+)([eE]-?[0-9]+)?[fFlL]?' 16 | t_STRING = r'"([^"\\]|\\.)*"' 17 | t_IDENTIFIER = r'[_A-Za-z][_A-Za-z0-9]*' 18 | t_OP = r'(\+\+|--|!=|>=|<=|>>|<<|&&|\|\||\+=|-=|\*=|/=|%=|&=|\|=|\^=|<<=|>>=|->|==)' 19 | t_WHITESPACE = r'[ \n\t]+' 20 | 21 | literals = '()=+-*/%!~^&|{}[];,?:<>.' 22 | 23 | def t_error(t): 24 | print >> sys.stderr, 'error tokenizing, character is', t.value[0] 25 | sys.exit(1) 26 | 27 | l = lex.lex() 28 | l.input(istr) 29 | 30 | tokens = [] 31 | 32 | buf = '' 33 | iscpp = True 34 | defines = {} 35 | 36 | while True: 37 | tok = l.token() 38 | if not tok: 39 | break 40 | if tok.type == 'CPPLINE': 41 | if not iscpp: 42 | sys.stderr.write('error: C preprocessor stuff not at top!\n'); 43 | sys.exit(1) 44 | else: 45 | m = re.match(r'\#define\s+(\S+)\s(\S+)\n', tok.value) 46 | if m: 47 | defines[m.group(2)] = m.group(1) 48 | buf += tok.value 49 | elif tok.type != 'WHITESPACE' and tok.type != 'COMMENT': 50 | iscpp = False 51 | if defines.has_key(tok.value): 52 | tokens.append(defines[tok.value]) 53 | else: 54 | tokens.append(tok.value) 55 | 56 | return buf, tokens 57 | 58 | ###################################################################### 59 | 60 | def can_join(buf, tok): 61 | ops = ['++','--','!=','>=','<=','>>','<<','&&','||','+=', 62 | '-=','*=','/=','%=','&=','|=','\=','^=','->','==']; 63 | if len(buf) == 0 or buf[-1].isspace(): 64 | return True 65 | elif buf[-1].isalnum() and tok[0].isalnum(): 66 | return False 67 | else: 68 | return not ops.count(buf[-1] + tok[0]) 69 | 70 | ###################################################################### 71 | 72 | def wrap_simple(filename, buf, tokens, width): 73 | 74 | line = '' 75 | last_space = -1 76 | 77 | for token in tokens: 78 | 79 | need_whitespace = not can_join(line, token) 80 | line_remaining = width - len(line) 81 | token_needs = len(token) 82 | 83 | if need_whitespace: 84 | token_needs += 1 85 | 86 | if token_needs > line_remaining: 87 | if last_space >= 0: 88 | buf += line[:last_space] + '\n' 89 | line = line[last_space+1:] 90 | last_space = -1 91 | line_remaining = width - len(line) 92 | if token_needs > line_remaining: 93 | buf += line + '\n' 94 | line = '' 95 | line_remaining = 0 96 | 97 | if need_whitespace: 98 | last_space = len(line) 99 | line += ' ' 100 | 101 | line += token 102 | 103 | buf += line 104 | 105 | cnt = len(buf) 106 | 107 | ws = len(re.findall(r'(?s)\s', buf)) 108 | br = len(re.findall(r'(?s)[{};]\s', buf)) 109 | 110 | print >> sys.stderr, '/* {:>30}: total size={:4}, contest length={:4} */'.format( 111 | filename, cnt, cnt-ws-br) 112 | 113 | print buf 114 | 115 | 116 | 117 | ###################################################################### 118 | 119 | filename = sys.argv[1] 120 | f = open(filename) 121 | istr = f.read() 122 | 123 | (buf, tokens) = get_tokens(istr) 124 | 125 | wrap_simple(filename, buf, tokens, 80) 126 | -------------------------------------------------------------------------------- /png/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/card.png -------------------------------------------------------------------------------- /png/miniray_0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_0.1.png -------------------------------------------------------------------------------- /png/miniray_0.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_0.2.png -------------------------------------------------------------------------------- /png/miniray_0.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_0.3.png -------------------------------------------------------------------------------- /png/miniray_0.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_0.4.png -------------------------------------------------------------------------------- /png/miniray_0.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_0.5.png -------------------------------------------------------------------------------- /png/miniray_0.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_0.6.png -------------------------------------------------------------------------------- /png/miniray_1.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_1.0.png -------------------------------------------------------------------------------- /png/miniray_1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_1.1.png -------------------------------------------------------------------------------- /png/miniray_1.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_1.2.png -------------------------------------------------------------------------------- /png/miniray_1.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_1.3.png -------------------------------------------------------------------------------- /png/miniray_1.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_1.4.png -------------------------------------------------------------------------------- /png/miniray_1.4_commented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_1.4_commented.png -------------------------------------------------------------------------------- /png/miniray_2.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_2.0.png -------------------------------------------------------------------------------- /png/miniray_2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_2.1.png -------------------------------------------------------------------------------- /png/miniray_2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_2.2.png -------------------------------------------------------------------------------- /png/miniray_2.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_2.3.png -------------------------------------------------------------------------------- /png/miniray_2.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_2.4.png -------------------------------------------------------------------------------- /png/miniray_3.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_3.0.png -------------------------------------------------------------------------------- /png/miniray_3.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_3.1.png -------------------------------------------------------------------------------- /png/miniray_4.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.0.png -------------------------------------------------------------------------------- /png/miniray_4.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.1.png -------------------------------------------------------------------------------- /png/miniray_4.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.2.png -------------------------------------------------------------------------------- /png/miniray_4.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.3.png -------------------------------------------------------------------------------- /png/miniray_4.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.4.png -------------------------------------------------------------------------------- /png/miniray_4.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.5.png -------------------------------------------------------------------------------- /png/miniray_4.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.6.png -------------------------------------------------------------------------------- /png/miniray_4.6_commented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/miniray_4.6_commented.png -------------------------------------------------------------------------------- /png/zucker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/png/zucker.png -------------------------------------------------------------------------------- /ppm/card.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/card.ppm -------------------------------------------------------------------------------- /ppm/miniray_0.4.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_0.4.ppm -------------------------------------------------------------------------------- /ppm/miniray_0.5.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_0.5.ppm -------------------------------------------------------------------------------- /ppm/miniray_0.6.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_0.6.ppm -------------------------------------------------------------------------------- /ppm/miniray_1.0.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_1.0.ppm -------------------------------------------------------------------------------- /ppm/miniray_1.1.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_1.1.ppm -------------------------------------------------------------------------------- /ppm/miniray_1.2.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_1.2.ppm -------------------------------------------------------------------------------- /ppm/miniray_1.3.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_1.3.ppm -------------------------------------------------------------------------------- /ppm/miniray_1.4.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_1.4.ppm -------------------------------------------------------------------------------- /ppm/miniray_1.4_commented.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_1.4_commented.ppm -------------------------------------------------------------------------------- /ppm/miniray_2.0.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_2.0.ppm -------------------------------------------------------------------------------- /ppm/miniray_2.1.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_2.1.ppm -------------------------------------------------------------------------------- /ppm/miniray_2.2.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_2.2.ppm -------------------------------------------------------------------------------- /ppm/miniray_2.3.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_2.3.ppm -------------------------------------------------------------------------------- /ppm/miniray_2.4.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_2.4.ppm -------------------------------------------------------------------------------- /ppm/miniray_3.0.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_3.0.ppm -------------------------------------------------------------------------------- /ppm/miniray_3.1.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_3.1.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.0.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.0.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.1.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.1.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.2.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.2.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.3.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.3.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.4.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.4.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.5.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.5.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.6.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.6.ppm -------------------------------------------------------------------------------- /ppm/miniray_4.6_commented.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/miniray_4.6_commented.ppm -------------------------------------------------------------------------------- /ppm/zucker.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzucker/miniray/3b8c201f991215d177ee3df8360131c2df916b01/ppm/zucker.ppm -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(RAYTRACERS_CPP 2 | miniray_0.1 3 | miniray_0.2 4 | miniray_0.3 5 | miniray_0.4 6 | miniray_0.5 7 | miniray_0.6 8 | miniray_1.0 9 | miniray_1.1 10 | miniray_1.2 11 | miniray_1.3 12 | miniray_1.4 13 | miniray_1.4_commented 14 | miniray_2.0 15 | miniray_2.1 16 | miniray_2.2 17 | miniray_2.3 18 | miniray_2.4 19 | miniray_3.0 20 | miniray_3.1 21 | card 22 | ) 23 | 24 | set(RAYTRACERS_C 25 | miniray_4.0 26 | miniray_4.1 27 | miniray_4.2 28 | miniray_4.3 29 | miniray_4.4 30 | miniray_4.5 31 | miniray_4.6 32 | miniray_4.6_commented 33 | zucker 34 | ) 35 | 36 | set(RAYTRACERS 37 | ${RAYTRACERS_CPP} 38 | ${RAYTRACERS_C}) 39 | 40 | foreach(RAYTRACER_CPP ${RAYTRACERS_CPP}) 41 | add_executable(${RAYTRACER_CPP} "${RAYTRACER_CPP}.cpp") 42 | endforeach() 43 | 44 | foreach(RAYTRACER_C ${RAYTRACERS_C}) 45 | add_executable(${RAYTRACER_C} "${RAYTRACER_C}.c") 46 | endforeach() 47 | 48 | add_custom_target(ppm_images) 49 | 50 | foreach(RAYTRACER ${RAYTRACERS}) 51 | add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/${RAYTRACER}.ppm" 52 | COMMAND time ./${RAYTRACER} > "${RAYTRACER}.ppm" 53 | DEPENDS ${RAYTRACER} 54 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) 55 | add_custom_target(${RAYTRACER}_image 56 | DEPENDS "${PROJECT_BINARY_DIR}/${RAYTRACER}.ppm") 57 | add_dependencies(ppm_images ${RAYTRACER}_image) 58 | endforeach() 59 | 60 | add_executable(encode "encode.cpp") -------------------------------------------------------------------------------- /src/card.cpp: -------------------------------------------------------------------------------- 1 | #include // ./card > mattz.ppm # see https://goo.gl/JM9c2P 2 | typedef double f;f H=.5,Y=.66,S=-1,I,y=-111;extern"C"{f cos(f),pow(f 3 | ,f),atan2(f,f);}struct v{f x,y,z;v(f a=0,f b=0,f c=0):x(a),y(b),z(c) 4 | {}f operator%(v r){return x*r.x+y*r.y+z*r.z;}v operator+(v r){return 5 | v(x+r.x,y+r.y,z+r.z);}v operator*(f s){return v(x*s,y*s,z*s);}}W(1,1 6 | ,1),P,C,M;f U(f a){return a<0?0:a>1?1:a;}v _(v t){return t*pow(t%t,- 7 | H);}f Q(v c){M=P+c*S;f d=M%M;return du?u: 11 | t,Q(k*H+v(cos(t),cos(t-1.57))*(a%2*H+1)):Q(k+d*U((p+k*S)%d/(d%d)));} 12 | return M=Q(v(p.x,-.9,p.z))?(int(p.x+64)^int(p.z+64))/8&1?Y:W:v(Y,Y,1 13 | ),pow(I,H)-.45;}v R(v o,v d,f z){for(f u=0,l=1,i=0,a=1;u<97;u+=l=D(o 14 | +d*u))if(l<.01){v p=M,n=_(P+C*S),L=_(v(S,1,2));for(o=o+d*u;++i<6;a-= 15 | U(i/3-D(o+n*i*.3))/pow(2,i));p=p*(U(n%L)*H*Y+Y)*a;p=z?p*Y+R(o+n*.1,d 16 | +n*-2*(d%n),z-1)*H*Y:p;u=pow(U(n%_(L+d*S)),40);return p+p*-u+W*u;}z= 17 | d.z*d.z;return v(z,z,1);} int main(){for(puts("P6 600 220 255");++y< 18 | 110;)for(f x=-301;P=R(v(-2,4,25),_(_(v(5,0,2))*++x+_(v(-2,73))*-y+v( 19 | 301,-59,-735)),2)*255,x<300;putchar(P.z))putchar(P.x),putchar(P.y);} 20 | -------------------------------------------------------------------------------- /src/encode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef unsigned char uint8; 11 | typedef unsigned short uint16; 12 | 13 | enum { 14 | X_COORD_BITS = 2, 15 | Y_COORD_BITS = 3, 16 | OP_BITS = 2, 17 | ARG_BITS = 5, 18 | }; 19 | 20 | enum { 21 | LINE_DX_BITS = 2, 22 | LINE_DY_BITS = 3, 23 | ARC_A0_BITS = 2, 24 | ARC_A1_BITS = 3, 25 | }; 26 | 27 | enum { 28 | SEP_0 = '"', 29 | SEP_1 = SEP_0 + 5, 30 | SEP_2 = SEP_1+1, 31 | }; 32 | 33 | #define MASK(b) ((1< buffer; 65 | buffer buf; 66 | 67 | struct shift_info { 68 | const char* which; 69 | int* shift; 70 | int bits; 71 | shift_info(); 72 | shift_info(const char* s, int* i, int b): which(s), shift(i), bits(b) {} 73 | }; 74 | 75 | std::vector shifts; 76 | 77 | int rand_int(int n) { 78 | return rand() % n; 79 | } 80 | 81 | void permute_shifts() { 82 | 83 | NEGATE_X = rand()%2; 84 | 85 | OP_LINE = rand()%4; 86 | do { OP_ARC = rand()%4; } while (OP_ARC == OP_LINE); 87 | do { OP_NLINE = rand()%4; } while (OP_NLINE == OP_ARC || OP_NLINE == OP_LINE); 88 | 89 | size_t all_bits = OP_BITS + ARG_BITS + X_COORD_BITS + Y_COORD_BITS; 90 | assert( all_bits <= 16 ); 91 | 92 | size_t padding_bits = 16 - all_bits; 93 | 94 | shifts.clear(); 95 | shifts.push_back(shift_info("OP", &OP_SHIFT, OP_BITS)); 96 | shifts.push_back(shift_info("X_COORD", &X_COORD_SHIFT, X_COORD_BITS)); 97 | shifts.push_back(shift_info("Y_COORD", &Y_COORD_SHIFT, Y_COORD_BITS)); 98 | shifts.push_back(shift_info("ARG", &ARG_SHIFT, ARG_BITS)); 99 | 100 | for (size_t i=0; i= X_COORD); 148 | assert(y >= Y_COORD || x > X_COORD); 149 | uint16 dx = x - X_COORD; 150 | X_COORD = x; 151 | x = dx; 152 | 153 | if (dx < dxmin) { dxmin = dx; dxminc = cur; } 154 | if (dx > dxmax) { dxmax = dx; dxmaxc = cur; } 155 | 156 | assert(type <= MASK(OP_BITS)); 157 | assert(arg <= MASK(ARG_BITS)); 158 | assert(x <= MASK(X_COORD_BITS)); 159 | assert(y <= MASK(Y_COORD_BITS)); 160 | 161 | uint16 val = ( (type << OP_SHIFT) | (arg << ARG_SHIFT) | 162 | (x << X_COORD_SHIFT) | (y << Y_COORD_SHIFT) | 163 | PADDING_VAL ); 164 | 165 | unsigned char c0 = val&0xff; 166 | unsigned char c1 = (val>>8)&0xff; 167 | 168 | bmin = std::min(bmin, std::min(c0,c1)); 169 | bmax = std::max(bmax, std::max(c0,c1)); 170 | 171 | buf.push_back(c0); 172 | buf.push_back(c1); 173 | 174 | } 175 | 176 | 177 | void start(char c, uint16 w) { 178 | 179 | Y_COORD = X_COORD = 0; 180 | 181 | 182 | buf.push_back(SEP_0+w); 183 | 184 | if (c != cur+1) { 185 | buf.push_back(SEP_2); 186 | buf.push_back(c); 187 | } 188 | 189 | cur = c; 190 | 191 | } 192 | 193 | void line(uint16 x, uint16 y, int dx, int dy) { 194 | 195 | int op = OP_LINE; 196 | 197 | if (dx < 0) { 198 | assert(NEGATE_X); 199 | dx = -dx; 200 | op = OP_NLINE; 201 | } 202 | 203 | if (dy < 0) { 204 | assert(!NEGATE_X); 205 | dy = -dy; 206 | op = OP_NLINE; 207 | } 208 | 209 | assert(y <= MASK(Y_COORD_BITS)); 210 | assert(dx <= MASK(LINE_DX_BITS)); 211 | assert(dy <= MASK(LINE_DY_BITS)); 212 | 213 | uint16 arg = (dx << LINE_DX_SHIFT) | (dy << LINE_DY_SHIFT); 214 | 215 | instr(op, arg, x, y); 216 | 217 | } 218 | 219 | void arc(uint16 x, 220 | uint16 y, 221 | uint16 a0, 222 | uint16 a1) { 223 | 224 | assert(y <= MASK(Y_COORD_BITS)); 225 | 226 | assert(a0 <= MASK(ARC_A0_BITS)); 227 | assert(a1 <= MASK(ARC_A1_BITS)); 228 | 229 | uint16 arg = (a0 << ARC_A0_SHIFT) | (a1 << ARC_A1_SHIFT); 230 | 231 | instr(OP_ARC, arg, x, y); 232 | 233 | } 234 | 235 | 236 | std::string stringify() { 237 | 238 | const unsigned char* ucbuf = (const unsigned char*)(&buf[0]); 239 | 240 | std::ostringstream ostr; 241 | bool wasHex = false; 242 | 243 | for (size_t i=0; i= 32 && b <= 126) { 250 | if (wasHex && isxdigit(b)) { 251 | // interrupt because it was hex, and we have a hex digit here 252 | ostr << "\"\""; 253 | } 254 | if (b == '\\') { 255 | ostr << "\\\\"; 256 | } else { 257 | ostr << char(b); 258 | } 259 | wasHex = false; 260 | } else { 261 | wasHex=false; 262 | switch (b) { 263 | case '\n': ostr << "\\n"; break; 264 | case '\t': ostr << "\\t"; break; 265 | case '\v': ostr << "\\v"; break; 266 | case '\b': ostr << "\\b"; break; 267 | case '\r': ostr << "\\r"; break; 268 | case '\a': ostr << "\\a"; break; 269 | case '\f': ostr << "\\f"; break; 270 | case '\0': ostr << "\\0"; break; 271 | default: 272 | ostr << "\\x" << std::hex << int(b); 273 | wasHex = true; 274 | break; 275 | } 276 | } 277 | } 278 | 279 | return ostr.str(); 280 | 281 | } 282 | 283 | 284 | std::string stringvar(const std::string& var, int shift, int bits, int total=8) { 285 | 286 | std::ostringstream ostr; 287 | 288 | ostr << var; 289 | 290 | bool needshift = shift; 291 | bool needmask = (bits + shift) < total; 292 | 293 | if (needshift) { 294 | if ((1 << shift) >= 100) { 295 | ostr << "<<" << shift; 296 | } else { 297 | ostr << "/" << (1 << shift); 298 | } 299 | } 300 | 301 | if (needmask) { 302 | ostr << "&" << ((1 << bits) - 1); 303 | } 304 | 305 | return ostr.str(); 306 | 307 | } 308 | 309 | std::string stringvar(int shift, int bits, int total=8) { 310 | 311 | 312 | if (shift>=8) { 313 | return stringvar("b[1]", shift-8, bits, total); 314 | } else { 315 | return stringvar("b[0]", shift, bits, total); 316 | } 317 | 318 | } 319 | 320 | 321 | std::string stringvars() { 322 | 323 | std::ostringstream ostr; 324 | 325 | ostr << "int o=" << stringvar(OP_SHIFT, OP_BITS) << ", a=" << stringvar(ARG_SHIFT, ARG_BITS) << ";\n"; 326 | ostr << "x+=" << stringvar(X_COORD_SHIFT, X_COORD_BITS) << "; y=" << stringvar(Y_COORD_SHIFT, Y_COORD_BITS) << ";\n"; 327 | ostr << "f i=" << stringvar("a", LINE_DX_SHIFT, LINE_DX_BITS, ARG_BITS) << ", j=" << stringvar("a", LINE_DY_SHIFT, LINE_DY_BITS, ARG_BITS) << ";\n"; 328 | ostr << "f l=-P*(" << stringvar("a", ARC_A0_SHIFT, ARC_A0_BITS, ARG_BITS) << "), " 329 | << "u=P*(" << stringvar("a", ARC_A1_SHIFT, ARC_A1_BITS, ARG_BITS) << ");\n"; 330 | 331 | return ostr.str(); 332 | 333 | } 334 | 335 | 336 | enum { 337 | OP_HLINE = 1, 338 | OP_VLINE = 2, 339 | OP_DLINE = 3, 340 | ARC_R0 = 0, 341 | ARC_R1 = 1, 342 | ARC_UPPER = 1, 343 | ARC_LOWER = 2, 344 | ARC_FULL = 3, 345 | }; 346 | 347 | 348 | void encode() { 349 | 350 | buf.clear(); 351 | 352 | bmin = -1; 353 | bmax = 0; 354 | dxmin = -1; 355 | dxmax = 0; 356 | dxminc = dxmaxc = cur = 0; 357 | 358 | start(' ', 1); 359 | 360 | start('!', 1); 361 | line(0, 0, 0, 0); 362 | line(0, 1, 0, 4); 363 | 364 | if (DO_PUNCTUATION) { 365 | 366 | start('"', 2); 367 | line(0,4,0,1); 368 | line(1,4,0,1); 369 | 370 | start('#', 4); 371 | line(0, 1, 3, 0); 372 | line(0, 4, 3, 0); 373 | line(1, 0, 0, 5); 374 | line(2, 0, 0, 5); 375 | 376 | start('$', 3); 377 | if (!NEGATE_X) { 378 | line(0, 3, 2, -1); 379 | } 380 | line(1, 0, 0, 5); 381 | arc(1, 2, 0, 1); 382 | arc(1, 3, 2, 1); 383 | if (NEGATE_X) { 384 | line(2, 2, -2, 1); 385 | } 386 | 387 | start('%', 4); 388 | line(0, 2, 3, 1); 389 | arc(1, 4, 0, 3); 390 | arc(2, 1, 0, 3); 391 | 392 | start('&', 5); 393 | line(0, 1, 0, 1); 394 | arc(1, 1, 0, 1); 395 | arc(1, 2, 3, 0); 396 | line(1, 3, 2, 0); 397 | arc(1, 4, 0, 3); 398 | line(2, 1, 0, 2); 399 | arc(3, 1, 0, 1); 400 | 401 | start('(', 2); 402 | line(0, 1, 0, 3); 403 | arc(1, 1, 0, 0); 404 | arc(1, 4, 3, 0); 405 | 406 | start(')', 2); 407 | arc(0, 1, 1, 0); 408 | arc(0, 4, 2, 0); 409 | line(1, 1, 0, 3); 410 | 411 | start('*', 3); 412 | line(0, 2, 2, 2); 413 | if (!NEGATE_X) { 414 | line(0, 4, 2, -2); 415 | } 416 | line(1, 1, 0, 4); 417 | if (NEGATE_X) { 418 | line(2, 2, -2, 2); 419 | } 420 | 421 | start('+', 3); 422 | line(0, 3, 2, 0); 423 | line(1, 2, 0, 2); 424 | 425 | 426 | start(',', 2); 427 | line(0, 0, 1, 1); 428 | 429 | start('-', 3); 430 | line(0, 3, 2, 0); 431 | 432 | } 433 | 434 | start('.', 1); 435 | line(0, 0, 0, 0); 436 | 437 | if (DO_PUNCTUATION) { 438 | start('/', 3); 439 | line(0, 0, 2, 5); 440 | } 441 | 442 | start('0', 3); 443 | line(0, 1, 0, 3); 444 | arc(1, 1, 0, 1); 445 | arc(1, 4, 2, 1); 446 | line(2, 1, 0, 3); 447 | 448 | start('1', 2); 449 | line(0, 4, 1, 1); 450 | line(1, 0, 0, 5); 451 | 452 | start('2', 3); 453 | line(0, 0, 2, 0); 454 | line(0, 0, 2, 4); 455 | arc(1, 4, 2, 1); 456 | 457 | start('3', 3); 458 | line(0, 5, 2, 0); 459 | arc(1, 1, 0, 1); 460 | arc(1, 2, 2, 0); 461 | line(1, 3, 1, 2); 462 | line(2, 1, 0, 1); 463 | 464 | start('4', 3); 465 | line(0, 2, 1, 3); 466 | line(0, 2, 2, 0); 467 | line(2, 0, 0, 5); 468 | 469 | start('5', 3); 470 | line(0, 2, 0, 3); 471 | line(0, 5, 2, 0); 472 | arc(1, 1, 0, 1); 473 | arc(1, 2, 2, 1); 474 | line(2, 1, 0, 1); 475 | 476 | start('6', 3); 477 | line(0, 1, 0, 3); 478 | arc(1, 1, 0, 1); 479 | arc(1, 2, 2, 1); 480 | arc(1, 4, 2, 1); 481 | line(2, 1, 0, 1); 482 | 483 | start('7', 3); 484 | line(0, 0, 2, 5); 485 | line(0, 5, 2, 0); 486 | 487 | start('8', 3); 488 | line(0, 1, 0, 1); 489 | arc(1, 1, 0, 1); 490 | arc(1, 2, 2, 1); 491 | arc(1, 4, 0, 3); 492 | line(2, 1, 0, 1); 493 | 494 | start('9', 3); 495 | line(0, 3, 0, 1); 496 | arc(1, 1, 0, 1); 497 | arc(1, 3, 0, 1); 498 | arc(1, 4, 2, 1); 499 | line(2, 1, 0, 3); 500 | 501 | if (DO_PUNCTUATION) { 502 | start('@', 4); 503 | line(0, 1, 0, 3); 504 | line(1, 0, 1, 0); 505 | line(1, 5, 1, 0); 506 | arc(1, 1, 0, 0); 507 | arc(1, 4, 3, 0); 508 | arc(2, 4, 2, 0); 509 | arc(2, 2, 0, 3); 510 | line(3, 1, 0, 3); 511 | } 512 | 513 | if (DO_UPPERCASE) { 514 | 515 | start('A', 3); 516 | line(0, 0, 0, 4); 517 | line(0, 2, 2, 0); 518 | arc(1, 4, 2, 1); 519 | line(2, 0, 0, 4); 520 | 521 | start('B', 3); 522 | line(0, 0, 0, 5); 523 | line(0, 0, 1, 0); 524 | line(0, 3, 1, 0); 525 | line(0, 5, 1, 0); 526 | arc(1, 1, 1, 0); 527 | arc(1, 2, 2, 0); 528 | arc(1, 4, 1, 1); 529 | line(2, 1, 0, 1); 530 | 531 | start('C', 3); 532 | line(0, 1, 0, 3); 533 | arc(1, 1, 0, 1); 534 | arc(1, 4, 2, 1); 535 | 536 | start('D', 3); 537 | line(0, 0, 0, 5); 538 | line(0, 0, 1, 0); 539 | line(0, 5, 1, 0); 540 | arc(1, 1, 1, 0); 541 | arc(1, 4, 2, 0); 542 | line(2, 1, 0, 3); 543 | 544 | start('E', 3); 545 | line(0, 0, 0, 5); 546 | line(0, 0, 2, 0); 547 | line(0, 3, 1, 0); 548 | line(0, 5, 2, 0); 549 | 550 | start('F', 3); 551 | line(0, 0, 0, 5); 552 | line(0, 3, 1, 0); 553 | line(0, 5, 2, 0); 554 | 555 | start('G', 3); 556 | line(0, 1, 0, 3); 557 | arc(1, 1, 0, 1); 558 | line(1, 2, 1, 0); 559 | arc(1, 4, 2, 1); 560 | line(2, 0, 0, 2); 561 | 562 | start('H', 3); 563 | line(0, 0, 0, 5); 564 | line(0, 3, 2, 0); 565 | line(2, 0, 0, 5); 566 | 567 | start('I', 3); 568 | line(0, 0, 2, 0); 569 | line(0, 5, 2, 0); 570 | line(1, 0, 0, 5); 571 | 572 | start('J', 3); 573 | arc(1, 1, 0, 1); 574 | line(2, 1, 0, 4); 575 | 576 | start('K', 3); 577 | line(0, 0, 0, 5); 578 | line(0, 3, 2, 2); 579 | 580 | if (!NEGATE_X) { 581 | line(0, 3, 2, -3); 582 | } 583 | if (NEGATE_X) { 584 | line(2, 0, -2, 3); // was 2, 5 585 | } 586 | 587 | start('L', 3); 588 | line(0, 0, 0, 5); 589 | line(0, 0, 2, 0); 590 | 591 | start('M', 5); 592 | line(0, 0, 0, 5); 593 | 594 | if (NEGATE_X) { 595 | line(2, 2, -2, 3); // was 2, 0 596 | } else { 597 | line(0, 5, 2, -3); 598 | } 599 | 600 | line(2, 2, 2, 3); 601 | line(4, 0, 0, 5); 602 | 603 | start('N', 3); 604 | line(0, 0, 0, 5); 605 | if (NEGATE_X) { 606 | line(2, 0, -2, 5); 607 | } else { 608 | line(0, 5, 2, -5); 609 | } 610 | line(2, 0, 0, 5); 611 | 612 | start('O', 3); 613 | line(0, 1, 0, 3); 614 | arc(1, 1, 0, 1); 615 | arc(1, 4, 2, 1); 616 | line(2, 1, 0, 3); 617 | 618 | start('P', 3); 619 | line(0, 0, 0, 5); 620 | line(0, 2, 1, 0); 621 | line(0, 5, 1, 0); 622 | arc(1, 3, 1, 0); 623 | arc(1, 4, 2, 0); 624 | line(2, 3, 0, 1); 625 | 626 | start('Q', 3); 627 | line(0, 1, 0, 3); 628 | arc(1, 1, 0, 1); 629 | if (!NEGATE_X) { 630 | line(1, 1, 1, -1); 631 | } 632 | arc(1, 4, 2, 1); 633 | if (NEGATE_X) { 634 | line(2, 0, -1, 1); 635 | } 636 | line(2, 1, 0, 3); 637 | 638 | start('R', 3); 639 | line(0, 0, 0, 5); 640 | line(0, 2, 1, 0); 641 | line(0, 5, 1, 0); 642 | if (!NEGATE_X) { 643 | line(1, 2, 1, -2); 644 | } 645 | arc(1, 3, 1, 0); 646 | arc(1, 4, 2, 0); 647 | if (NEGATE_X) { 648 | line(2, 0, -1, 2); 649 | } 650 | line(2, 3, 0, 1); 651 | 652 | start('S', 3); 653 | if (!NEGATE_X) { 654 | line(0, 4, 2, -3); 655 | } 656 | arc(1, 1, 0, 1); 657 | arc(1, 4, 2, 1); 658 | if (NEGATE_X) { 659 | line(2, 1, -2, 3); 660 | } 661 | 662 | start('T', 3); 663 | line(0, 5, 2, 0); 664 | line(1, 0, 0, 5); 665 | 666 | start('U', 3); 667 | line(0, 1, 0, 4); 668 | arc(1, 1, 0, 1); 669 | line(2, 1, 0, 4); 670 | 671 | start('V', 3); 672 | if (!NEGATE_X) { 673 | line(0, 5, 1, -5); 674 | } 675 | if (NEGATE_X) { 676 | line(1, 0, -1, 5); 677 | } 678 | line(1, 0, 1, 5); 679 | 680 | start('W', 5); 681 | if (!NEGATE_X) { 682 | line(0, 5, 1, -5); 683 | } 684 | if (NEGATE_X) { 685 | line(1, 0, -1, 5); 686 | } 687 | line(1, 0, 1, 3); 688 | if (!NEGATE_X) { 689 | line(2, 3, 1, -3); 690 | } 691 | if (NEGATE_X) { 692 | line(3, 0, -1, 3); 693 | } 694 | line(3, 0, 1, 5); 695 | 696 | start('X', 3); 697 | line(0, 0, 2, 5); 698 | if (!NEGATE_X) { 699 | line(0, 5, 2, -5); 700 | } else { 701 | line(2, 0, -2, 5); 702 | } 703 | 704 | start('Y', 3); 705 | if (!NEGATE_X) { 706 | line(0, 5, 1, -3); 707 | } 708 | line(1, 0, 0, 2); 709 | if (NEGATE_X) { 710 | line(1, 2, -1, 3); 711 | } 712 | line(1, 2, 1, 3); 713 | 714 | start('Z', 3); 715 | line(0, 0, 2, 0); 716 | line(0, 0, 2, 5); 717 | line(0, 5, 2, 0); 718 | } 719 | 720 | start('a', 3); 721 | line(0, 3, 1, 0); 722 | arc(1, 1, 0, 3); 723 | arc(1, 2, 2, 0); 724 | line(2, 0, 0, 2); 725 | 726 | start('b', 3); 727 | line(0, 0, 0, 5); 728 | arc(1, 1, 0, 1); 729 | arc(1, 2, 2, 1); 730 | line(2, 1, 0, 1); 731 | 732 | start('c', 3); 733 | line(0, 1, 0, 1); 734 | arc(1, 1, 0, 1); 735 | arc(1, 2, 2, 1); 736 | 737 | start('d', 3); 738 | line(0, 1, 0, 1); 739 | arc(1, 1, 0, 1); 740 | arc(1, 2, 2, 1); 741 | line(2, 0, 0, 5); 742 | 743 | start('e', 3); 744 | line(0, 1, 0, 1); 745 | line(0, 2, 2, 0); 746 | arc(1, 1, 0, 1); 747 | arc(1, 2, 2, 1); 748 | 749 | start('f', 3); 750 | line(0, 3, 2, 0); 751 | line(1, 0, 0, 4); 752 | arc(2, 4, 3, 0); 753 | 754 | start('g', 3); 755 | line(0, 0, 1, 0); 756 | arc(1, 1, 1, 0); 757 | arc(1, 2, 0, 3); 758 | line(2, 1, 0, 2); 759 | 760 | start('h', 3); 761 | line(0, 0, 0, 5); 762 | arc(1, 2, 2, 1); 763 | line(2, 0, 0, 2); 764 | 765 | start('i', 1); 766 | line(0, 0, 0, 3); 767 | line(0, 4, 0, 0); 768 | 769 | start('j', 3); 770 | arc(1, 1, 0, 1); 771 | line(2, 1, 0, 2); 772 | line(2, 4, 0, 0); 773 | 774 | start('k', 3); 775 | line(0, 0, 0, 5); 776 | line(0, 2, 2, 1); 777 | if (NEGATE_X) { 778 | line(2, 0, -2, 2); 779 | } 780 | if (!NEGATE_X) { 781 | line(0, 2, 2, -2); 782 | } 783 | 784 | start('l', 1); 785 | line(0, 0, 0, 5); 786 | 787 | start('m', 5); 788 | line(0, 0, 0, 3); 789 | arc(1, 2, 2, 1); 790 | line(2, 0, 0, 2); 791 | arc(3, 2, 2, 1); 792 | line(4, 0, 0, 2); 793 | 794 | start('n', 3); 795 | line(0, 0, 0, 3); 796 | arc(1, 2, 2, 1); 797 | line(2, 0, 0, 2); 798 | 799 | start('o', 3); 800 | line(0, 1, 0, 1); 801 | arc(1, 1, 0, 1); 802 | arc(1, 2, 2, 1); 803 | line(2, 1, 0, 1); 804 | 805 | start('p', 3); 806 | line(0, 0, 0, 3); 807 | arc(1, 2, 0, 3); 808 | 809 | start('q', 3); 810 | arc(1, 2, 0, 3); 811 | line(2, 0, 0, 3); 812 | 813 | start('r', 3); 814 | line(0, 0, 0, 3); 815 | arc(1, 2, 2, 1); 816 | 817 | start('s', 3); 818 | if (!NEGATE_X) { 819 | line(0, 2, 2, -1); 820 | } 821 | arc(1, 1, 0, 1); 822 | arc(1, 2, 2, 1); 823 | if (NEGATE_X) { 824 | line(2, 1, -2, 1); 825 | } 826 | 827 | start('t', 3); 828 | line(0, 3, 2, 0); 829 | line(1, 1, 0, 4); 830 | arc(2, 1, 0, 0); 831 | 832 | start('u', 3); 833 | line(0, 1, 0, 2); 834 | arc(1, 1, 0, 1); 835 | line(2, 0, 0, 3); 836 | 837 | start('v', 3); 838 | if (!NEGATE_X) { 839 | line(0, 3, 1, -3); 840 | } 841 | line(1, 0, 1, 3); 842 | if (NEGATE_X) { 843 | line(1, 0, -1, 3); 844 | } 845 | 846 | start('w', 5); 847 | if (!NEGATE_X) { 848 | line(0, 3, 1, -3); 849 | } 850 | line(1, 0, 1, 2); 851 | if (NEGATE_X) { 852 | line(1, 0, -1, 3); 853 | } 854 | if (!NEGATE_X) { 855 | line(2, 2, 1, -2); 856 | } 857 | line(3, 0, 1, 3); 858 | if (NEGATE_X) { 859 | line(3, 0, -1, 2); 860 | } 861 | 862 | start('x', 3); 863 | line(0, 0, 2, 3); 864 | if (NEGATE_X) { 865 | line(2, 0, -2, 3); 866 | } 867 | if (!NEGATE_X) { 868 | line(0, 3, 2, -3); 869 | } 870 | 871 | start('y', 3); 872 | line(0, 0, 1, 0); 873 | line(0, 2, 0, 1); 874 | arc(1, 1, 1, 0); 875 | arc(1, 2, 0, 1); 876 | line(2, 1, 0, 2); 877 | 878 | start('z', 3); 879 | line(0, 0, 2, 0); 880 | line(0, 0, 2, 3); 881 | line(0, 3, 2, 0); 882 | 883 | 884 | 885 | } 886 | 887 | void decode() { 888 | 889 | std::ofstream ostr("test.svg"); 890 | 891 | ostr << "\n"; 892 | ostr << "\n"; 893 | ostr << "\n"; 894 | 895 | 896 | int print = 0; 897 | uint16 w = 0; 898 | uint16 scl = 10; 899 | uint16 ox = 1; 900 | uint16 oy = 6; 901 | 902 | int cnt = 0; 903 | cur = 0; 904 | 905 | ostr << " bmax) { 914 | 915 | if (c0 == SEP_2) { 916 | cur = buf[++i]; 917 | } else { 918 | --i; 919 | cur++; 920 | } 921 | 922 | ox += w; 923 | w = c1 - SEP_0; 924 | if (print) std::cout << "\nstart(" << cur << ", " << w << ")\n"; 925 | X_COORD = 0; 926 | if (cnt++ >= 13) { oy += 6; ox = 1; cnt = 0;} 927 | 928 | } else { 929 | uint16 x = (val >> X_COORD_SHIFT) & MASK(X_COORD_BITS); 930 | uint16 y = (val >> Y_COORD_SHIFT) & MASK(Y_COORD_BITS); 931 | uint16 op = (val >> OP_SHIFT) & MASK(OP_BITS); 932 | uint16 arg = (val >> ARG_SHIFT) & MASK(ARG_BITS); 933 | X_COORD += x; 934 | if (op == OP_LINE || op == OP_NLINE) { 935 | int ldx = ((arg >> LINE_DX_SHIFT) & MASK(LINE_DX_BITS)); 936 | int ldy = (arg >> LINE_DY_SHIFT) & MASK(LINE_DY_BITS); 937 | if (op == OP_NLINE) { 938 | if (NEGATE_X) { 939 | ldx *= -1; 940 | } else { 941 | ldy *= -1; 942 | } 943 | } 944 | if (print) std::cout << "line(" << X_COORD << ", " << y << ", " << ldx << ", " << ldy << ");\n"; 945 | ostr << "M " << scl*(ox+X_COORD) << " " << scl*(oy-y) << " l " << scl*ldx << " " << -scl*ldy << " "; 946 | } else if (op == OP_ARC) { 947 | uint16 a0 = (arg >> ARC_A0_SHIFT) & MASK(ARC_A0_BITS); 948 | uint16 a1 = (arg >> ARC_A1_SHIFT) & MASK(ARC_A1_BITS); 949 | if (print) std::cout << "arc(" << X_COORD << ", " << y << ", " << a0 << ", " << a1 << ");\n"; 950 | float t0 = -M_PI+a0*M_PI/2; 951 | float t1 = t0 + (a1+1)*M_PI/2; 952 | float cx = scl*(ox+X_COORD); 953 | float cy = scl*(oy-y); 954 | for (float f=t0; f\n"; 968 | 969 | ostr << "\n"; 970 | 971 | 972 | } 973 | 974 | void usage() { 975 | std::cout << "usage: encode -random\n"; 976 | std::cout << " or: encode -final\n"; 977 | exit(1); 978 | } 979 | 980 | int main(int argc, char** argv) { 981 | 982 | if (argc != 2) { 983 | usage(); 984 | } 985 | 986 | std::string arg(argv[1]); 987 | bool randomize; 988 | 989 | if (arg == "-random") { 990 | randomize = true; 991 | } else if (arg == "-final") { 992 | randomize = false; 993 | } else { 994 | usage(); 995 | } 996 | 997 | srand(time(NULL)); 998 | 999 | size_t best(-1); 1000 | bool was_good = false; 1001 | 1002 | for (int i=0; i<100000; ++i) { 1003 | 1004 | if (randomize) { permute_shifts(); } 1005 | 1006 | encode(); 1007 | bool this_good = (bmin > SEP_1); 1008 | if (!this_good) { continue; } 1009 | 1010 | std::string dstr = stringify(); 1011 | std::string vstr = stringvars(); 1012 | 1013 | size_t len = dstr.length() + vstr.length(); 1014 | 1015 | if (this_good && (!was_good || len < best)) { 1016 | 1017 | was_good = true; 1018 | best = len; 1019 | 1020 | if (shifts.size()) { 1021 | std::cerr << "layout (LSB first):\n"; 1022 | size_t start = 0; 1023 | for (size_t i=0; i 2 | #include 3 | #include 4 | 5 | typedef int i; 6 | typedef float f; 7 | typedef unsigned char u; 8 | 9 | f M = 100; 10 | f L = 1e-4; 11 | f R = 0.4; 12 | 13 | struct v { 14 | f x,y,z; 15 | v() {} 16 | v (f a, f b, f c=0): x(a),y(b),z(c) {} 17 | v operator*(f s) { return v(x*s,y*s,z*s); } 18 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 19 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 20 | v operator-(v r) { return v(x-r.x,y-r.y,z-r.z); } 21 | v operator!() { return *this*(1/~(*this)); } 22 | f operator~() { return sqrt(+(*this)); } 23 | f operator+() { return *this%*this; } 24 | }; 25 | 26 | struct hit { 27 | v p, pc; 28 | f d2; 29 | hit(v P): p(P), pc(P+v(2*M*M,0)), d2(2*M*M) {} 30 | f operator()(v pn) { 31 | f d2n = +(p-pn); 32 | if (d2n < d2) { pc=pn; d2=d2n; } 33 | return d2; 34 | } 35 | }; 36 | 37 | v fa(f t) { return v(cos(t),sin(t),0); } 38 | 39 | f min(f a, f b) { return ab?a:b; } 41 | f c01(f a) { return min(max(a,0),1); } 42 | v lerp(v a, v b, f u) { return a*(1-u)+b*u; } 43 | v c01(v x) { return v(c01(x.x),c01(x.y),c01(x.z)); } 44 | i fi(f c) { return c01(c)*255; } 45 | 46 | v black(0,0,0); 47 | v white(1,1,1); 48 | 49 | template float T(v o, v d, D& k, v& pi, v& n) { 50 | pi=o; 51 | f u=0; 52 | f l0=k(pi, 0); 53 | for (i c=0;u b) ? fa(b) : q)) * r); 69 | } 70 | } 71 | 72 | f seg(v a,v b,hit& h) { 73 | f l = +(b-a); 74 | f u = l?-((a-h.p)%(b-a))/l:0; 75 | return h((u<0)?a:((u>1)?b:lerp(a,b,u))); 76 | } 77 | 78 | f seg(f x,f y,f dx,f dy,hit& h) { 79 | return seg(v(x,y),v(x,y)+v(dx,dy),h); 80 | } 81 | 82 | f dst(v p, v* nn) { 83 | 84 | hit h(p); 85 | 86 | i data[] = { 87 | 0x40426040, 88 | 0x24824044, 89 | 0xe38d2486, 90 | 0x814a6048, 91 | 0x42966329, 92 | 0x632d814e, 93 | 0x6031429e, 94 | 0x60716331, 95 | 0 96 | }; 97 | 98 | for (u* c=(u*)data; *c; c+=2) { 99 | i o = c[0]>>5; 100 | f x = c[0]&31; 101 | f y = c[1]&31; 102 | i l = c[1]>>5; 103 | (o>=1&&o<=3)?seg(x,y,l*(o!=2),l*(o!=1),h): 104 | (o==4)?arc(v(x/2,y/2),1+0.5*(l>>2),-M_PI*((l>>1)&1),M_PI*(l&1),h):0; 105 | } 106 | 107 | if (nn) { *nn = !(p-h.pc); } 108 | return sqrt(h.d2)-R; 109 | 110 | } 111 | 112 | f dst0(v p) { 113 | return dst(p, 0); 114 | } 115 | 116 | v light(v c, v n, v l, v d) { 117 | f nl = max(n%l,0); 118 | v h = !(l-d); 119 | f nh = max(n%h,0); 120 | return c01(lerp(c*0.25, c, nl) + white*pow(nh,120)); 121 | } 122 | 123 | int main(int argc, char** argv) { 124 | v o(10,2,30); 125 | i nx=480; 126 | i ny=180; 127 | f dx=24.0/nx; 128 | v pi,n; 129 | v l = !v(-1,2,1); 130 | printf("P3 %d %d 255\n", nx, ny); 131 | for (i y=0; y 2 | #include 3 | #define op operator 4 | #define ret return 5 | 6 | typedef int i; 7 | typedef float f; 8 | typedef unsigned char u; 9 | 10 | f M=80; 11 | f L=1e-4; 12 | f R=.4; 13 | 14 | struct v { 15 | f x,y,z; 16 | v() {} 17 | v (f a, f b, f c=0): x(a),y(b),z(c) {} 18 | v operator*(f s) { return v(x*s,y*s,z*s); } 19 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 20 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 21 | v operator-(v r) { return v(x-r.x,y-r.y,z-r.z); } 22 | v operator!() { return *this*(1/~(*this)); } 23 | f operator~() { return sqrt(+(*this)); } 24 | f operator+() { return *this%*this; } 25 | }; 26 | 27 | struct q { 28 | v p,pc; 29 | f d; 30 | q(v P): p(P), pc(P+v(2e2,0)), d(4e4) {} 31 | f operator()(v pn) { 32 | f dn=+(p-pn); 33 | if(dnb?a:b; } 40 | f c01(f a) { return a>1?1:max(a,0); } 41 | v le(v a, v b, f u) { return a*(1-u)+b*u; } 42 | v c01(v x) { return v(c01(x.x),c01(x.y),c01(x.z)); } 43 | i fi(f c) { return c01(c)*255; } 44 | 45 | v black(0,0,0); 46 | v white(1,1,1); 47 | 48 | f a(v c,f r,f a,f b,q& h) { 49 | v d=v(h.p.x,h.p.y)-c; 50 | if (~db)?fa(b):d))*r); 56 | } 57 | } 58 | 59 | f s(f x,f y,f dx,f dy,q& h) { 60 | v a(x,y); 61 | v d(dx,dy); 62 | f l=+d; 63 | f u=c01((h.p-a)%d/l); 64 | return h(a+d*u); 65 | } 66 | 67 | f dst(v p, v* nn=0) { 68 | q h(p); 69 | i d[] = { 70 | 0x40426040,0x24824044,0xe38d2486,0x814a6048, 71 | 0x42966329,0x632d814e,0x6031429e,0x60716331, 72 | 0 73 | }; 74 | for (u* c=(u*)d;*c;c+=2) { 75 | i o=c[0]>>5; 76 | f x=c[0]&31; 77 | f y=c[1]&31; 78 | i l=c[1]>>5; 79 | (o>=1&&o<=3)?s(x,y,l*(o!=2),l*(o!=1),h): 80 | (o==4)?a(v(x/2,y/2),1+.5*(l>>2), 81 | -M_PI*((l>>1)&1),M_PI*(l&1),h):0; 82 | } 83 | if (nn){*nn=!(p-h.pc);} 84 | return sqrt(h.d)-R; 85 | } 86 | 87 | f T(v o, v d, v& pi, v& n) { 88 | pi=o; 89 | f u=0; 90 | f l0=dst(pi); 91 | for (i c=0;u 2 | #include 3 | #define op operator 4 | #define ret return 5 | 6 | typedef int i; 7 | typedef float f; 8 | typedef unsigned char u; 9 | 10 | f M=80; 11 | f L=1e-4; 12 | f R=.4; 13 | 14 | struct v { 15 | f x,y,z; 16 | v() {} 17 | v (f a, f b, f c=0): x(a),y(b),z(c) {} 18 | v operator*(f s) { return v(x*s,y*s,z*s); } 19 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 20 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 21 | v operator-(v r) { return *this+r*-1; } 22 | v operator!() { return *this*(1/~(*this)); } 23 | f operator~() { return sqrt(*this%*this); } 24 | }; 25 | 26 | struct q { 27 | v p,c; 28 | f d; 29 | q(v P): p(P), c(P+v(2e2,0)), d(4e4) {} 30 | f operator()(v n) { 31 | f e=(p-n)%(p-n); 32 | if(eb)?A(b):d))*r); 47 | } 48 | } 49 | 50 | f s(f x,f y,f s,f t,q& h) { 51 | v a(x,y); 52 | v d(s,t); 53 | f u=(h.p-a)%d/(d%d); 54 | return h(a+d*(u<0?0:u>1?1:u)); 55 | } 56 | 57 | f dst(v p, v* n=0) { 58 | q h(p); 59 | i d[] = { 60 | 1078091840, 61 | 612515908, 62 | -477289338, 63 | -2125832120, 64 | 1117152041, 65 | 1663926606, 66 | 1613841054, 67 | 1618043697, 68 | 0 69 | }; 70 | for (u* c=(u*)d;*c;c+=2) { 71 | i o=c[0]>>5; 72 | f x=c[0]&31; 73 | f y=c[1]&31; 74 | i l=c[1]>>5; 75 | (o>=1&&o<=3)?s(x,y,l*(o!=2),l*(o!=1),h): 76 | (o==4)?a(v(x/2,y/2),1+.5*(l>>2), 77 | -M_PI*((l/2)&1),M_PI*(l&1),h):0; 78 | } 79 | if (n){*n=!(p-h.c);} 80 | return sqrt(h.d)-R; 81 | } 82 | 83 | v T(v o, v d) { 84 | v pi=o; 85 | f u=0; 86 | f l0=dst(pi); 87 | for (i c=0;u 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | typedef int i; 7 | typedef float f; 8 | typedef unsigned char u; 9 | 10 | f M=50, // maximum distance we care about in sphere tracing 11 | L=1e-4, // minimum distance tolerance 12 | R=.4; // radius of letters in "mattz" 13 | 14 | // vector struct 15 | struct v { 16 | f x,y,z; 17 | v() {} 18 | v (f a, f b, f c=0): x(a),y(b),z(c) {} 19 | v operator*(f s) { return v(x*s,y*s,z*s); } 20 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 21 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 22 | v operator-(v r) { return *this+r*-1; } 23 | v operator!() { return *this*(1/~(*this)); } 24 | f operator~() { return sqrt(*this%*this); } 25 | }; 26 | 27 | // hit query struct for successive distance queries 28 | struct q { 29 | 30 | v p, c; // p: world point and c: closest in geometry 31 | f d; // d: squared distance from p to c 32 | 33 | // construct with large distance 34 | q(v P): p(P), c(P+v(2e2,0)), d(4e4) {} 35 | 36 | // see if new point n is closer to p than current point c 37 | // and modify distances if so 38 | void operator()(v n) { 39 | f e= (p-n)%(p-n); 40 | if (eb)?A(b):d))*r); // return point on circle 60 | } 61 | } 62 | 63 | // test distance from point h.p to a line segment going from (x,y) to 64 | // (x+s,y+t) (z=0). 65 | 66 | i S(f x,f y,f s,f t,q& h) { 67 | v a(x,y), d(s,t); 68 | f u=(h.p-a)%d/(d%d); 69 | h(a+d*(u<0?0:u>1?1:u)); 70 | } 71 | 72 | // test distance from point p to the text "mattz" 73 | f D(v p, v* n=0) { 74 | // initialize our distance query 75 | q h(p); 76 | // encode "mattz" as bytecodes 77 | i d[] = { 78 | 1078091840, 79 | 612515908, 80 | -477289338, 81 | -2125832120, 82 | 1117152041, 83 | 1663926606, 84 | 1613841054, 85 | 1618043697, 86 | 0 87 | }; 88 | // interpret bytecodes 89 | for (u* c=(u*)d;*c;c+=2) { 90 | i o=c[0]>>5, l=c[1]>>5; 91 | f x=c[0]&31, y=c[1]&31, r=M_PI; 92 | (o>=1&&o<=3)?S(x,y,l*(o&1),l*(o&2)/2,h): 93 | (o&4)?C(x/2,y/2,1+.5*(l/4), 94 | -r*((l&2)/2),r*(l&1),h):0; 95 | } 96 | // if we were asked for a normal, spit it out 97 | if (n){*n=!(p-h.c);} 98 | // return the distance 99 | return sqrt(h.d)-R; 100 | } 101 | 102 | v T(v o, v d) { 103 | v p=o; 104 | f u=0, l=D(p); 105 | while (u 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | typedef int i; 7 | typedef float f; 8 | typedef unsigned char u; 9 | 10 | f M=50, // maximum distance we care about in sphere tracing 11 | L=1e-4, // minimum distance tolerance 12 | R=.4; // radius of letters 13 | 14 | 15 | // vector struct 16 | struct v { 17 | f x,y,z; 18 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 19 | v operator*(f s) { return v(x*s,y*s,z*s); } 20 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 21 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 22 | v operator-(v r) { return *this+r*-1; } 23 | v operator!() { return *this*(1/~(*this)); } 24 | f operator~() { return sqrt(*this%*this); } 25 | }; 26 | 27 | v K(-1,.5,1), // light position 28 | W(1,1,1), B; 29 | 30 | // hit query struct for successive distance queries 31 | struct q { 32 | 33 | v p, c; // p: world point and c: closest in geometry 34 | f d; // d: squared distance from p to c 35 | 36 | // construct with large distance 37 | q(v P): p(P), c(P+v(2e2,0)), d(4e4) {} 38 | 39 | // see if new point n is closer to p than current point c 40 | // and modify distances if so 41 | i operator()(v n) { 42 | f e= (p-n)%(p-n); 43 | if (e1?1:a; } 49 | v X(v a, v b, f u) { return a*(1-u)+b*u; } 50 | 51 | // construct a unit vector with given angle 52 | v A(f t) { return v(cos(t),sin(t)); } 53 | 54 | // test distance from point h.p to a circular arc centered at point x, 55 | // y, (z=0) with radius r and angle range given by a & b 56 | i C(f x, f y, f r, f a, f b, q& h) { 57 | v c(x,y); // center of circle 58 | v d=v(h.p.x,h.p.y)-c; // vector from projection of point p onto z=0 59 | // plane to center of circle 60 | if (~db)?A(b):d)*r); // return point on circle 66 | } 67 | } 68 | 69 | // test distance from point h.p to a line segment going from (x,y) to 70 | // (x+s,y+t) (z=0). 71 | 72 | i S(f x,f y,f s,f t,q& h) { 73 | v a(x,y), d(s,t); 74 | f u=(h.p-a)%d/(d%d); 75 | h(a+d*U(u)); 76 | } 77 | 78 | // test distance from point p to the text "mattz" 79 | f D(v p, v& n) { 80 | 81 | // initialize our distance query 82 | q h(p); 83 | 84 | // encode "mattz" as bytecodes 85 | i d[] = { 86 | 1078091840, 87 | 612515908, 88 | -477289338, 89 | -2125832120, 90 | 1117152041, 91 | 1663926606, 92 | 1613841054, 93 | 1618043697, 94 | 0 95 | }; 96 | 97 | // interpret bytecodes by calling S() and C() with the appropriate 98 | // parameters 99 | for (u* c=(u*)d;*c;c+=2) { 100 | i o=c[0]>>5, a=c[1]>>5; // o: opcode in 0..7, a: arguments in 0..7 101 | f x=c[0]&31, y=c[1]&31, r=M_PI; // x,y are position in 0..31 102 | (o>=1&&o<=3) ? S(x,y,a*(o&1),a*(o&2)/2,h) : // line segments are 103 | // opcode 1 2 or 3: 1 104 | // is horiz, 2 is 105 | // vert, 3 is diag; a 106 | // encodes length 107 | (o&4)?C(x/2,y/2,1+.5*(a/4), // circles are opcode 4. radius is 108 | // given by highest bit of a. start 109 | // and end angles given by lowest 110 | // bits of a. 111 | -r*(a&2)/2,r*(a&1),h):0; 112 | } 113 | 114 | // if we were asked for a normal, spit it out 115 | n=!(p-h.c); 116 | 117 | // return the distance 118 | return sqrt(h.d)-R; 119 | 120 | } 121 | 122 | v I(v c, v n, v d) { 123 | return X(c*(.7*U(n%K)+.3),W,pow(U(n%!(K-d)),40)); 124 | } 125 | 126 | 127 | // do our raytracing from ray origin o in direction d 128 | v T(v o, v d) { 129 | 130 | ////////////////////////////////////////////////// 131 | // first do the sphere tracing for letters 132 | 133 | v n; // normal at hit 134 | f u=0, l=0; // u tracks distance along ray, l tracks distance 135 | 136 | while (u 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | typedef int i; 7 | typedef float f; 8 | typedef unsigned char u; 9 | 10 | // vector struct 11 | struct v { 12 | f x,y,z; 13 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 14 | v operator*(f s) { return v(x*s,y*s,z*s); } 15 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 16 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 17 | v operator-(v r) { return *this+r*-1; } 18 | v operator!() { return *this*(1/~(*this)); } 19 | f operator~() { return sqrt(*this%*this); } 20 | } L(-1,.5,1), W(1,1,1), B; 21 | 22 | // hit query struct for successive distance queries 23 | struct q { 24 | 25 | v p, c; // p: world point and c: closest in geometry 26 | f d; // d: squared distance from p to c 27 | 28 | // construct with large distance 29 | q(v P): p(P), d(9e9) {} 30 | 31 | // see if new point n is closer to p than current point c 32 | // and modify distances if so 33 | i operator()(v n) { 34 | f e= (p-n)%(p-n); 35 | if (e1?1:a; } 41 | 42 | //v M(v a, v b, f u) { return a*(1-u)+b*u; } 43 | //v I(v c, v n, v d) { return M(c*(.7*U(n%L)+.3),W,pow(U(n%!(L-d)),40)); } 44 | 45 | // test distance from point h.p to a circular arc centered at point x, 46 | // y, (z=0) with radius r and angle range given by a & b 47 | i C(f x, f y, f r, f a, f b, q& h) { 48 | v d(h.p.x-x,h.p.y-y); 49 | f t = ~d<1e-4?a:atan2(d.y,d.x); 50 | t = tb?b:t; 51 | h(v(x+r*cos(t),y+r*sin(t))); 52 | } 53 | 54 | // test distance from point h.p to a line segment going from (x,y) to 55 | // (x+s,y+t) (z=0). 56 | 57 | i S(f x,f y,f s,f t,q& h) { 58 | v a(x,y), d(s,t); 59 | f u=(h.p-a)%d/(d%d); 60 | h(a+d*U(u)); 61 | } 62 | 63 | // test distance from point p to the text "mattz" 64 | f D(v p, v& n) { 65 | 66 | // initialize our distance query 67 | q h(p); 68 | 69 | // encode "mattz" as bytecodes 70 | i d[] = { 71 | 1078091840, 72 | 612515908, 73 | -477289338, 74 | -2125832120, 75 | 1117152041, 76 | 1663926606, 77 | 1613841054, 78 | 1618043697, 79 | 0 80 | }; 81 | 82 | // interpret bytecodes by calling S() and C() with the appropriate 83 | // parameters 84 | for (u* c=(u*)d;*c;c+=2) { 85 | i o=c[0]>>5, a=c[1]>>5; // o: opcode in 0..7, a: arguments in 0..7 86 | f x=c[0]&31, y=c[1]&31, r=M_PI; // x,y are position in 0..31 87 | (o<4) ? S(x,y,a*(o&1),a*(o&2)/2,h) : 88 | (o&4)?C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h):0; 89 | } 90 | 91 | // if we were asked for a normal, spit it out 92 | n=!(p-h.c); 93 | 94 | // return the distance 95 | return sqrt(h.d)-.4; 96 | 97 | } 98 | 99 | // do our raytracing from ray origin o in direction d 100 | v T(v o, v d) { 101 | 102 | ////////////////////////////////////////////////// 103 | // first do the sphere tracing for letters 104 | 105 | v n; // normal at hit 106 | f u=0, l=0; // u tracks distance along ray, l tracks distance 107 | 108 | while (u<50) { 109 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 110 | f s = pow(U(n%!(L-d)),40); 111 | return v(1)*(.7*U(n%L)+.3)*(1-s)+W*s; 112 | } 113 | } 114 | return B; 115 | 116 | } 117 | 118 | i main() { 119 | v o(10,2,30); // camera 120 | i w=720, h=270, x, y=-1; 121 | f s=24.0/w; // disp on pixel plane 122 | printf("P6 %d %d 255\n", w, h); 123 | while (++y 2 | #include 3 | #include 4 | #define O operator 5 | #define E return 6 | 7 | typedef int i; 8 | typedef float f; 9 | typedef unsigned char u; 10 | 11 | // vector struct 12 | struct v { 13 | f x,y,z; 14 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 15 | v operator*(f s) { return v(x*s,y*s,z*s); } 16 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 17 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 18 | v operator-(v r) { return *this+r*-1; } 19 | v operator!() { return *this*(1/~(*this)); } 20 | f operator~() { return sqrt(*this%*this); } 21 | } L(!v(-.5,2,4)), W(1,1,1), B; 22 | 23 | // hit query struct for successive distance queries 24 | struct q { 25 | 26 | v p, c; // p: world point and c: closest in geometry 27 | f d; // d: distance from p to c 28 | 29 | // construct with large distance 30 | q(v P): p(P), d(9e9) {} 31 | 32 | // see if new point n is closer to p than current point c 33 | // and modify distances if so 34 | i operator()(v n) { 35 | f e= ~(p-n); 36 | if (e1?1:a; } 42 | 43 | // test distance from point h.p to a circular arc centered at point x, 44 | // y, (z=0) with radius r and angle range given by a & b 45 | i C(f x, f y, f r, f a, f b, q& h) { 46 | v d(h.p.x-x,h.p.y-y); 47 | f t = ~d<1e-4?a:atan2(d.y,d.x); 48 | t = tb?b:t; 49 | h(v(x+r*cos(t),y+r*sin(t))); 50 | } 51 | 52 | // test distance from point h.p to a line segment going from (x,y) to 53 | // (x+s,y+t) (z=0). 54 | i S(f x,f y,f s,f t,q& h) { 55 | v a(x,y), d(s,t); 56 | f u=(h.p-a)%d/(d%d); 57 | h(a+d*U(u)); 58 | } 59 | 60 | i P(v n, f d, q& h) { h(h.p-n*(h.p%n-d)); } 61 | 62 | // test distance from point p to the text "mattz" 63 | f D(v p, v& n) { 64 | 65 | // initialize our distance query 66 | q h(p); 67 | 68 | // encode "mattz" as bytecodes 69 | i d[] = { 70 | 1078091840, 71 | 612515908, 72 | -477289338, 73 | -2125832120, 74 | 1117152041, 75 | 1663926606, 76 | 1613841054, 77 | 1618043697, 78 | 0 79 | }; 80 | 81 | // interpret bytecodes by calling S() and C() with the appropriate 82 | // parameters 83 | for (u* c=(u*)d;*c;c+=2) { 84 | i o=c[0]>>5, a=c[1]>>5; // o: opcode in 0..7, a: arguments in 0..7 85 | f x=c[0]&31, y=c[1]&31, r=M_PI; // x,y are position in 0..31 86 | (o<4) ? S(x,y,a*(o&1),a*(o&2)/2,h) : 87 | (o&4) ? C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h) : 0; 88 | 89 | } 90 | 91 | P(v(0,0,1),-.9,h); 92 | P(v(0,1,0),-.9,h); 93 | 94 | // if we were asked for a normal, spit it out 95 | n=!(p-h.c); 96 | 97 | // return the distance 98 | return h.d-.45; 99 | 100 | } 101 | 102 | // do our raytracing from ray origin o in direction d 103 | f T(v o, v d) { 104 | 105 | ////////////////////////////////////////////////// 106 | // first do the sphere tracing for letters 107 | 108 | f u=0, l=0; // u is dist along ray, l is dist to obj 109 | v n; 110 | 111 | while (u<50) 112 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 113 | f s=pow(U(n%!(L-d)),40); 114 | f w=(.3*U(n%L)+.65)*(1-s)+s; 115 | // do ambient occlusion pass 116 | f c=0, i=1, a=1, e=.15, k=.9; 117 | v h=o+d*u, g; 118 | while (++c<6) { 119 | f p=e*c; 120 | a -= .9*(p-D(h+n*p,g))*(i/=2); 121 | } 122 | return w*a; 123 | } 124 | 125 | ////////////////////////////////////////////////// 126 | 127 | return 0; 128 | 129 | } 130 | 131 | i main() { 132 | v o(10,2,30); // camera 133 | i w=720, h=270, x, y=-1; 134 | //i w=240, h=90, x, y=-1; 135 | //i w=360, h=135, x, y=-1; 136 | f s=24.0/w, t; // disp on pixel plane 137 | printf("P5 %d %d 255\n", w, h); 138 | while (++y 2 | #include 3 | #include 4 | #define O operator 5 | #define E return 6 | 7 | typedef int i; 8 | typedef float f; 9 | typedef unsigned char u; 10 | 11 | // vector struct 12 | struct v { 13 | f x,y,z; 14 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 15 | v operator*(f s) { return v(x*s,y*s,z*s); } 16 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 17 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 18 | v operator-(v r) { return *this+r*-1; } 19 | v operator!() { return *this*(1/~(*this)); } 20 | f operator~() { return sqrt(*this%*this); } 21 | } L(!v(-.5,2,4)), W(1,1,1), B; 22 | 23 | // hit query struct for successive distance queries 24 | struct q { 25 | 26 | v p, c; // p: world point and c: closest in geometry 27 | f d; // d: distance from p to c 28 | 29 | // construct with large distance 30 | q(v P): p(P), d(9e9) {} 31 | 32 | // see if new point n is closer to p than current point c 33 | // and modify distances if so 34 | i operator()(v n) { 35 | f e= ~(p-n); 36 | if (e1?1:a; } 42 | 43 | // test distance from point h.p to a circular arc centered at point x, 44 | // y, (z=0) with radius r and angle range given by a & b 45 | i C(f x, f y, f r, f a, f b, q& h) { 46 | f t = atan2(h.p.y-y,h.p.x-x); 47 | t = tb?b:t; 48 | h(v(x+r*cos(t),y+r*sin(t))); 49 | } 50 | 51 | // test distance from point h.p to a line segment going from (x,y) to 52 | // (x+s,y+t) (z=0). 53 | i S(f x,f y,f s,f t,q& h) { 54 | v a(x,y), d(s,t); 55 | f u=(h.p-a)%d/(d%d); 56 | h(a+d*U(u)); 57 | } 58 | 59 | i P(v n, q& h) { h(h.p-n*(h.p%n+.9)); } 60 | 61 | // test distance from point p to the text "mattz" 62 | f D(v p, v& n) { 63 | 64 | // initialize our distance query 65 | q h(p); 66 | 67 | // encode "mattz" as bytecodes 68 | i d[] = { 69 | 1078091840, 70 | 612515908, 71 | -477289338, 72 | -2125832120, 73 | 1117152041, 74 | 1663926606, 75 | 1613841054, 76 | 1618043697, 77 | 0 78 | }; 79 | 80 | // interpret bytecodes by calling S() and C() with the appropriate 81 | // parameters 82 | for (u* c=(u*)d;*c;c+=2) { 83 | i o=c[0]>>5, a=c[1]>>5; // o: opcode in 0..7, a: arguments in 0..7 84 | f x=c[0]&31, y=c[1]&31, r=M_PI; // x,y are position in 0..31 85 | (o<4) ? S(x,y,a*(o&1),a*(o&2)/2,h) : 86 | (o&4) ? C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h) : 0; 87 | 88 | } 89 | 90 | P(v(0,0,1),h); 91 | P(v(0,1,0),h); 92 | 93 | // if we were asked for a normal, spit it out 94 | n=!(p-h.c); 95 | 96 | // return the distance 97 | return h.d-.45; 98 | 99 | } 100 | 101 | // do our raytracing from ray origin o in direction d 102 | f T(v o, v d) { 103 | 104 | ////////////////////////////////////////////////// 105 | // first do the sphere tracing for letters 106 | 107 | f u=0, l=0; // u is dist along ray, l is dist to obj 108 | v n; 109 | 110 | while (u<50) 111 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 112 | // do ambient occlusion pass 113 | f c=0, a=1, s=pow(U(n%!(L-d)),40); 114 | o=o+d*u; 115 | while (++c<6) { 116 | a -= .8*(.2*c-D(o+n*.2*c,d))/pow(2,c); 117 | } 118 | return ((.3*U(n%L)+.65)*(1-s)+s)*a; 119 | } 120 | 121 | ////////////////////////////////////////////////// 122 | 123 | return 0; 124 | 125 | } 126 | 127 | i main() { 128 | v o(10,2,30); // camera 129 | i w=720, h=270, x, y=-1; 130 | //i w=240, h=90, x, y=-1; 131 | //i w=360, h=135, x, y=-1; 132 | f s=24.0/w, t; // disp on pixel plane 133 | printf("P5 %d %d 255\n", w, h); 134 | while (++y 2 | #include 3 | #include 4 | #define O operator 5 | #define E return 6 | 7 | typedef int i; 8 | typedef float f; 9 | typedef unsigned char u; 10 | 11 | // vector struct 12 | struct v { 13 | f x,y,z; 14 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 15 | v operator*(f s) { return v(x*s,y*s,z*s); } 16 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 17 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 18 | v operator-(v r) { return *this+r*-1; } 19 | v operator!() { return *this*(1/~(*this)); } 20 | f operator~() { return sqrt(*this%*this); } 21 | //v operator^(v r) { return v(y*r.z-z*r.y,x*r.z-z*r.x,x*r.y-y*r.x); } 22 | } L(!v(-1,1,2)), W(1,1,1), B; 23 | 24 | // hit query struct for successive distance queries 25 | struct q { 26 | 27 | v p, c; // p: world point and c: closest in geometry 28 | f d; // d: distance from p to c 29 | 30 | // construct with large distance 31 | q(v P): p(P), d(9e9) {} 32 | 33 | // see if new point n is closer to p than current point c 34 | // and modify distances if so 35 | i operator()(v n) { 36 | f e= ~(p-n); 37 | if (e1?1:a; } 43 | 44 | // test distance from point h.p to a circular arc centered at point x, 45 | // y, (z=0) with radius r and angle range given by a & b 46 | i C(f x, f y, f r, f a, f b, q& h) { 47 | f t = atan2(h.p.y-y,h.p.x-x); 48 | t = tb?b:t; 49 | h(v(x+r*cos(t),y+r*sin(t))); 50 | } 51 | 52 | // test distance from point h.p to a line segment going from (x,y) to 53 | // (x+s,y+t) (z=0). 54 | i S(f x,f y,f s,f t,q& h) { 55 | v a(x,y), d(s,t); 56 | f u=(h.p-a)%d/(d%d); 57 | h(a+d*U(u)); 58 | } 59 | 60 | i P(v n, q& h) { h(h.p-n*(h.p%n+.9)); } 61 | 62 | // test distance from point p to the text "mattz" 63 | f D(v p, v& n) { 64 | 65 | // initialize our distance query 66 | q h(p); 67 | 68 | // encode "mattz" as bytecodes 69 | i d[] = { 70 | 1078091840, 71 | 612515908, 72 | -477289338, 73 | -2125832120, 74 | 1117152041, 75 | 1663926606, 76 | 1613841054, 77 | 1618043697, 78 | 0 79 | }; 80 | 81 | // interpret bytecodes by calling S() and C() with the appropriate 82 | // parameters 83 | for (u* c=(u*)d;*c;c+=2) { 84 | i o=c[0]>>5, a=c[1]>>5; // o: opcode in 0..7, a: arguments in 0..7 85 | f x=c[0]&31, y=c[1]&31, r=M_PI; // x,y are position in 0..31 86 | (o<4) ? S(x,y,a*(o&1),a*(o&2)/2,h) : 87 | (o&4) ? C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h) : 0; 88 | 89 | } 90 | 91 | P(v(0,0,1),h); 92 | P(v(0,1,0),h); 93 | 94 | // if we were asked for a normal, spit it out 95 | n=!(p-h.c); 96 | 97 | // return the distance 98 | return h.d-.45; 99 | 100 | } 101 | 102 | // do our raytracing from ray origin o in direction d 103 | f T(v o, v d) { 104 | 105 | ////////////////////////////////////////////////// 106 | // first do the sphere tracing for letters 107 | 108 | f u=0, l=0; // u is dist along ray, l is dist to obj 109 | v n; 110 | 111 | while (u<50) 112 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 113 | // do ambient occlusion pass 114 | f c=0, a=1, s=pow(U(n%!(L-d)),40); 115 | o=o+d*u; 116 | while (++c<6) { 117 | a -= .8*(.2*c-D(o+n*.2*c,d))/pow(2,c); 118 | } 119 | return ((.3*U(n%L)+.65)*(1-s)+s)*a; 120 | } 121 | 122 | ////////////////////////////////////////////////// 123 | 124 | return 0; 125 | 126 | } 127 | 128 | 129 | i main() { 130 | v c(-2,4,25), z(c-v(8.25,2)), x=!v(5,0,2), y=!v(-2,73,.5); 131 | //v c(-2,4,25), z(c-v(8.25,2)), x=v(0,1)^z, y=x^z; 132 | //fprintf(stderr, "x=%f,%f,%f\n", x.x, x.y, x.z); x=!x; 133 | //fprintf(stderr, "y=%f,%f,%f\n", y.x, y.y, y.z); y=!y; 134 | i w=600, h=220, s, t=-1; 135 | //i w=300, h=110, s, t=-1; 136 | f p=20.0/w; 137 | printf("P5 %d %d 255\n", w, h); 138 | while (++t 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | typedef float f; 7 | 8 | // vector struct 9 | struct v { 10 | f x,y,z; 11 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 12 | v operator*(f s) { return v(x*s,y*s,z*s); } 13 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 14 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 15 | v operator-(v r) { return *this+r*-1; } 16 | v operator!() { return *this*(1/~(*this)); } 17 | f operator~() { return sqrt(*this%*this); } 18 | //v operator^(v r) { return v(y*r.z-z*r.y,x*r.z-z*r.x,x*r.y-y*r.x); } 19 | } L(!v(-1,1,2)); 20 | 21 | typedef unsigned char u; 22 | typedef int i; 23 | 24 | // hit query struct for successive distance queries 25 | struct q: v { 26 | 27 | // *this stores point being queried 28 | v c; // c: closest in geometry 29 | f d; // d: distance from p to c 30 | 31 | // construct with large distance 32 | q(v P): v(P), d(99) {} 33 | 34 | // see if new point n is closer to p than current point c 35 | // and modify distances if so 36 | i operator()(v n) { 37 | f e= ~(*this-n); 38 | if (e1?1:a; } 44 | 45 | // test distance from point h to a circular arc centered at point x, 46 | // y, (z=0) with radius r and angle range given by a & b 47 | i C(f x, f y, f r, f a, f b, q& h) { 48 | f t = atan2(h.y-y,h.x-x); 49 | t = tb?b:t; 50 | h(v(x+r*cos(t),y+r*sin(t))); 51 | } 52 | 53 | // test distance from point h to a line segment going from (x,y) to 54 | // (x+s,y+t) (z=0). 55 | i S(f x,f y,f s,f t,q& h) { 56 | v a(x,y), d(s,t); 57 | f u=(h-a)%d/(d%d); 58 | h(a+d*U(u)); 59 | } 60 | 61 | i P(v n, q& h) { h(h-n*(h%n+.9)); } 62 | 63 | // test distance from point p to the text "mattz" 64 | f D(v p, v& n) { 65 | 66 | // initialize our distance query 67 | q h(p); 68 | 69 | // encode "mattz" as bytecodes 70 | u d[] = "@`B@D@\x82$\x86$\x8d\xe3H`J\x81)c\x96""BN\x81-c\x9e""B1`1cq`"; 71 | 72 | // interpret bytecodes by calling S() and C() with the appropriate 73 | // parameters 74 | for (u* c=d;*c;c+=2) { 75 | i o=c[0]>>5, a=c[1]>>5; // o: opcode in 0..7, a: arguments in 0..7 76 | f x=c[0]&31, y=c[1]&31, r=M_PI; // x,y are position in 0..31 77 | (o<4) ? S(x,y,a*(o&1),a*(o&2)/2,h) : 78 | C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h); 79 | } 80 | 81 | P(v(0,0,1),h); 82 | P(v(0,1),h); 83 | 84 | // if we were asked for a normal, spit it out 85 | n=!(p-h.c); 86 | 87 | // return the distance 88 | return h.d-.45; 89 | 90 | } 91 | 92 | // do our raytracing from ray origin o in direction d 93 | f T(v o, v d) { 94 | 95 | ////////////////////////////////////////////////// 96 | // first do the sphere tracing for letters 97 | 98 | f u=0, l=0; // u is dist along ray, l is dist to obj 99 | v n; 100 | 101 | while (u<50) 102 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 103 | // do ambient occlusion pass 104 | f c=0, a=1, s=pow(U(n%!(L-d)),80); 105 | o=o+d*u; 106 | while (++c<6) { 107 | a -= .8*(.2*c-D(o+n*.2*c,d))/pow(2,c); 108 | } 109 | return ((.3*U(n%L)+.65)*(1-s)+s)*a; 110 | } 111 | 112 | ////////////////////////////////////////////////// 113 | 114 | return 0; 115 | 116 | } 117 | 118 | 119 | i main() { 120 | //v c(-2,4,25), z(c-v(8.25,2)), x=v(0,1)^z, y=x^z; 121 | //fprintf(stderr, "x=%f,%f,%f\n", x.x, x.y, x.z); x=!x; 122 | //fprintf(stderr, "y=%f,%f,%f\n", y.x, y.y, y.z); y=!y; 123 | i t=-1; 124 | puts("P5 600 220 255"); 125 | while (++t<220) 126 | for (i s=0;s<600;++s) { 127 | putchar(255*T(v(-2,4,25), 128 | !(!v(5,0,2)*(s-300)*.034 - 129 | !v(-2,73)*(t-110)*.034 + 130 | v(10.25,-2,-25)))); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/miniray_1.4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | typedef float f; 7 | 8 | // vector struct 9 | struct v { 10 | f x,y,z; 11 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 12 | v operator*(f s) { return v(x*s,y*s,z*s); } 13 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 14 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 15 | v operator-(v r) { return *this+r*-1; } 16 | v operator!() { return *this*(1/~*this); } 17 | f operator~() { return sqrt(*this%*this); } 18 | //v operator^(v r) { return v(y*r.z-z*r.y,x*r.z-z*r.x,x*r.y-y*r.x); } 19 | } L(!v(-1,1,2)); 20 | 21 | typedef unsigned char u; 22 | typedef int i; 23 | 24 | // hit query struct for successive distance queries 25 | struct q: v { 26 | 27 | // *this stores point being queried 28 | v c; // c: closest in geometry 29 | f d; // d: distance from p to c 30 | 31 | // construct with large distance 32 | q(v P): v(P), d(99) {} 33 | 34 | // see if new point n is closer to p than current point c 35 | // and modify distances if so 36 | i operator()(v n) { 37 | f e= ~(*this-n); 38 | if (e1?1:a; } 44 | 45 | // test distance from point h to a circular arc centered at point x, 46 | // y, (z=0) with radius r and angle range given by a & b 47 | //i C(f x, f y, f r, f a, f b, q& h) { 48 | // f t = atan2(h.y-y,h.x-x); 49 | // t = tb?b:t; 50 | // h(v(x+r*cos(t),y+r*sin(t))); 51 | //} 52 | 53 | // test distance from point h to a line segment going from (x,y) to 54 | // (x+s,y+t) (z=0). 55 | //i S(f x,f y,f s,f t,q& h) { 56 | //v a(x,y), d(s,t); 57 | // h(a+d*U((h-a)%d/(d%d))); 58 | //} 59 | 60 | //i P(v n, q& h) { h(h-n*(h%n+.9)); } 61 | 62 | // test distance from point p to the text "mattz" 63 | f D(v p, v& n) { 64 | 65 | // initialize our distance query 66 | q h(p); 67 | 68 | // encode "mattz" as bytecodes 69 | u d[] = "`@@B@D$\x82$\x86\xe3\x8d`H\x81Jc)B\x96\x81Nc-B\x9e`1c1`q"; 70 | 71 | // interpret bytecodes by calling S() and C() with the appropriate 72 | // parameters 73 | for (u* c=d;*c;c+=2) { 74 | i o=c[1]>>5, a=*c>>5; // o: opcode in 0..7, a: arguments in 0..7 75 | f x=c[1]&31, y=*c&31; // x,y are position in 0..31 76 | //(o<4) ? S(x,y,a*(o&1),a*(o&2)/2,h) : 77 | //C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h); 78 | if (o<4) { 79 | v k(x,y), d(a*(o&1),a*(o&2)/2); 80 | h(k+d*U((h-k)%d/(d%d))); 81 | } else { 82 | f P=M_PI, l=-P*(a&2)/2, u=P*(a&1), 83 | r=1+.5*(a/4), t=atan2(h.y-y/2,h.x-x/2); 84 | t = tu?u:t; 85 | h(v(x/2+r*cos(t),y/2+r*sin(t))); 86 | //C(x/2,y/2,1+.5*(a/4),-r*(a&2)/2,r*(a&1),h); 87 | } 88 | } 89 | 90 | n=v(0,0,1); h(h-n*(h%n+.9)); 91 | n=v(0,1); h(h-n*(h%n+.9)); 92 | 93 | //P(v(0,0,1),h); 94 | //P(v(0,1),h); 95 | 96 | // spit out the normal 97 | n=!(p-h.c); 98 | 99 | // return the distance 100 | return h.d-.45; 101 | 102 | } 103 | 104 | // do our raytracing from ray origin o in direction d 105 | f T(v o, v d) { 106 | 107 | ////////////////////////////////////////////////// 108 | // first do the sphere tracing for letters 109 | 110 | f u=0, l=0; // u is dist along ray, l is dist to obj 111 | v n; 112 | 113 | while (u<50) 114 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 115 | // do ambient occlusion pass 116 | f c=0, a=1, s=pow(U(n%!(L-d)),80); 117 | o=o+d*u; 118 | while (++c<6) 119 | a -= .8*(.2*c-D(o+n*.2*c,d))/pow(2,c); 120 | return ((.3*U(n%L)+.65)*(1-s)+s)*a; 121 | } 122 | 123 | ////////////////////////////////////////////////// 124 | 125 | return 0; 126 | 127 | } 128 | 129 | 130 | i main() { 131 | //v c(-2,4,25), z(c-v(8.25,2)), x=v(0,1)^z, y=x^z; 132 | //fprintf(stderr, "x=%f,%f,%f\n", x.x, x.y, x.z); x=!x; 133 | //fprintf(stderr, "y=%f,%f,%f\n", y.x, y.y, y.z); y=!y; 134 | i t=-111; 135 | puts("P5 600 220 255"); 136 | while (++t<110) 137 | for (i s=-300;s<300;++s) { 138 | putchar(255*T(v(-2,4,25), 139 | !((!v(5,0,2)*s - 140 | !v(-2,73)*t)*.034 + 141 | v(10.25,-2,-25)))); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/miniray_1.4_commented.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // This is the "verbose" version of an obfuscated business card 3 | // sized raytracer. 4 | // 5 | // Compile this with full optimization and pipe the output to a file 6 | // named "mattz.pgm" 7 | 8 | #include 9 | #include 10 | #define O operator 11 | #define E return 12 | 13 | // Start by saving some space: 14 | typedef float f; 15 | typedef unsigned char u; 16 | typedef int i; 17 | 18 | ////////////////////////////////////////////////////////////////////// 19 | // A basic vector class. Note all vector operations are overloaded 20 | // single character operators -- no "named" methods. Thanks, Bjarne! 21 | 22 | struct v { 23 | 24 | // Just hold x,y,z. 25 | f x,y,z; 26 | 27 | // Construct with 1, 2, or 3 elements 28 | v (f a=0, f b=0, f c=0): x(a),y(b),z(c) {} 29 | 30 | // Multiplication by scalar. 31 | v operator*(f s) { return v(x*s,y*s,z*s); } 32 | 33 | // Dot product 34 | f operator%(v r) { return x*r.x+y*r.y+z*r.z; } 35 | 36 | // Vector addition 37 | v operator+(v r) { return v(x+r.x,y+r.y,z+r.z); } 38 | 39 | // Vector subtraction (defined in terms of multiplication by -1 and 40 | // addition to save space). 41 | v operator-(v r) { return *this+r*-1; } 42 | 43 | // Return a normalized version of this vector. 44 | v operator!() { return *this*(1/~*this); } 45 | 46 | // Return the length of this vector. 47 | f operator~() { return sqrt(*this%*this); } 48 | 49 | } 50 | 51 | // The vector L holds the light direction in world space. Yes, you 52 | // can declare a variable in the same statement as a class 53 | // declaration. 54 | L(!v(-1,1,2)); 55 | 56 | 57 | ////////////////////////////////////////////////////////////////////// 58 | // A structure for distance queries that derives from the vector 59 | // class. Given an arbitrary point in the world, store the closest 60 | // point in the scene geometry, along with the distance from world 61 | // point to scene point. This structure is updated several times 62 | // as we test distances to various scene primitives. 63 | // 64 | // The underlying vector (base class) stores the arbitrary world 65 | // point. 66 | 67 | struct q: v { 68 | 69 | // Closest point in scene geometry 70 | v c; 71 | 72 | // Distance from world point to scene point 73 | f d; 74 | 75 | // Construct with a sufficiently large distance. 76 | q(v P): v(P), d(99) {} 77 | 78 | // Check to see if point n in the scene geometry is closer than 79 | // current closest point c. If so, set c and d. 80 | // 81 | // It's fewer characters to return an int than a void, so we take 82 | // the hit and don't return anything from this method (generates 83 | // a warning in g++, oh well). 84 | i operator()(v n) { 85 | f e= ~(*this-n); 86 | if (e1?1:a; } 95 | 96 | ////////////////////////////////////////////////////////////////////// 97 | // Test the distance from the point p to the scene, and store the 98 | // scene normal (normalized difference between p and closest point in 99 | // the scene) in n. 100 | 101 | f D(v p, v& n) { 102 | 103 | // Initialize our distance query h. 104 | q h(p); 105 | 106 | // Encode the letters "mattz", see below for explanation: 107 | u d[] = "`@@B@D$\x82$\x86\xe3\x8d`H\x81Jc)B\x96\x81Nc-B\x9e`1c1`q"; 108 | 109 | // Interpret bytecodes by iterating over d in 2-byte chunks. 110 | for (u* c=d;*c;c+=2) { 111 | 112 | // Extract o, a, x, y from the current two bytes: 113 | // 114 | // o is a 3-bit opcode that stores the current geometry type 115 | // (line segment or arc) 116 | // 117 | // a is a 3-bit argument whose interpretation depends on whether 118 | // we are a line segment or arc 119 | // 120 | // x and y are 5-bit scene coordinates. 121 | // 122 | i o=c[1]>>5, a=*c>>5; 123 | f x=c[1]&31, y=*c&31; 124 | 125 | // Check if the high bit of o is set. 126 | 127 | if (o<4) { // High bit not set. 128 | 129 | // The current primitive is a line segment extending 130 | // from (x,y) to (x+dx, y+dy), where: 131 | // 132 | // dx = a if the low bit of o is set, otherwise zero. 133 | // 134 | // dy = a if the middle bit of o is set, otherwise zero. 135 | // 136 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 137 | // 138 | v k(x,y), d(a*(o&1),a*(o&2)/2); 139 | 140 | // Compute the closest point along the line segment and 141 | // feed it to the distance query. 142 | h(k+d*U((h-k)%d/(d%d))); 143 | 144 | } else { // High bit is set. 145 | 146 | // The current primitive is an arc centered around 147 | // (x,y) with starting angle l, ending angle u, 148 | // and radius r, where 149 | // 150 | // l = -M_PI if the middle bit of a is set, otherwise 0. 151 | // 152 | // u = M_PI if the low bit of a is set, otherwise 0. 153 | // 154 | // r = 1.5 if the high bit of a is set, otherwise 1. 155 | // 156 | // Also compute t, the angle of the point p with respect to the 157 | // arc's center. 158 | // 159 | f P=M_PI, l=-P*(a&2)/2, u=P*(a&1), 160 | r=1+.5*(a/4), t=atan2(h.y-y/2,h.x-x/2); 161 | 162 | // Clamp t to the range given. 163 | t = tu?u:t; 164 | 165 | // Compute the point along the arc closest to p (just given by 166 | // the angle t and radius r), and feed it to the distance query. 167 | h(v(x/2+r*cos(t),y/2+r*sin(t))); 168 | 169 | } // Done with current primitive 170 | 171 | } // Looping through primitives 172 | 173 | // Find the projections of point p onto the wall and floor planes, 174 | // and feed them to the distance query. 175 | n=v(0,0,1); h(h-n*(h%n+.9)); 176 | n=v(0,1); h(h-n*(h%n+.9)); 177 | 178 | // Compute the normal n. 179 | n=!(p-h.c); 180 | 181 | // Return the distance -- we subtract off a radius of .45 to give 182 | // everything some dimension (otherwise all primitives would be 183 | // infinitely thin and we would just see the planes). 184 | return h.d-.45; 185 | 186 | } 187 | 188 | ////////////////////////////////////////////////////////////////////// 189 | // Trace a ray from origin o along direction d, and return the scene 190 | // brightness at the intersection. Instead of analytic ray tracing, 191 | // this is actually "sphere tracing" by using the distance to closest 192 | // point in scene to lower-bound how far we can step along the ray. 193 | 194 | f T(v o, v d) { 195 | 196 | // u holds the distance along the ray, l holds the distance to 197 | // closest object. 198 | f u=0, l=0; 199 | 200 | // n holds the normal (normalized difference of ray point minus 201 | // closest scene point). 202 | v n; 203 | 204 | // March along the ray: 205 | while (u<50) 206 | 207 | // Get the distance D from the ray point to the scene geometry. 208 | // If it is less than a threshold, then we have intersected the scene, 209 | // otherwise increase the distance along the ray by most of l: 210 | if (fabs(l=D(o+d*(u+=.9*l),n))<1e-4){ 211 | 212 | // Ok, we have intersected. It's time to compute lighting and 213 | // ambient occlusion now. At this point it would be instructive 214 | // to look at the linked PDF here: 215 | // 216 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 217 | // 218 | // Basically, we're going to use the distance function D to get an 219 | // idea of how much "clutter" there is as we march away from the 220 | // intersecting point along the normal n. 221 | // 222 | // Our variables: 223 | // 224 | // c is just a counter that counts steps along the normal. 225 | // 226 | // a is going to track our ambient occlusion (lower value = 227 | // more occluded) 228 | // 229 | // s is the specular contribution (Phong shading model). 230 | // 231 | f c=0, a=1, s=pow(U(n%!(L-d)),80); 232 | 233 | // We reset o to be the point of intersection instead of the ray 234 | // origin from here on out. Also, we're clobbering d in the call 235 | // to D below. 236 | o=o+d*u; 237 | 238 | // Take 5 steps along the normal: 239 | while (++c<6) 240 | 241 | // OK, we are comparing two distances here: 242 | // 243 | // .2*c is the distance along the normal from the point of 244 | // intersection. 245 | // 246 | // The D(...) subexpression is the distance to closest point 247 | // in the scene. 248 | // 249 | // If the point of intersection was the closest thing, then 250 | // the difference below should be zero and there is no 251 | // occlusion happening. 252 | // 253 | // However, if there's non-convex geometry in that region, the 254 | // D(...) thing will be less than the .2*c thing and we end up 255 | // contributing to a. Each time we take a step along the 256 | // normal, we reduce the "importance" of the AO computation by 257 | // a factor of 2 (occlusion at larger distances matter 258 | // exponentially less). 259 | // 260 | a -= .8*(.2*c-D(o+n*.2*c,d))/pow(2,c); 261 | 262 | // Do the lighting and modulate the entire lighting computation by a: 263 | // 264 | // Inside the parentheses: 265 | // 266 | // Basically if s is zero, we are totally lambertian with a minimum 267 | // brightness of .65 and a maximum brightness of 0.95 268 | // 269 | // If s is one, then we are totally white. 270 | // 271 | // We use the specular contribution to modulate between 272 | // lambertian and total whiteness. 273 | // 274 | return ((.3*U(n%L)+.65)*(1-s)+s)*a; 275 | 276 | } // End marching along the ray 277 | 278 | // The ray missed the scene entirely (shouldn't happen), so return 279 | // zero brightness. Probably could just remove this statement 280 | // and pick up another warning. 281 | return 0; 282 | 283 | } 284 | 285 | ////////////////////////////////////////////////////////////////////// 286 | // Main function just prints a header and iterates through the image 287 | // pixels. 288 | 289 | i main() { 290 | 291 | // Output the portable graymap header (binary version). 292 | puts("P5 600 220 255"); // * size encoded into the string 293 | 294 | i t=-111; // * t holds the vertical pixel coord. 295 | 296 | while (++t<110) // * 297 | 298 | for (i s=-300;s<300;++s) { // * s holds the horiz. coord. 299 | 300 | // Get the brightness of the pixel as a float in 0,1 and output 301 | // the character. View transformation? Never heard of it. Naw, 302 | // let's just directly encode our camera position and viewing 303 | // direction as inline variables. 304 | // 305 | // If you wanted to resize the output image, you'd have to change 306 | // all the marked lines (*) to get the output to scale uniformly. 307 | putchar(255*T(v(-2,4,25), 308 | !((!v(5,0,2)*s - 309 | !v(-2,73)*t)*.034 + // * .034 is a pixel scaling factor 310 | v(10.25,-2,-25)))); 311 | } 312 | 313 | // If we were good citizens, we'd return something here. Oh well. 314 | 315 | } 316 | -------------------------------------------------------------------------------- /src/miniray_2.0.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // This is the "verbose" version of an obfuscated business card 3 | // sized raytracer. 4 | // 5 | // Compile this with full optimization and pipe the output to a file 6 | // named "mattz.pgm" 7 | 8 | #include 9 | #include 10 | 11 | // Start by saving some space: 12 | #define O operator 13 | #define E return 14 | 15 | typedef float f; 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | // A basic vector class. Note all vector operations are overloaded 19 | // single character operators -- no "named" methods. Thanks, Bjarne! 20 | 21 | struct v { 22 | 23 | // Just hold x,y,z. 24 | f x, y, z; 25 | 26 | // Construct with 1, 2, or 3 elements 27 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 28 | 29 | // Multiplication by scalar. 30 | v operator*(f s) { return v(x*s, y*s, z*s); } 31 | 32 | // Dot product 33 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 34 | 35 | // Return a normalized version of this vector. 36 | v operator!() { return *this*(1/sqrt(*this%*this)); } 37 | 38 | // Vector addition 39 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 40 | 41 | // Vector subtraction (defined in terms of multiplication by -1 and 42 | // addition to save space). 43 | v operator-(v r) { return *this+r*-1; } 44 | 45 | 46 | } 47 | 48 | // The vector L holds the light direction in world space. Defining it 49 | // right after the class declaration saves us a character or two later 50 | // on. 51 | L(!v(-1,1,2)); 52 | 53 | ////////////////////////////////////////////////////////////////////// 54 | // Clamp any float to the [0,1] unit interval. 55 | 56 | f U(f a) { return a<0?0:a>1?1:a; } 57 | 58 | ////////////////////////////////////////////////////////////////////// 59 | // A helper function for distance queries. The scene is broken up into 60 | // a number of primitives. For some point p, we cycle through all the 61 | // primitives to see which one is closest to p, and this function is 62 | // called once per primitive. Variables in this function: 63 | // 64 | // n: the nearest point on the current primitive to p 65 | // j: the "color" of the current primitive 66 | // 67 | // c: the closest point to p on any primitive found so far 68 | // d: the distance between p and c 69 | // m: the "color" of the closest primitive identified so far 70 | // 71 | // The implementation is dead simple: if the distance between p and n 72 | // is less than d, we simply update c, d, and m. 73 | 74 | f Q(v p, v n, v& c, f& d, f& m, f j=1) { 75 | 76 | f e = sqrt((p-n)%(p-n)); 77 | 78 | if (e>5, a=*c>>5; 115 | f x=c[1]&31, y=*c&31; 116 | 117 | if (o>3) { // High bit is set 118 | 119 | // The current primitive is an arc centered around 120 | // (x,y) with starting angle l, ending angle u, 121 | // and radius r, where 122 | // 123 | // l = -M_PI if the middle bit of a is set, otherwise 0. 124 | // 125 | // u = M_PI if the low bit of a is set, otherwise 0. 126 | // 127 | // r = 1.5 if the high bit of a is set, otherwise 1. 128 | // 129 | // Also compute t, the angle of the point p with respect to the 130 | // arc's center. 131 | // 132 | f r=.5*(a/4)+1, t=atan2(p.y-y/2,p.x-x/2), 133 | P=M_PI, l=-P*(a&2)/2, u=P*(a&1); 134 | 135 | // Clamp t to the range given. 136 | t = tu?u:t; 137 | 138 | // Compute the point along the arc closest to p (just given by 139 | // the angle t and radius r), and feed it to the distance query. 140 | Q(p,v(r*cos(t)+x/2,r*sin(t)+y/2),C,D,m,.7); 141 | 142 | } else { // High bit not set 143 | 144 | // The current primitive is a line segment extending 145 | // from (x,y) to (x+dx, y+dy), where: 146 | // 147 | // dx = a if the low bit of o is set, otherwise zero. 148 | // 149 | // dy = a if the middle bit of o is set, otherwise zero. 150 | // 151 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 152 | // 153 | v k(x,y), d(a*(o&1),a*(o&2)/2); 154 | 155 | // Compute the closest point along the line segment and 156 | // feed it to the distance query. 157 | Q(p,k+d*U((p-k)%d/(d%d)),C,D,m,.7); 158 | 159 | } // Done with current primitive 160 | 161 | } // Looping though primitives 162 | 163 | // Find the projections of point p onto the wall and floor planes, 164 | // and feed them to the distance query. 165 | n=v(0,1); Q(p,p-n*(p%n+.9),C,D,m); 166 | n=v(0,0,1); Q(p,p-n*(p%n+.9),C,D,m); 167 | 168 | // Compute the normal n. 169 | n=!(p-C); 170 | 171 | // Return the distance -- we subtract off a radius of .45 to give 172 | // everything some dimension (otherwise all primitives would be 173 | // infinitely thin and we would only see the planes). 174 | return D-.45; 175 | 176 | } 177 | 178 | ////////////////////////////////////////////////////////////////////// 179 | // Trace a ray from origin o along direction d, and return the scene 180 | // brightness at the intersection. Instead of analytic ray tracing, 181 | // this is actually "sphere tracing" by using the distance to closest 182 | // point in scene to lower-bound how far we can step along the ray. 183 | // Returns the scene color at the point of intersection. 184 | 185 | v T(v o, v d) { 186 | 187 | // Some local variables: 188 | // u: distance along the ray 189 | // l: distance to closest object at u 190 | // m: primitive "color" 191 | // c: a counter 192 | // a: ambient occlusion parameter 193 | // 194 | f u=0, l=0, m=0, c=0, a=1; 195 | 196 | // n holds the normal returned by the distance query above 197 | v n; 198 | 199 | // March along the ray: 200 | while (u<50) 201 | 202 | // Get the distance D from the ray point to the scene geometry. 203 | // If it is less than a threshold, then we have intersected the scene, 204 | // otherwise increase the distance along the ray by most of l: 205 | if (fabs(l=D(o+d*(u+=l),n,m))<1e-4){ 206 | 207 | // Ok, we have intersected! Now compute lighting, which consists 208 | // of three terms: a Lambertian term, a specular term, and ambient 209 | // occlusion. 210 | 211 | // s is specular lighting component 212 | f s=pow(U(n%!(L-d)),80),w; 213 | 214 | // update o to put it at the point of intersection 215 | o=o+d*u; 216 | 217 | // It's time to compute ambient occlusion now. At this point it 218 | // would be instructive to look at the linked PDF here: 219 | // 220 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 221 | // 222 | // Basically, we're going to use the distance function D to get an 223 | // idea of how much "clutter" there is as we march away from the 224 | // intersecting point along the normal n. 225 | // 226 | // Take 5 steps along the normal: 227 | // 228 | while (++c<6) 229 | 230 | // OK, we are comparing two distances here: 231 | // 232 | // .2*c is the distance along the normal from the point of 233 | // intersection. 234 | // 235 | // The D(...) subexpression is the distance to closest point 236 | // in the scene. 237 | // 238 | // If the point of intersection was the closest thing, then 239 | // the difference below should be zero and there is no 240 | // occlusion happening. 241 | // 242 | // However, if there's non-convex geometry in that region, the 243 | // D(...) thing will be less than the .2*c thing and we end up 244 | // contributing to a. Each time we take a step along the 245 | // normal, we reduce the "importance" of the AO computation by 246 | // a factor of 2 (occlusion at larger distances matter 247 | // exponentially less). 248 | // 249 | a -= (c/5-D(o+n*.2*c,d,w))/pow(2,c); 250 | 251 | // Do all the lighting now: 252 | // 253 | // v(m,m,1) is the color (white or blue) 254 | // 255 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 256 | // ambient, and modulates the color. 257 | // 258 | // So then we take the modulated color, and use the specular 259 | // term to linearly interpolate between that and white 260 | // (totally fake specular lighting). 261 | // 262 | // Finally we take that entire thing and darken it up with 263 | // the ambient occlusion term that we computed above. 264 | // 265 | return (v(m,m,1)*(U(n%L)/3+.65)*(1-s) + v(1,1,1)*s)*a; 266 | 267 | } 268 | 269 | // Return values are overrated. 270 | 271 | } 272 | 273 | ////////////////////////////////////////////////////////////////////// 274 | // Main function just prints a header and iterates through the image 275 | // pixels. 276 | 277 | int main() { 278 | 279 | 280 | // t holds the vertical pixel coordinate 281 | f t=-111; 282 | 283 | // Output the portable pixmap header (binary version). 284 | puts("P6 600 220 255"); 285 | 286 | // For each row: 287 | while (++t<110) 288 | 289 | // For each column: 290 | // s holds the horizontal pixel coordinate 291 | for (f s=-300;s<300;++s) { 292 | 293 | // Get the color of the pixel as a float with components in 294 | // [0,1] and scale it into [0,255]. View transformation? Never 295 | // heard of it. Naw, let's just directly encode our camera 296 | // position and viewing direction as inline variables. 297 | // 298 | v c = T(v(-2,4,25), 299 | !((!v(5,0,2)*s - 300 | !v(-2,73)*t)*.034 + 301 | v(10.25,-2,-25)))*255; 302 | 303 | // Output each channel as a character. 304 | putchar(c.x); 305 | putchar(c.y); 306 | putchar(c.z); 307 | 308 | } // for each column 309 | 310 | } 311 | -------------------------------------------------------------------------------- /src/miniray_2.1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | ////////////////////////////////////////////////////////////////////// 7 | // This is the "verbose" version of an obfuscated business card 8 | // sized raytracer. 9 | // 10 | // Compile this with full optimization and pipe the output to a file 11 | // named "mattz.pgm" 12 | 13 | // Start by saving some space: 14 | typedef float f; 15 | 16 | ////////////////////////////////////////////////////////////////////// 17 | // A basic vector class. Note all vector operations are overloaded 18 | // single character operators -- no "named" methods. Thanks, Bjarne! 19 | 20 | struct v { 21 | 22 | // Just hold x,y,z. 23 | f x, y, z; 24 | 25 | // Construct with 1, 2, or 3 elements 26 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 27 | 28 | // Multiplication by scalar. 29 | v operator*(f s) { return v(x*s, y*s, z*s); } 30 | 31 | // Dot product 32 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 33 | 34 | // Return a normalized version of this vector. 35 | v operator!() { return *this*(1/sqrt(*this%*this)); } 36 | 37 | // Vector addition 38 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 39 | 40 | // Vector subtraction (defined in terms of multiplication by -1 and 41 | // addition to save space). 42 | v operator-(v r) { return *this+r*-1; } 43 | 44 | 45 | } 46 | 47 | // The vector L holds the light direction in world space. Defining it 48 | // right after the class declaration saves us a character or two later 49 | // on. 50 | L(!v(-1,1,2)); 51 | 52 | ////////////////////////////////////////////////////////////////////// 53 | // Clamp any float to the [0,1] unit interval. 54 | 55 | f U(f a) { return a<0?0:a>1?1:a; } 56 | 57 | ////////////////////////////////////////////////////////////////////// 58 | // A helper function for distance queries. The scene is broken up into 59 | // a number of primitives. For some point p, we cycle through all the 60 | // primitives to see which one is closest to p, and this function is 61 | // called once per primitive. Variables in this function: 62 | // 63 | // c: the closest point on the current primitive to p 64 | // m: the "material" of the current primitive 65 | // 66 | // C: the closest point to p on any primitive found so far 67 | // D: the distance between p and c 68 | // M: the "material" of the closest primitive identified so far 69 | // 70 | // The implementation is dead simple: if the distance between p and c 71 | // is less than D, we simply update C, D, and M. 72 | 73 | f Q(v p, v c, v& C, f& D, f& M, f m=1) { 74 | 75 | f d = sqrt((p-c)%(p-c)); 76 | 77 | if (d>5, a=*b>>5; 116 | f x=b[1]&31, y=*b&31; 117 | 118 | if (o>3) { // High bit is set 119 | 120 | // The current primitive is an arc centered around 121 | // (x,y) with starting angle l, ending angle u, 122 | // and radius r, where 123 | // 124 | // l = -M_PI if the middle bit of a is set, otherwise 0. 125 | // 126 | // u = M_PI if the low bit of a is set, otherwise 0. 127 | // 128 | // r = 1.5 if the high bit of a is set, otherwise 1. 129 | // 130 | // Also compute t, the angle of the point p with respect to the 131 | // arc's center. 132 | // 133 | f r=.5*(a/4)+1, t=atan2(p.y-y/2,p.x-x/2), 134 | P=M_PI, l=-P*(a&2)/2, u=P*(a&1); 135 | 136 | // Clamp t to the range given. 137 | t = tu?u:t; 138 | 139 | // Compute the point along the arc closest to p (just given by 140 | // the angle t and radius r), and feed it to the distance query. 141 | Q(p,v(r*cos(t)+x/2,r*sin(t)+y/2),C,D,M,.7); 142 | 143 | } else { // High bit not set 144 | 145 | // The current primitive is a line segment extending 146 | // from (x,y) to (x+dx, y+dy), where: 147 | // 148 | // dx = a if the low bit of o is set, otherwise zero. 149 | // 150 | // dy = a if the middle bit of o is set, otherwise zero. 151 | // 152 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 153 | // 154 | v k(x,y), d(a*(o&1),a*(o&2)/2); 155 | 156 | // Compute the closest point along the line segment and 157 | // feed it to the distance query. 158 | Q(p,k+d*U((p-k)%d/(d%d)),C,D,M,.7); 159 | 160 | } // Done with current primitive 161 | 162 | } // Looping though primitives 163 | 164 | // Find the projections of point p onto the wall and floor planes, 165 | // and feed them to the distance query. 166 | n=v(0,1); Q(p,p-n*(p%n+.9),C,D,M); 167 | n=v(0,0,1); Q(p,p-n*(p%n+.9),C,D,M); 168 | 169 | // Compute the normal n. 170 | n=!(p-C); 171 | 172 | // Return the distance -- we subtract off a radius of .45 to give 173 | // everything some dimension (otherwise all primitives would be 174 | // infinitely thin and we would only see the planes). 175 | return D-.45; 176 | 177 | } 178 | 179 | 180 | ////////////////////////////////////////////////////////////////////// 181 | // Main function just prints a header and iterates through the image 182 | // pixels. 183 | 184 | int main() { 185 | 186 | 187 | // y holds the vertical pixel coordinate 188 | f y=-111; 189 | 190 | // Output the portable pixmap header (binary version). 191 | puts("P6 600 220 255"); 192 | 193 | // For each row: 194 | while (++y<110) 195 | 196 | // For each column: 197 | // x holds the horizontal pixel coordinate 198 | for (f x=-300;x<300;++x) { 199 | 200 | // Trace a ray from origin o along direction d, and compute the 201 | // scene color at the intersection. Instead of analytic ray 202 | // tracing, this is actually "sphere tracing" by using the 203 | // distance to closest point in scene as a lower-bound of how 204 | // far we can step along the ray. 205 | 206 | // Vector variables: 207 | // 208 | // o is the ray origin 209 | // d is the ray direction, note hardcoded view transformation. 210 | // n is the normal at the point of intersection 211 | // p is the pixel color 212 | // 213 | v o(-2,4,25), 214 | d = !((!v(5,0,2)*x - 215 | !v(-2,73)*y)*.034 + 216 | v(10.25,-2,-25)), n, p; 217 | 218 | // Scalar variables: 219 | // 220 | // u: distance along the ray at current point 221 | // l: distance to closest object at current point 222 | // m: primitive "material" 223 | // i: a counter 224 | // a: ambient occlusion parameter 225 | // 226 | f u=0, l=0, m, i=0, a=1; 227 | 228 | // March along the ray: 229 | while (u<50) 230 | 231 | // Get the distance D from the current ray point to the scene 232 | // geometry. If it is less than a threshold, then we have 233 | // intersected the scene, otherwise increase the distance 234 | // along the ray by most of l: 235 | // 236 | if (fabs(l=D(o+d*(u+=l),n,m))<1e-4){ 237 | 238 | // Ok, we have intersected! Now compute lighting, which consists 239 | // of three terms: a Lambertian term, a specular term, and ambient 240 | // occlusion. 241 | 242 | // s is specular lighting component 243 | // w is ignored but needs to be passed into D above 244 | f s=pow(U(n%!(L-d)),80),w; 245 | 246 | // update o to put it at the point of intersection 247 | o=o+d*u; 248 | 249 | // It's time to compute ambient occlusion now. At this point it 250 | // would be instructive to look at the linked PDF here: 251 | // 252 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 253 | // 254 | // Basically, we're going to use the distance function D to get an 255 | // idea of how much "clutter" there is as we march away from the 256 | // intersecting point along the normal n. 257 | // 258 | // Take 5 steps along the normal: 259 | // 260 | while (++i<6) 261 | 262 | // OK, we are comparing two distances here: 263 | // 264 | // .2*i is the distance along the normal from the point of 265 | // intersection. 266 | // 267 | // The D(...) subexpression is the distance to closest point 268 | // in the scene. 269 | // 270 | // If the point of intersection was the closest thing, then 271 | // the difference below should be zero and there is no 272 | // occlusion happening. 273 | // 274 | // However, if there's non-convex geometry in that region, the 275 | // D(...) thing will be less than the .2*i thing and we end up 276 | // contributing to a. Each time we take a step along the 277 | // normal, we reduce the "importance" of the AO computation by 278 | // a factor of 2 (occlusion at larger distances matter 279 | // exponentially less). 280 | // 281 | a -= (i/5-D(o+n*.2*i,d,w))/pow(2,i); 282 | 283 | // Do all the lighting now: 284 | // 285 | // v(m,m,1) is the color (white or blue) 286 | // 287 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 288 | // ambient, and modulates the color. 289 | // 290 | // So then we take the modulated color, and use the specular 291 | // term to linearly interpolate between that and white 292 | // (totally fake specular lighting). 293 | // 294 | // Finally we take that entire thing and darken it up with 295 | // the ambient occlusion term that we computed above. 296 | // 297 | // Pixel color is multiplied by 255 to put it in unsigned 298 | // char range. 299 | // 300 | p = (v(m,m,1)*(U(n%L)/3+.65)*(1-s) + v(1,1,1)*s)*a*255; 301 | break; 302 | 303 | } 304 | 305 | // Output each channel of the pixel as a character. 306 | putchar(p.x); 307 | putchar(p.y); 308 | putchar(p.z); 309 | 310 | } // for each column 311 | // for each row 312 | 313 | } 314 | -------------------------------------------------------------------------------- /src/miniray_2.2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define O operator 4 | #define E return 5 | 6 | ////////////////////////////////////////////////////////////////////// 7 | // This is the "verbose" version of an obfuscated business card 8 | // sized raytracer. 9 | // 10 | // Compile this with full optimization and pipe the output to a file 11 | // named "mattz.pgm" 12 | 13 | // Start by saving some space: 14 | typedef float f; 15 | 16 | ////////////////////////////////////////////////////////////////////// 17 | // A basic vector class. Note all vector operations are overloaded 18 | // single character operators -- no "named" methods. Thanks, Bjarne! 19 | 20 | struct v { 21 | 22 | // Just hold x,y,z. 23 | f x, y, z; 24 | 25 | // Construct with 1, 2, or 3 elements 26 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 27 | 28 | // Multiplication by scalar. 29 | v operator*(f s) { return v(x*s, y*s, z*s); } 30 | 31 | // Dot product 32 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 33 | 34 | // Return a normalized version of this vector. 35 | v operator!() { return *this*(1/sqrt(*this%*this)); } 36 | 37 | // Vector addition 38 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 39 | 40 | // Vector subtraction (defined in terms of multiplication by -1 and 41 | // addition to save space). 42 | v operator-(v r) { return *this+r*-1; } 43 | 44 | 45 | } 46 | 47 | // The vector L holds the light direction in world space. Defining it 48 | // right after the class declaration saves us a character or two later 49 | // on. 50 | L(!v(-1,1,2)); 51 | 52 | ////////////////////////////////////////////////////////////////////// 53 | // Clamp any float to the [0,1] unit interval. 54 | 55 | f U(f a) { return a<0?0:a>1?1:a; } 56 | 57 | ////////////////////////////////////////////////////////////////////// 58 | // A helper function for distance queries. The scene is broken up into 59 | // a number of primitives. For some point p, we cycle through all the 60 | // primitives to see which one is closest to p, and this function is 61 | // called once per primitive. Variables in this function: 62 | // 63 | // c: the closest point on the current primitive to p 64 | // m: the "material" of the current primitive 65 | // 66 | // C: the closest point to p on any primitive found so far 67 | // D: the distance between p and c 68 | // M: the "material" of the closest primitive identified so far 69 | // 70 | // The implementation is dead simple: if the distance between p and c 71 | // is less than D, we simply update C, D, and M. 72 | 73 | f Q(v p, v c, v& C, f& D, f& M, f m=1) { 74 | 75 | f d = sqrt((p-c)%(p-c)); 76 | 77 | if (d>5, a=*b>>5; 116 | f x=b[1]&31, y=*b&31; 117 | 118 | if (o>3) { // High bit is set 119 | 120 | // The current primitive is an arc centered around 121 | // (x,y) with starting angle l, ending angle u, 122 | // and radius r, where 123 | // 124 | // l = -M_PI if the middle bit of a is set, otherwise 0. 125 | // 126 | // u = M_PI if the low bit of a is set, otherwise 0. 127 | // 128 | // r = 1.5 if the high bit of a is set, otherwise 1. 129 | // 130 | // Also compute t, the angle of the point p with respect to the 131 | // arc's center. 132 | // 133 | f r=.5*(a/4)+1, t=atan2(p.y-y/2,p.x-x/2), 134 | P=M_PI, l=-P*(a&2)/2, u=P*(a&1); 135 | 136 | // Clamp t to the range given. 137 | t = tu?u:t; 138 | 139 | // Compute the point along the arc closest to p (just given by 140 | // the angle t and radius r), and feed it to the distance query. 141 | Q(p,v(r*cos(t)+x/2,r*sin(t)+y/2),C,D,M,.7); 142 | 143 | } else { // High bit not set 144 | 145 | // The current primitive is a line segment extending 146 | // from (x,y) to (x+dx, y+dy), where: 147 | // 148 | // dx = a if the low bit of o is set, otherwise zero. 149 | // 150 | // dy = a if the middle bit of o is set, otherwise zero. 151 | // 152 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 153 | // 154 | v k(x,y), d(a*(o&1),a*(o&2)/2); 155 | 156 | // Compute the closest point along the line segment and 157 | // feed it to the distance query. 158 | Q(p,k+d*U((p-k)%d/(d%d)),C,D,M,.7); 159 | 160 | } // Done with current primitive 161 | 162 | } // Looping though primitives 163 | 164 | // Find the projections of point p onto the wall and floor planes, 165 | // and feed them to the distance query. 166 | n=v(0,1); Q(p,p-n*(p%n+.9),C,D,M); 167 | n=v(0,0,1); Q(p,p-n*(p%n+.9),C,D,M); 168 | 169 | // Compute the normal n. 170 | n=!(p-C); 171 | 172 | // Return the distance -- we subtract off a radius of .45 to give 173 | // everything some dimension (otherwise all primitives would be 174 | // infinitely thin and we would only see the planes). 175 | return D-.45; 176 | 177 | } 178 | 179 | 180 | ////////////////////////////////////////////////////////////////////// 181 | // Main function just prints a header and iterates through the image 182 | // pixels. 183 | 184 | int main() { 185 | 186 | 187 | // y holds the vertical pixel coordinate 188 | f y=-111; 189 | 190 | // Output the portable pixmap header (binary version). 191 | puts("P6 600 220 255"); 192 | 193 | // For each row: 194 | while (++y<110) 195 | 196 | // For each column: 197 | // x holds the horizontal pixel coordinate 198 | for (f x=-300;x<300;++x) { 199 | 200 | // Trace a ray from origin o along direction d, and compute the 201 | // scene color at the intersection. Instead of analytic ray 202 | // tracing, this is actually "sphere tracing" by using the 203 | // distance to closest point in scene as a lower-bound of how 204 | // far we can step along the ray. 205 | 206 | // Vector variables: 207 | // 208 | // o is the ray origin 209 | // d is the ray direction, note hardcoded view transformation. 210 | // n is the normal at the point of intersection 211 | // p is the pixel color 212 | // 213 | v o(-2,4,25), 214 | d = !((!v(5,0,2)*x - 215 | !v(-2,73)*y)*.034 + 216 | v(10.25,-2,-25)), n, p, L; 217 | 218 | // Scalar variables: 219 | // 220 | // u: distance along the ray at current point 221 | // l: distance to closest object at current point 222 | // m: primitive "material" 223 | // i: a counter 224 | // a: ambient occlusion parameter 225 | // 226 | f u=0, l=0, m, i=0, a=1; 227 | 228 | // March along the ray: 229 | while (u<50) 230 | 231 | // Get the distance D from the current ray point to the scene 232 | // geometry. If it is less than a threshold, then we have 233 | // intersected the scene, otherwise increase the distance 234 | // along the ray by most of l: 235 | // 236 | if (fabs(l=D(o+d*(u+=l),n,m))<1e-4){ 237 | 238 | // Ok, we have intersected! Now compute lighting, which consists 239 | // of three terms: a Lambertian term, a specular term, and ambient 240 | // occlusion. 241 | 242 | // s is specular lighting component 243 | // w is ignored but needs to be passed into D above 244 | f s=pow(U(n%!(L-d)),80),w; 245 | 246 | // update o to put it at the point of intersection 247 | o=o+d*u; 248 | 249 | // It's time to compute ambient occlusion now. At this point it 250 | // would be instructive to look at the linked PDF here: 251 | // 252 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 253 | // 254 | // Basically, we're going to use the distance function D to get an 255 | // idea of how much "clutter" there is as we march away from the 256 | // intersecting point along the normal n. 257 | // 258 | // Take 5 steps along the normal: 259 | // 260 | while (++i<6) 261 | 262 | // OK, we are comparing two distances here: 263 | // 264 | // .2*i is the distance along the normal from the point of 265 | // intersection. 266 | // 267 | // The D(...) subexpression is the distance to closest point 268 | // in the scene. 269 | // 270 | // If the point of intersection was the closest thing, then 271 | // the difference below should be zero and there is no 272 | // occlusion happening. 273 | // 274 | // However, if there's non-convex geometry in that region, the 275 | // D(...) thing will be less than the .2*i thing and we end up 276 | // contributing to a. Each time we take a step along the 277 | // normal, we reduce the "importance" of the AO computation by 278 | // a factor of 2 (occlusion at larger distances matter 279 | // exponentially less). 280 | // 281 | a -= (i/5-D(o+n*.2*i,d,w))/pow(2,i); 282 | 283 | // Do all the lighting now: 284 | // 285 | // v(m,m,1) is the color (white or blue) 286 | // 287 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 288 | // ambient, and modulates the color. 289 | // 290 | // So then we take the modulated color, and use the specular 291 | // term to linearly interpolate between that and white 292 | // (totally fake specular lighting). 293 | // 294 | // Finally we take that entire thing and darken it up with 295 | // the ambient occlusion term that we computed above. 296 | // 297 | // Pixel color is multiplied by 255 to put it in unsigned 298 | // char range. 299 | // 300 | p = (v(m,m,1)*(U(n%L)/3+.65)*(1-s) + v(1,1,1)*s)*a*255; 301 | break; 302 | 303 | } 304 | 305 | // Output each channel of the pixel as a character. 306 | putchar(p.x); 307 | putchar(p.y); 308 | putchar(p.z); 309 | 310 | } // for each column 311 | // for each row 312 | 313 | } 314 | -------------------------------------------------------------------------------- /src/miniray_2.3.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // This is the "verbose" version of an obfuscated business card 3 | // sized raytracer. 4 | // 5 | // Compile this with full optimization and pipe the output to a file 6 | // named "mattz.ppm" 7 | 8 | #include 9 | #include 10 | 11 | // Start by saving some space: 12 | #define O operator 13 | #define E return 14 | typedef float f; 15 | 16 | ////////////////////////////////////////////////////////////////////// 17 | // A basic vector class. Note all vector operations are overloaded 18 | // single character operators -- no "named" methods. Thanks, Bjarne! 19 | 20 | struct v { 21 | 22 | // Just hold x,y,z. 23 | f x, y, z; 24 | 25 | // Construct with 1, 2, or 3 elements 26 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 27 | 28 | // Multiplication by scalar. 29 | v operator*(f s) { return v(x*s, y*s, z*s); } 30 | 31 | // Dot product 32 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 33 | 34 | // Return a normalized version of this vector. 35 | v operator!() { return *this*(1/sqrt(*this%*this)); } 36 | 37 | // Vector addition 38 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 39 | 40 | // Vector subtraction (defined in terms of multiplication by -1 and 41 | // addition to save space). 42 | v operator-(v r) { return *this+r*-1; } 43 | 44 | 45 | } 46 | 47 | // The vector L holds the light direction in world space. Defining it 48 | // right after the class declaration saves us a character or two later 49 | // on. 50 | L(!v(-1,1,2)); 51 | 52 | ////////////////////////////////////////////////////////////////////// 53 | // Clamp any float to the [0,1] unit interval. 54 | 55 | f U(f a) { return a<0?0:a>1?1:a; } 56 | 57 | ////////////////////////////////////////////////////////////////////// 58 | // A helper function for distance queries. The scene is broken up into 59 | // a number of primitives. For some point p, we cycle through all the 60 | // primitives to see which one is closest to p, and this function is 61 | // called once per primitive. Variables in this function: 62 | // 63 | // c: the closest point on the current primitive to p 64 | // m: the "material" of the current primitive 65 | // 66 | // C: the closest point to p on any primitive found so far 67 | // D: the distance between p and c 68 | // M: the "material" of the closest primitive identified so far 69 | // 70 | // The implementation is dead simple: if the distance between p and c 71 | // is less than D, we simply update C, D, and M. 72 | 73 | f Q(v p, v c, v& C, f& D, f& M, f m=1) { 74 | 75 | f d = sqrt((p-c)%(p-c)); 76 | 77 | if (du?u:t; 138 | 139 | // Compute the point along the arc closest to p (just given by 140 | // the angle t and radius r), and feed it to the distance query. 141 | Q(p,v(r*cos(t)+x/2,r*sin(t)+y/2),C,D,M,.7); 142 | 143 | 144 | } else { // High bit not set 145 | 146 | // The current primitive is a line segment extending 147 | // from (x,y) to (x+dx, y+dy), where: 148 | // 149 | // dx = a if the low bit of o is set, otherwise zero. 150 | // 151 | // dy = a if the middle bit of o is set, otherwise zero. 152 | // 153 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 154 | // 155 | v k(x,y), d(a*(o&1),a*(o/2)); 156 | 157 | // Compute the closest point along the line segment and 158 | // feed it to the distance query. 159 | Q(p,k+d*U((p-k)%d/(d%d)),C,D,M,.7); 160 | 161 | } // Done with current primitive 162 | 163 | } // Looping though primitives 164 | 165 | // Find the projections of point p onto the wall and floor planes, 166 | // and feed them to the distance query. 167 | n=v(0,1); Q(p,p-n*(p%n+.9),C,D,M); 168 | n=v(0,0,1); Q(p,p-n*(p%n+.9),C,D,M); 169 | 170 | // Compute the normal n. 171 | n=!(p-C); 172 | 173 | // Return the distance -- we subtract off a radius of .45 to give 174 | // everything some dimension (otherwise all primitives would be 175 | // infinitely thin and we would only see the planes). 176 | return D-.45; 177 | 178 | } 179 | 180 | 181 | ////////////////////////////////////////////////////////////////////// 182 | // Main function just prints a header and iterates through the image 183 | // pixels. 184 | 185 | int main() { 186 | 187 | 188 | // y holds the vertical pixel coordinate 189 | f y=-111; 190 | 191 | // Output the portable pixmap header (binary version). 192 | puts("P6 600 220 255"); 193 | 194 | // For each row: 195 | while (++y<110) 196 | 197 | // For each column: 198 | // x holds the horizontal pixel coordinate 199 | for (f x=-300;x<300;++x) { 200 | 201 | // Trace a ray from origin o along direction d, and compute the 202 | // scene color at the intersection. Instead of analytic ray 203 | // tracing, this is actually "sphere tracing" by using the 204 | // distance to closest point in scene as a lower-bound of how 205 | // far we can step along the ray. 206 | 207 | // Vector variables: 208 | // 209 | // o is the ray origin 210 | // d is the ray direction, note hardcoded view transformation. 211 | // n is the normal at the point of intersection 212 | // p is the pixel color 213 | // 214 | v o(-2,4,25), 215 | d = !((!v(5,0,2)*x - 216 | !v(-2,73)*y)*.034 + 217 | v(10.25,-2,-25)), n, p, L; 218 | 219 | // Scalar variables: 220 | // 221 | // u: distance along the ray at current point 222 | // l: distance to closest object at current point 223 | // m: primitive "material" 224 | // i: a counter 225 | // a: ambient occlusion parameter 226 | // 227 | f u=0, l=0, m, i=0, a=1; 228 | 229 | // March along the ray: 230 | while (u<50) 231 | 232 | // Get the distance D from the current ray point to the scene 233 | // geometry. If it is less than a threshold, then we have 234 | // intersected the scene, otherwise increase the distance 235 | // along the ray by l: 236 | // 237 | if (fabs(l=D(o+d*(u+=l),n,m))<1e-4){ 238 | 239 | // Ok, we have intersected! Now compute lighting, which consists 240 | // of three terms: a Lambertian term, a specular term, and ambient 241 | // occlusion. 242 | 243 | // s is specular lighting component 244 | // w is ignored but needs to be passed into D above 245 | f s=pow(U(n%!(L-d)),80),w; 246 | 247 | // update o to put it at the point of intersection 248 | o=o+d*u; 249 | 250 | // It's time to compute ambient occlusion now. At this point it 251 | // would be instructive to look at the linked PDF here: 252 | // 253 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 254 | // 255 | // Basically, we're going to use the distance function D to get an 256 | // idea of how much "clutter" there is as we march away from the 257 | // intersecting point along the normal n. 258 | // 259 | // Take 5 steps along the normal: 260 | // 261 | while (++i<6) 262 | 263 | // OK, we are comparing two distances here: 264 | // 265 | // .2*i is the distance along the normal from the point of 266 | // intersection. 267 | // 268 | // The D(...) subexpression is the distance to closest point 269 | // in the scene. 270 | // 271 | // If the point of intersection was the closest thing, then 272 | // the difference below should be zero and there is no 273 | // occlusion happening. 274 | // 275 | // However, if there's non-convex geometry in that region, the 276 | // D(...) thing will be less than the .2*i thing and we end up 277 | // contributing to a. Each time we take a step along the 278 | // normal, we reduce the "importance" of the AO computation by 279 | // a factor of 2 (occlusion at larger distances matter 280 | // exponentially less). 281 | // 282 | a -= (i/5-D(o+n*.2*i,d,w))/pow(2,i); 283 | 284 | // Do all the lighting now: 285 | // 286 | // v(m,m,1) is the color (white or blue) 287 | // 288 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 289 | // ambient, and modulates the color. 290 | // 291 | // So then we take the modulated color, and use the specular 292 | // term to linearly interpolate between that and white 293 | // (totally fake specular lighting). 294 | // 295 | // Finally we take that entire thing and darken it up with 296 | // the ambient occlusion term that we computed above. 297 | // 298 | // Pixel color is multiplied by 255 to put it in unsigned 299 | // char range. 300 | // 301 | p = (v(m,m,1)*(U(n%L)/3+.65)*(1-s) + v(1,1,1)*s)*a*255; 302 | break; 303 | 304 | } 305 | 306 | // Output each channel of the pixel as a character. 307 | putchar(p.x); 308 | putchar(p.y); 309 | putchar(p.z); 310 | 311 | } // for each column 312 | // for each row 313 | 314 | } 315 | 316 | -------------------------------------------------------------------------------- /src/miniray_2.4.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // This is the "verbose" version of an obfuscated business card 3 | // sized raytracer. 4 | // 5 | // Compile this with full optimization and pipe the output to a file 6 | // named "mattz.ppm" 7 | 8 | #include 9 | #include 10 | 11 | // Start by saving some space: 12 | #define O operator 13 | #define E return 14 | 15 | typedef float f; 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | // A basic vector class. Note all vector operations are overloaded 19 | // single character operators -- no "named" methods. Thanks, Bjarne! 20 | 21 | struct v { 22 | 23 | // Just hold x,y,z. 24 | f x, y, z; 25 | 26 | // Construct with 1, 2, or 3 elements 27 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 28 | 29 | // Multiplication by scalar. 30 | v operator*(f s) { return v(x*s, y*s, z*s); } 31 | 32 | // Dot product 33 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 34 | 35 | // Return a normalized version of this vector. 36 | v operator!() { v&t=*this; return t*(1/sqrt(t%t)); } 37 | 38 | // Vector addition 39 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 40 | 41 | // Vector subtraction (defined in terms of multiplication by -1 and 42 | // addition to save space). 43 | v operator-(v r) { return *this+r*-1; } 44 | 45 | 46 | } 47 | 48 | // The vector L holds the light direction in world space. Defining it 49 | // right after the class declaration saves us a character or two later 50 | // on. 51 | L=!v(-1,1,2), 52 | 53 | // Similarly, we declare a white constant vector as well. 54 | W(1,1,1); 55 | 56 | ////////////////////////////////////////////////////////////////////// 57 | // Clamp any float to the [0,1] unit interval. 58 | 59 | f U(f a) { return a<0?0:a>1?1:a; } 60 | 61 | ////////////////////////////////////////////////////////////////////// 62 | // A helper function for distance queries. The scene is broken up into 63 | // a number of primitives. For some point p, we cycle through all the 64 | // primitives to see which one is closest to p, and this function is 65 | // called once per primitive. Variables in this function: 66 | // 67 | // c: the closest point on the current primitive to p 68 | // m: the "material" of the current primitive 69 | // 70 | // C: the closest point to p on any primitive found so far 71 | // D: the distance between p and c 72 | // M: the "material" of the closest primitive identified so far 73 | // 74 | // The implementation is dead simple: if the distance between p and c 75 | // is less than D, we simply update C, D, and M. 76 | 77 | f Q(v p, v c, v& C, f& D, f& M, f m=.6) { 78 | 79 | f d = sqrt((p-c)%(p-c)); 80 | 81 | if (du?u:t; 144 | 145 | // Compute the point along the arc closest to p (just given by 146 | // the angle t and radius r), and feed it to the distance query. 147 | n = v(cos(t),sin(t))*r + k*.5; 148 | 149 | } else { // High bit not set 150 | 151 | // The current primitive is a line segment extending 152 | // from (x,y) to (x+dx, y+dy), where: 153 | // 154 | // dx = a if the low bit of o is set, otherwise zero. 155 | // 156 | // dy = a if the middle bit of o is set, otherwise zero. 157 | // 158 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 159 | // 160 | 161 | // Compute the closest point along the line segment and 162 | // feed it to the distance query. 163 | n = k+d*U((p-k)%d/(d%d)); 164 | 165 | } 166 | 167 | // Now run the distance query on this primitive 168 | Q(p,n,C,D,M); 169 | 170 | } // Looping though primitives 171 | 172 | // Find the projections of point p onto the wall and floor planes, 173 | // and feed them to the distance query. 174 | n=v(0,1); Q(p,p-n*(p%n+.9),C,D,M,1); 175 | n=v(0,0,1); Q(p,p-n*(p%n+.9),C,D,M,1); 176 | 177 | // Compute the normal n. 178 | n=!(p-C); 179 | 180 | // Return the distance -- we subtract off a radius of .45 to give 181 | // everything some dimension (otherwise all primitives would be 182 | // infinitely thin and we would only see the planes). 183 | return D-.45; 184 | 185 | } 186 | 187 | v R(v o, v d, f z) { 188 | 189 | v n, p; 190 | 191 | // Scalar variables: 192 | // 193 | // u: distance along the ray at current point; also, dummy var for material 194 | // l: distance to closest object at current point 195 | // m: primitive "material" 196 | // a: ambient occlusion parameter 197 | // 198 | f u=0, l=0, m, i=0, a=1; 199 | 200 | // March along the ray: 201 | while (u<50) 202 | 203 | // Get the distance D from the current ray point to the scene 204 | // geometry. If it is less than a threshold, then we have 205 | // intersected the scene, otherwise increase the distance 206 | // along the ray by l: 207 | // 208 | if (fabs(l=D(o+d*(u+=l),n,m))<.001) { 209 | 210 | // Ok, we have intersected! Now compute lighting, which consists 211 | // of three terms: a Lambertian term, a specular term, and ambient 212 | // occlusion. 213 | 214 | // update o to put it at the point of intersection 215 | o=o+d*u; 216 | 217 | // It's time to compute ambient occlusion now. At this point it 218 | // would be instructive to look at the linked PDF here: 219 | // 220 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 221 | // 222 | // Basically, we're going to use the distance function D to get an 223 | // idea of how much "clutter" there is as we march away from the 224 | // intersecting point along the normal n. 225 | // 226 | // Take 5 steps along the normal: 227 | 228 | while (++i<6) 229 | 230 | // OK, we are comparing two distances here: 231 | // 232 | // .2*i is the distance along the normal from the point of 233 | // intersection. 234 | // 235 | // The D(...) subexpression is the distance to closest point 236 | // in the scene. 237 | // 238 | // If the point of intersection was the closest thing, then 239 | // the difference below should be zero and there is no 240 | // occlusion happening. 241 | // 242 | // However, if there's non-convex geometry in that region, the 243 | // D(...) thing will be less than the .2*i thing and we end up 244 | // contributing to a. Each time we take a step along the 245 | // normal, we reduce the "importance" of the AO computation by 246 | // a factor of 2 (occlusion at larger distances matter 247 | // exponentially less). 248 | // 249 | a -= (i/5-D(o+n*.2*i,p,u))/pow(2,i); 250 | 251 | // Do all the lighting now: 252 | // 253 | // v(m,m,1) is the color (white or blue) 254 | // 255 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 256 | // ambient, and modulates the color. 257 | // 258 | // Finally we take that entire thing and darken it up with 259 | // the ambient occlusion term that we computed above. 260 | p = v(m,m,1)*(U(n%L)/3+.65)*a; 261 | 262 | if (z && m!=1) { p = p*.7 + R(o+n*.1,n,0)*.3; } 263 | 264 | // Compute a specular term and use it to linearly interpolate 265 | // between the surface color and white; this is physically 266 | // implausible, but doesn't require clamping (as does, for 267 | // instance, the Phong shading model). 268 | u=pow(U(n%!(L-d)),40); 269 | 270 | return p*(1-u) + W*u; 271 | 272 | } // hit 273 | 274 | return W*.6; 275 | 276 | } 277 | 278 | 279 | 280 | ////////////////////////////////////////////////////////////////////// 281 | // Main function just prints a header and iterates through the image 282 | // pixels. 283 | 284 | int main() { 285 | 286 | 287 | // y holds the vertical pixel coordinate 288 | f y=-111; 289 | 290 | // Output the portable pixmap header (binary version). 291 | puts("P6 600 220 255"); 292 | 293 | // For each row: 294 | while (++y<110) 295 | 296 | // For each column: 297 | // x holds the horizontal pixel coordinate 298 | for (f x=-300;x<300;++x) { 299 | 300 | // Trace a ray from origin o along direction d, and compute the 301 | // scene color at the intersection. Instead of analytic ray 302 | // tracing, this is actually "sphere tracing" by using the 303 | // distance to closest point in scene as a lower-bound of how 304 | // far we can step along the ray. 305 | 306 | v p = R(v(-2,4,25), 307 | !((!v(5,0,2)*x - 308 | !v(-2,73)*y)*.034 + 309 | v(10.25,-2,-25)), 310 | 1)*255; 311 | 312 | // Output each channel of the pixel as a character. 313 | putchar(p.x); 314 | putchar(p.y); 315 | putchar(p.z); 316 | 317 | } // for each column 318 | // for each row 319 | 320 | } 321 | 322 | -------------------------------------------------------------------------------- /src/miniray_3.0.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // This is the "verbose" version of an obfuscated business card 3 | // sized raytracer. 4 | // 5 | // Compile this with full optimization and pipe the output to a file 6 | // named "mattz.ppm" 7 | 8 | #include 9 | #include 10 | 11 | // Start by saving some space: 12 | #define O operator 13 | #define E return 14 | 15 | typedef float f; 16 | 17 | f H=.5, Z=.33, Y=Z+Z, I; 18 | 19 | ////////////////////////////////////////////////////////////////////// 20 | // A basic vector class. Note all vector operations are overloaded 21 | // single character operators -- no "named" methods. Thanks, Bjarne! 22 | 23 | struct v { 24 | 25 | // Just hold x,y,z. 26 | f x, y, z; 27 | 28 | // Construct with 1, 2, or 3 elements 29 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 30 | 31 | // Multiplication by scalar. 32 | v operator*(f s) { return v(x*s, y*s, z*s); } 33 | 34 | // Dot product 35 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 36 | 37 | // Return a normalized version of this vector. 38 | v operator!() { v&t=*this; return t*pow(t%t,-H); } 39 | 40 | // Vector addition 41 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 42 | 43 | // Vector subtraction (defined in terms of multiplication by -1 and 44 | // addition to save space). 45 | v operator-(v r) { return *this+r*-1; } 46 | 47 | 48 | } 49 | 50 | // The vector L holds the light direction in world space. Defining it 51 | // right after the class declaration saves us a character or two later 52 | // on. 53 | L=!v(-1,1,2), 54 | W(1,1,1), 55 | F(Y,Y,1), 56 | P, C, M, N; 57 | 58 | 59 | ////////////////////////////////////////////////////////////////////// 60 | // Clamp any float to the [0,1] unit interval. 61 | 62 | f U(f a) { return a<0?0:a>1?1:a; } 63 | 64 | ////////////////////////////////////////////////////////////////////// 65 | // A helper function for distance queries. The scene is broken up into 66 | // a number of primitives. For some point p, we cycle through all the 67 | // primitives to see which one is closest to p, and this function is 68 | // called once per primitive. Variables in this function: 69 | // 70 | // c: the closest point on the current primitive to p 71 | // m: the "material" of the current primitive 72 | // 73 | // C: the closest point to p on any primitive found so far 74 | // D: the distance between p and c 75 | // M: the "material" of the closest primitive identified so far 76 | // 77 | // The implementation is dead simple: if the distance between p and c 78 | // is less than D, we simply update C, D, and M. 79 | 80 | f Q(v c, v m) { 81 | 82 | f d = (P-c)%(P-c); 83 | 84 | if (du?u:t; 163 | 164 | // Compute the point along the arc closest to p (just given by 165 | // the angle t and radius r), and feed it to the distance query. 166 | Q(k*H+v(cos(t),sin(t))*r,F); 167 | 168 | } 169 | 170 | 171 | } // Looping though primitives 172 | 173 | // Find the projections of point p onto the wall and floor planes, 174 | // and feed them to the distance query. 175 | N=v(0,1); Q(p-N*(p%N+.9),W); 176 | 177 | if (M.x==1 && (int((p.x+64)/8)^int((p.z+64)/8))&1) 178 | M = Y; 179 | 180 | //N=v(0,0,1); Q(p,p-N*(p%n+.9),W); 181 | 182 | // Compute the normal n. 183 | N=P-C; 184 | 185 | // Return the distance -- we subtract off a radius of .45 to give 186 | // everything some dimension (otherwise all primitives would be 187 | // infinitely thin and we would only see the planes). 188 | return sqrt(I)-.45; 189 | 190 | } 191 | 192 | v R(v o, v d, f z) { 193 | 194 | v n, p; 195 | 196 | // Scalar variables: 197 | // 198 | // u: distance along the ray at current point 199 | // l: distance to closest object at current point 200 | // m: primitive "material" 201 | // a: ambient occlusion parameter 202 | // 203 | f u=0, l=0, i=0, a=1, k=d.z*d.z; 204 | 205 | // March along the ray: 206 | while (u<97) 207 | 208 | // Get the distance D from the current ray point to the scene 209 | // geometry. If it is less than a threshold, then we have 210 | // intersected the scene, otherwise increase the distance 211 | // along the ray by l: 212 | // 213 | if ((l=D(o+d*(u+=l)))*l<.001) { 214 | 215 | p=M; 216 | n=!N; 217 | 218 | // Ok, we have intersected! Now compute lighting, which consists 219 | // of three terms: a Lambertian term, a specular term, and ambient 220 | // occlusion. 221 | 222 | // update o to put it at the point of intersection 223 | o=o+d*u; 224 | 225 | // It's time to compute ambient occlusion now. At this point it 226 | // would be instructive to look at the linked PDF here: 227 | // 228 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 229 | // 230 | // Basically, we're going to use the distance function D to get an 231 | // idea of how much "clutter" there is as we march away from the 232 | // intersecting point along the normal n. 233 | // 234 | // Take 5 steps along the normal: 235 | while (++i<6) 236 | 237 | // OK, we are comparing two distances here: 238 | // 239 | // .2*i is the distance along the normal from the point of 240 | // intersection. 241 | // 242 | // The D(...) subexpression is the distance to closest point 243 | // in the scene. 244 | // 245 | // If the point of intersection was the closest thing, then 246 | // the difference below should be zero and there is no 247 | // occlusion happening. 248 | // 249 | // However, if there's non-convex geometry in that region, the 250 | // D(...) thing will be less than the .2*i thing and we end up 251 | // contributing to a. Each time we take a step along the 252 | // normal, we reduce the "importance" of the AO computation by 253 | // a factor of 2 (occlusion at larger distances matter 254 | // exponentially less). 255 | // 256 | a -= U(i/5-D(o+n*.2*i))/pow(2,i); 257 | 258 | // Do all the lighting now: 259 | // 260 | // v(m,m,1) is the color (white or blue) 261 | // 262 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 263 | // ambient, and modulates the color. 264 | // 265 | // Finally we take that entire thing and darken it up with 266 | // the ambient occlusion term that we computed above. 267 | p = p*(U(n%L)*Z+Y)*a; 268 | 269 | if (z) 270 | p = p*Y + R(o+n*.1,d-n*2*(d%n),z-1)*Z; 271 | 272 | // Compute a specular term and use it to linearly interpolate 273 | // between the surface color and white; this is physically 274 | // implausible, but doesn't require clamping (as does, for 275 | // instance, the Phong shading model). 276 | u=pow(U(n%!(L-d)),40); 277 | 278 | return p*(1-u) + W*u; 279 | 280 | } // hit 281 | 282 | return v(k, k, 1); 283 | 284 | } 285 | 286 | 287 | 288 | ////////////////////////////////////////////////////////////////////// 289 | // Main function just prints a header and iterates through the image 290 | // pixels. 291 | 292 | int main() { 293 | 294 | // y holds the vertical pixel coordinate 295 | f y=-111; 296 | 297 | // Output the portable pixmap header (binary version). 298 | puts("P6 600 220 255"); 299 | 300 | // For each row: 301 | while (++y<110) 302 | 303 | // For each column: 304 | // x holds the horizontal pixel coordinate 305 | for (f x=-300;x<300;++x) { 306 | 307 | // Trace a ray from origin o along direction d, and compute the 308 | // scene color at the intersection. Instead of analytic ray 309 | // tracing, this is actually "sphere tracing" by using the 310 | // distance to closest point in scene as a lower-bound of how 311 | // far we can step along the ray. 312 | 313 | v p = R(v(-2,4,25), 314 | !((!v(5,0,2)*x - 315 | !v(-2,73)*y)*.034 + 316 | v(10.25,-2,-25)), 317 | 2)*255; 318 | 319 | // Output each channel of the pixel as a character. 320 | putchar(p.x); 321 | putchar(p.y); 322 | putchar(p.z); 323 | 324 | } // for each column 325 | // for each row 326 | 327 | } 328 | 329 | -------------------------------------------------------------------------------- /src/miniray_3.1.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // This is the "verbose" version of an obfuscated business card 3 | // sized raytracer. 4 | // 5 | // Compile this with full optimization and pipe the output to a file 6 | // named "mattz.ppm" 7 | 8 | #include 9 | 10 | // Start by saving some space: 11 | //#define O operator 12 | //#define E return 13 | 14 | typedef double f; 15 | 16 | 17 | f H=.5, Y=.66, S=-1, I, y=-111; 18 | 19 | extern "C" { 20 | f cos(f), pow(f, f), atan2(f, f); 21 | } 22 | 23 | ////////////////////////////////////////////////////////////////////// 24 | // A basic vector class. Note all vector operations are overloaded 25 | // single character operators -- no "named" methods. Thanks, Bjarne! 26 | 27 | struct v { 28 | 29 | // Just hold x,y,z. 30 | f x, y, z; 31 | 32 | // Construct with 1, 2, or 3 elements 33 | v (f a=0, f b=0, f c=0): x(a), y(b), z(c) {} 34 | 35 | // Dot product 36 | f operator%(v r) { return x*r.x + y*r.y + z*r.z; } 37 | 38 | // Vector addition 39 | v operator+(v r) { return v(x+r.x, y+r.y, z+r.z); } 40 | 41 | // Multiplication by scalar. 42 | v operator*(f s) { return v(x*s, y*s, z*s); } 43 | 44 | 45 | } 46 | 47 | // The vector L holds the light direction in world space. Defining it 48 | // right after the class declaration saves us a character or two later 49 | // on. 50 | W(1,1,1), 51 | P, C, M; 52 | 53 | 54 | 55 | 56 | ////////////////////////////////////////////////////////////////////// 57 | // Clamp any float to the [0,1] unit interval. 58 | 59 | f U(f a) { return a<0?0:a>1?1:a; } 60 | 61 | 62 | // Normalize vector 63 | v _(v t) { return t*pow(t%t, -H); } 64 | 65 | 66 | ////////////////////////////////////////////////////////////////////// 67 | // A helper function for distance queries. The scene is broken up into 68 | // a number of primitives. For some point P, we cycle through all the 69 | // primitives to see which one is closest to P, and this function is 70 | // called once per primitive. Variables in this function: 71 | // 72 | // c: the closest point on the current primitive to P 73 | // 74 | // C: the closest point to P on any primitive found so far 75 | // I: the squared distance between P and c 76 | // 77 | // The implementation is dead simple: if the distance between p and c 78 | // is less than I, we simply update C and I 79 | 80 | f Q(v c) { 81 | 82 | M = P+c*S; 83 | f d = M%M; 84 | 85 | return d < I ? C=c, I=d : 0; 86 | 87 | } 88 | 89 | ////////////////////////////////////////////////////////////////////// 90 | // Test the distance from the point p to the scene, and store the 91 | // scene normal (normalized difference between p and closest point in 92 | // the scene) in n, and the "material" of the closest primitive in m. 93 | // 94 | f D(v p) { 95 | 96 | 97 | I=99; P=p; 98 | f l, u, t; 99 | v k; 100 | 101 | // Encode the letters "mattz", see below for explanation: 102 | // Interpret bytecodes by iterating over string in 2-byte chunks. 103 | // P, I are the variables associated with the distance query 104 | // function above. 105 | for (const char* b="BCJB@bJBHbJCE[FLL_A[FLMCA[CCTT`T"; *b; ++b) { 106 | 107 | // Extract o, a, x, y from the current two bytes: 108 | // 109 | // o is a 3-bit opcode that stores the current geometry type 110 | // (line segment or arc) 111 | // 112 | // a is a 3-bit argument whose interpretation depends on whether 113 | // we are a line segment or arc 114 | // 115 | // x and y are 5-bit scene coordinates. 116 | // 117 | k.x+=*b/4&15; 118 | int o=*b&3, a=*++b&7; 119 | k.y=*b/8&7; 120 | 121 | v d(o%2*a,o/2*a); 122 | 123 | !o ? 124 | 125 | 126 | // The current primitive is an arc centered around 127 | // (x,y) with starting angle l, ending angle u, 128 | // and radius r, where 129 | // 130 | // l = -M_PI if the high bit of a is set, otherwise 0. 131 | // 132 | // u = M_PI if the middle bit of a is set, otherwise 0. 133 | // 134 | // r = 1.5 if the low bit of a is set, otherwise 1. 135 | // 136 | // Also compute t, the angle of the point p with respect to the 137 | // arc's center. 138 | // 139 | l=a/4%2*-3.14, u=a/2%2*3.14, d=p+k*-H, t=atan2(d.y, d.x), 140 | 141 | // Clamp t to the range given. 142 | t = tu?u:t, 143 | 144 | // Compute the point along the arc closest to p (just given by 145 | // the angle t and radius r), and feed it to the distance query. 146 | Q(k*H+v(cos(t),cos(t-1.57))*(a%2*H+1)) 147 | 148 | : 149 | 150 | // The current primitive is a line segment extending 151 | // from (x,y) to (x+dx, y+dy), where: 152 | // 153 | // dx = a if the low bit of o is set, otherwise zero. 154 | // 155 | // dy = a if the middle bit of o is set, otherwise zero. 156 | // 157 | // Here, k stores the point (x,y), d stores the vector (dx,dy) 158 | // 159 | // Compute the closest point along the line segment and 160 | // feed it to the distance query. 161 | Q(k+d*U((p+k*S)%d/(d%d))); 162 | 163 | } // Looping though primitives 164 | 165 | // Find the projections of point p onto the floor plane and feed it 166 | // to the distance query. If it is the closest, evaluate the floor 167 | // texture and assign the material accordingly; otherwise assign the 168 | // letter material. 169 | 170 | 171 | // Return the distance -- we subtract off a radius of .45 to give 172 | // everything some dimension (otherwise all primitives would be 173 | // infinitely thin and we would only see the planes). 174 | return M = Q(v(p.x,-.9,p.z)) ? 175 | (int(p.x+64)^int(p.z+64))/8&1 ? Y : W : v(Y,Y,1), 176 | pow(I,H)-.45; 177 | 178 | } 179 | 180 | v R(v o, v d, f z) { 181 | 182 | // Scalar variables: 183 | // 184 | // u: distance along the ray at current point 185 | // l: distance to closest object at current point 186 | // m: primitive "material" 187 | // a: ambient occlusion parameter 188 | // 189 | // March along the ray: Get the distance D from the current ray 190 | // point to the scene geometry. If it is less than a threshold, 191 | // then we have intersected the scene, otherwise increase the 192 | // distance along the ray by l: 193 | 194 | for (f u=0, l=1, i=0, a=1; u<97; u+=l=D(o+d*u)) 195 | 196 | if (l<.01) { 197 | 198 | v p=M, n=_(P+C*S), L=_(v(S,1,2)); 199 | 200 | // Ok, we have intersected! Now compute lighting, which consists 201 | // of three terms: a Lambertian term, a specular term, and ambient 202 | // occlusion. 203 | 204 | 205 | // It's time to compute ambient occlusion now. At this point it 206 | // would be instructive to look at the linked PDF here: 207 | // 208 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 209 | // 210 | // Basically, we're going to use the distance function D to get an 211 | // idea of how much "clutter" there is as we march away from the 212 | // intersecting point along the normal n. 213 | // 214 | // First update o to put it at the point of intersection, then 215 | // Take 5 steps along the normal: 216 | for (o=o+d*u; ++i<6; a -= U(i/3-D(o+n*i*.3))/pow(2,i)); 217 | 218 | // OK, we are comparing two distances here: 219 | // 220 | // i*.3 is the distance along the normal from the point of 221 | // intersection. 222 | // 223 | // The D(...) subexpression is the distance to closest point 224 | // in the scene. 225 | // 226 | // If the point of intersection was the closest thing, then 227 | // the difference below should be zero and there is no 228 | // occlusion happening. 229 | // 230 | // However, if there's non-convex geometry in that region, the 231 | // D(...) thing will be less than the i*.3 thing and we end up 232 | // contributing to a. Each time we take a step along the 233 | // normal, we reduce the "importance" of the AO computation by 234 | // a factor of 2 (occlusion at larger distances matter 235 | // exponentially less). 236 | // 237 | 238 | 239 | // Do all the lighting now: 240 | // 241 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 242 | // ambient, and modulates the color. 243 | // 244 | // Finally we take that entire thing and darken it up with 245 | // the ambient occlusion term that we computed above. 246 | p = p*(U(n%L)*H*Y+Y)*a; 247 | 248 | p = z ? p*Y + R(o+n*.1,d+n*-2*(d%n),z-1)*H*Y : p; 249 | 250 | // Compute a specular term and use it to linearly interpolate 251 | // between the surface color and white; this is physically 252 | // implausible, but doesn't require clamping (as does, for 253 | // instance, the Phong shading model). 254 | u=pow(U(n%_(L+d*S)),40); 255 | 256 | return p + p*-u + W*u; 257 | 258 | } // hit 259 | 260 | // Didn't hit anything, return the sky color. 261 | z=d.z*d.z; 262 | return v(z, z, 1); 263 | 264 | } 265 | 266 | 267 | 268 | ////////////////////////////////////////////////////////////////////// 269 | // Main function just prints a header and iterates through the image 270 | // pixels. 271 | 272 | int main() { 273 | 274 | 275 | 276 | // Output the portable pixmap header (binary version). 277 | // Then, for each row: 278 | for (puts("P6 600 220 255"); ++y<110;) 279 | 280 | // For each column: 281 | // x holds the horizontal pixel coordinate 282 | for (f x=-301; 283 | 284 | P = R(v(-2,4,25), 285 | _(_(v(5,0,2))*++x + 286 | _(v(-2,73))*-y + 287 | v(301,-59,-735)), 288 | 2)*255, x<300; 289 | 290 | putchar(P.z) 291 | 292 | ) 293 | 294 | // Trace a ray from origin o along direction d, and compute the 295 | // scene color at the intersection. Instead of analytic ray 296 | // tracing, this is actually "sphere tracing" by using the 297 | // distance to closest point in scene as a lower-bound of how 298 | // far we can step along the ray. 299 | 300 | putchar(P.x), putchar(P.y); 301 | 302 | // Then output each channel of the pixel as a character. (see 303 | // for loop increment above) 304 | 305 | 306 | } 307 | 308 | -------------------------------------------------------------------------------- /src/miniray_4.0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define E return 5 | 6 | typedef float f; 7 | typedef struct { f x,y,z; } v; 8 | 9 | f H=.5, Z=.33, Y=.66, I, x, y=-111; 10 | v L, W={1,1,1}, F, P, C, M, N; 11 | 12 | v G(f x, f y, f z) { v n={x,y,z}; return n; } 13 | v A(v a, v b, f c) { return G(a.x+b.x*c, a.y+b.y*c, a.z+b.z*c); } 14 | f O(v a, v b) { return a.x*b.x+a.y*b.y+a.z*b.z; } 15 | v S(v a, f s) { return G(a.x*s, a.y*s, a.z*s); } 16 | v _(v a) { return S(a, 1/sqrt(O(a,a))); } 17 | 18 | f U(f a) { return a<0?0:a>1?1:a; } 19 | 20 | f Q(v c, v m) { 21 | v D = A(P,c,-1); 22 | f d = O(D,D); 23 | return du?u:t; 91 | 92 | // Compute the point along the arc closest to p (just given by 93 | // the angle t and radius r), and feed it to the distance query. 94 | Q(A(S(k,H),G(cos(t),sin(t),0),r),F); 95 | 96 | } 97 | 98 | 99 | } // Looping though primitives 100 | 101 | N=G(0,1,0); Q(A(p,N,-O(p,N)-.9),W); 102 | 103 | M = M.x==1 && ((int)((p.x+64)/8)^(int)((p.z+64)/8))&1 ? 104 | G(Y,0,0) : M; 105 | 106 | N=A(P,C,-1); 107 | 108 | return sqrt(I)-.45; 109 | 110 | } 111 | 112 | v R(v o, v d, f z) { 113 | 114 | f u=0, l=0, i=0, a=1, k=d.z*d.z; 115 | v p, n; 116 | 117 | while (u<97) 118 | if ((l=D(p = A(o,d,u+=l)))*l<.001) { 119 | 120 | p=M; 121 | n=_(N); 122 | 123 | // Ok, we have intersected! Now compute lighting, which consists 124 | // of three terms: a Lambertian term, a specular term, and ambient 125 | // occlusion. 126 | 127 | // update o to put it at the point of intersection 128 | o=A(o,d,u); 129 | 130 | // It's time to compute ambient occlusion now. At this point it 131 | // would be instructive to look at the linked PDF here: 132 | // 133 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 134 | // 135 | // Basically, we're going to use the distance function D to get an 136 | // idea of how much "clutter" there is as we march away from the 137 | // intersecting point along the normal n. 138 | // 139 | // Take 5 steps along the normal: 140 | while (++i<6) 141 | 142 | // OK, we are comparing two distances here: 143 | // 144 | // .2*i is the distance along the normal from the point of 145 | // intersection. 146 | // 147 | // The D(...) subexpression is the distance to closest point 148 | // in the scene. 149 | // 150 | // If the point of intersection was the closest thing, then 151 | // the difference below should be zero and there is no 152 | // occlusion happening. 153 | // 154 | // However, if there's non-convex geometry in that region, the 155 | // D(...) thing will be less than the .2*i thing and we end up 156 | // contributing to a. Each time we take a step along the 157 | // normal, we reduce the "importance" of the AO computation by 158 | // a factor of 2 (occlusion at larger distances matter 159 | // exponentially less). 160 | // 161 | a -= U(i/5-D(A(o,n,i/5)))/pow(2,i); 162 | 163 | // Do all the lighting now: 164 | // 165 | // v(m,m,1) is the color (white or blue) 166 | // 167 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 168 | // ambient, and modulates the color. 169 | // 170 | // Finally we take that entire thing and darken it up with 171 | // the ambient occlusion term that we computed above. 172 | p = S(p,(U(O(n,L))*Z+Y)*a); 173 | 174 | p = z?A(S(p,Y),R(A(o,n,.1),A(d,n,-2*O(d,n)),z-1),Z):p; 175 | 176 | // Compute a specular term and use it to linearly interpolate 177 | // between the surface color and white; this is physically 178 | // implausible, but doesn't require clamping (as does, for 179 | // instance, the Phong shading model). 180 | u=pow(U(O(n,_(A(L,d,-1)))),40); 181 | 182 | return A(S(p,1-u),W,u); 183 | 184 | } 185 | 186 | return G(k,k,1); 187 | 188 | } 189 | 190 | int main() { 191 | 192 | // Set up the lighting direction and material 193 | L=_(G(-1,1,2)); 194 | F=G(Y,Y,1); 195 | 196 | // Output the portable pixmap header (binary version). 197 | puts("P6 600 220 255"); 198 | 199 | // For each row: 200 | // y holds the vertical pixel coordinate 201 | while (++y<110) 202 | 203 | // For each column: 204 | // x holds the horizontal pixel coordinate 205 | for (x=-300;x<300;++x) { 206 | 207 | v p = S( R( G(-2,4,25), 208 | _( A( G(10.25,-2,-25) , 209 | A( S( _(G(5,0,2)), x ), 210 | _(G(-2,73,0)),-y), .034) ), 211 | 2 ), 255 ); 212 | putchar(p.x); 213 | putchar(p.y); 214 | putchar(p.z); 215 | 216 | } 217 | 218 | return 0; 219 | 220 | } 221 | -------------------------------------------------------------------------------- /src/miniray_4.1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define E return 5 | 6 | typedef float f; 7 | typedef struct { f x,y,z; } v; 8 | 9 | f H=.5, Z=.33, Y=.66, I, x, y=-111, i, j; 10 | v L, W={1,1,1}, F={.7,.7,1}, P, C, M, N, k, d; 11 | 12 | v G(f x, f y, f z) { v a; a.x=x; a.y=y; a.z=z; return a; } 13 | v A(v a, v b, f c) { return G(a.x+b.x*c, a.y+b.y*c, a.z+b.z*c); } 14 | f O(v a, v b) { return a.x*b.x+a.y*b.y+a.z*b.z; } 15 | v S(v a, f s) { return G(a.x*s, a.y*s, a.z*s); } 16 | v _(v a) { return S(a, 1/sqrt(O(a,a))); } 17 | 18 | f U(f a) { return a<0?0:a>1?1:a; } 19 | 20 | f Q(v c, v m) { 21 | v D = A(P,c,-1); 22 | f d = O(D,D); 23 | return du?u:t; 91 | 92 | // Compute the point along the arc closest to p (just given by 93 | // the angle t and radius r), and feed it to the distance query. 94 | Q(A(S(k,H),G(cos(t),sin(t),0),r),F); 95 | 96 | } 97 | 98 | 99 | } // Looping though primitives 100 | 101 | N=G(0,1,0); Q(A(p,N,-O(p,N)-.9),W); 102 | 103 | M = M.x==1 && ((int)((p.x+64)/8)^(int)((p.z+64)/8))&1 ? 104 | G(Y,0,0) : M; 105 | 106 | N=A(P,C,-1); 107 | 108 | return sqrt(I)-.45; 109 | 110 | } 111 | 112 | v R(v o, v d, f z) { 113 | 114 | f u=0, l=0, i=0, a=1, k=d.z*d.z; 115 | v p, n; 116 | 117 | while (u<97) 118 | if ((l=D(p = A(o,d,u+=l)))*l<.001) { 119 | 120 | p=M; 121 | n=_(N); 122 | 123 | // Ok, we have intersected! Now compute lighting, which consists 124 | // of three terms: a Lambertian term, a specular term, and ambient 125 | // occlusion. 126 | 127 | // update o to put it at the point of intersection 128 | o=A(o,d,u); 129 | 130 | // It's time to compute ambient occlusion now. At this point it 131 | // would be instructive to look at the linked PDF here: 132 | // 133 | // http://iquilezles.org/www/material/nvscene2008/nvscene2008.htm 134 | // 135 | // Basically, we're going to use the distance function D to get an 136 | // idea of how much "clutter" there is as we march away from the 137 | // intersecting point along the normal n. 138 | // 139 | // Take 5 steps along the normal: 140 | while (++i<6) 141 | 142 | // OK, we are comparing two distances here: 143 | // 144 | // .2*i is the distance along the normal from the point of 145 | // intersection. 146 | // 147 | // The D(...) subexpression is the distance to closest point 148 | // in the scene. 149 | // 150 | // If the point of intersection was the closest thing, then 151 | // the difference below should be zero and there is no 152 | // occlusion happening. 153 | // 154 | // However, if there's non-convex geometry in that region, the 155 | // D(...) thing will be less than the .2*i thing and we end up 156 | // contributing to a. Each time we take a step along the 157 | // normal, we reduce the "importance" of the AO computation by 158 | // a factor of 2 (occlusion at larger distances matter 159 | // exponentially less). 160 | // 161 | a -= U(i/5-D(A(o,n,i/5)))/pow(2,i); 162 | 163 | // Do all the lighting now: 164 | // 165 | // v(m,m,1) is the color (white or blue) 166 | // 167 | // U(n%L)/3+.65 is a blend of 0.33 Lambertian and 0.65 168 | // ambient, and modulates the color. 169 | // 170 | // Finally we take that entire thing and darken it up with 171 | // the ambient occlusion term that we computed above. 172 | p = S(p,(U(O(n,L))*Z+Y)*a); 173 | 174 | p = z?A(S(p,Y),R(A(o,n,.1),A(d,n,-2*O(d,n)),z-1),Z):p; 175 | 176 | // Compute a specular term and use it to linearly interpolate 177 | // between the surface color and white; this is physically 178 | // implausible, but doesn't require clamping (as does, for 179 | // instance, the Phong shading model). 180 | u=pow(U(O(n,_(A(L,d,-1)))),40); 181 | 182 | return A(S(p,1-u),W,u); 183 | 184 | } 185 | 186 | return G(k,k,1); 187 | 188 | } 189 | 190 | int main() { 191 | 192 | // Set up the lighting direction and material 193 | L=_(G(-1,1,2)); 194 | 195 | // Output the portable pixmap header (binary version). 196 | puts("P6 600 220 255"); 197 | 198 | // For each row: 199 | // y holds the vertical pixel coordinate 200 | while (++y<110) 201 | 202 | // For each column: 203 | // x holds the horizontal pixel coordinate 204 | for (x=-300;x<300;++x) { 205 | 206 | v p = {0,0,0}; 207 | for (i=0; i<1; i+=H) 208 | for (j=0; j<1; j+=H) 209 | p = A(p, R( G(-2,4,25), 210 | _( A( G(10.25,-2,-25) , 211 | A( S( _(G(5,0,2)), x+i ), 212 | _(G(-2,73,0)),-y-j), .034) ), 213 | 2 ), 214 | 63.75 ); 215 | putchar(p.x); 216 | putchar(p.y); 217 | putchar(p.z); 218 | 219 | } 220 | 221 | return 0; 222 | 223 | } 224 | -------------------------------------------------------------------------------- /src/miniray_4.2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define E return 4 | 5 | typedef float f; 6 | f H=.5, Z=.33, Y=.66, I, y=-111, t=0, q, w, u, m, r; 7 | f U(f a) { return a<0?0:a>1?1:a; } 8 | 9 | typedef struct { f c,a,t; } v; 10 | 11 | v L, W={1,1,1}, F={.7,.7,1}, P, C, M, N, k, d, K; 12 | 13 | v G(f t, f a, f c) { K.c=t; K.a=a; K.t=c; return K; } 14 | v A(v a, v b, f c) { return G(a.c+b.c*c, a.a+b.a*c, a.t+b.t*c); } 15 | f O(v a, v b) { return a.t*b.t+a.c*b.c+a.a*b.a; } 16 | f Q(v c, v m) { 17 | K = A(P,c,-1); 18 | q = O(K,K); 19 | return qU+H*X ? L : t > U ? U : t 2 | #include 3 | #define S for 4 | #define E return 5 | 6 | typedef float f; 7 | 8 | f U(f a) { return a<0?0:a>1?1:a; } 9 | 10 | f H=.5, Y=.66, I, y=-111, T=-1, l=0, q, w, s, t, r; 11 | 12 | typedef struct { f x,y,z; } v; 13 | 14 | f O(v a, v b) { return q=a.z*b.z+b.x*a.x+a.y*b.y; } 15 | 16 | v L, W={1,1,1}, Z={0,0,0}, P, C, M, N, K, p; 17 | 18 | v G(f t, f a, f c) { K.x=t; K.z=c; K.y=a; return K; } 19 | 20 | v A(v a, v b, f c) { return G(a.x+b.x*c, a.y+c*b.y, b.z*c+a.z); } 21 | 22 | char* J = "LJFFF%7544\0#( #@@DA#(.@@%(0CAaIqDCI$IDEH%P@T@qL%PEaIpBJCAI%KBPBEP%CBPEaIqBAI%CAaIqBqDAI%U@PE%AAaIqBcDAI%ACaIaCqDCI%(aHCcIpBBH%E@aIqBAI%AAaIqB%AAaIqBEH%AAPBaIqB%PCDHxL%H@hIcBBI%E@qJBH#C@@D%aIBI@D%E@QB2P#E@'C@qJBHqJBH%C@qJBH%AAaIqBAI%C@cJ%cJCH%C@qJ%aIqB1I%PCDI`I%BAaICH%KH+@'JH+@KP*@%S@3P%H@ABhIaBBI%P@S@PC", 23 | 24 | B[999], *b=B, *j, *e, X=40, o, a, c, m, z=5; 25 | 26 | f Q() { 27 | return A(P,M,T), O(K,K)u+H*d ? l : j > u ? u : j1 ? z=0, 1[k] : J; *e; ++e) 102 | S (o=a=0, j=J+11; (c=*j)&&!(o&&*j 2 | #include 3 | #define S for 4 | #define E return 5 | 6 | typedef float f; 7 | 8 | f U(f a) { return a<0?0:a>1?1:a; } 9 | 10 | f H=.5, Y=.66, I, T=-1, l=0, q, w, u, i; 11 | 12 | typedef struct { f x,y,z; } v; 13 | 14 | f O(v a, v b) { return q=a.z*b.z+b.x*a.x+a.y*b.y; } 15 | 16 | v L, W={1,1,1}, Z={0,0,0}, B[99], P, C, M, N, K, p; 17 | 18 | int b=0, r, y=-111, (*m)(int) = putchar, o, a, c, t; 19 | 20 | v G(f t, f a, f c) { K.x=t; K.z=c; K.y=a; return K; } 21 | 22 | v A(v a, v b, f c) { return G(a.x+b.x*c, a.y+c*b.y, b.z*c+a.z); } 23 | 24 | char* J = "LJFFF%7544\0#( #@@DA#(.@@%(0CAaIqDCI$IDEH%P@T@qL%PEaIpBJCAI%KBPBEP%CBPEaIqBAI%CAaIqBqDAI%U@PE%AAaIqBcDAI%ACaIaCqDCI%(aHCcIpBBH%E@aIqBAI%AAaIqB%AAaIqBEH%AAPBaIqB%PCDHxL%H@hIcBBI%E@qJBH#C@@D%aIBI@D%E@QB2P#E@'C@qJBHqJBH%C@qJBH%AAaIqBAI%C@cJ%cJCH%C@qJ%aIqB1I%PCDI`I%BAaICH%KH+@'JH+@KP*@%S@3P%H@ABhIaBBI%P@S@PC", 25 | 26 | *j, *e, X=40, z=5; 27 | 28 | f Q() { 29 | return A(P,M,T), O(K,K)t+H*a ? o : w > t ? t : w1 ? z=0, 1[k] : J; *e; ++e) 90 | S (o=a=0, j=J+11; (c=*j)&&!(o&&c2), 1 : 94 | (o = (a = cX ? a : *++j) == ((*e|32)^z)) ; 95 | 96 | S (r=b, z=x<3, l = 10-l*H, 97 | L=_(G(T,1,2)), puts("P6 600 220 255"); ++y<110;) 98 | 99 | S (x=-301;p=Z,++x<300;m(p.x),m(p.y),m(p.z)) 100 | 101 | S (c=0; c 2 | #include 3 | #define E return 4 | #define S for 5 | 6 | /* 7 | _abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 8 | iiivc fvfccfFiivfivif fttiFvvFPiFffcvivvFvFiPiFFvifv 9 | * * 10 | */ 11 | 12 | 13 | char* J = "LJFFF%7544x^H^XXHZZXHZ]]2#( #@@DA#(.@@%(0CAaIqDCI$IDEH%P@T@qL%PEaIpBJCAI%KBPBEP%CBPEaIqBAI%CAaIqBqDAI%U@PE%AAaIqBcDAI%ACaIaCqDCI%(aHCcIpBBH%E@aIqBAI%AAaIqB%AAaIqBEH%AAPBaIqB%PCDHxL%H@hIcBBI%E@qJBH#C@@D%aIBI@D%E@QB2P#E@'C@qJBHqJBH%C@qJBH%AAaIqBAI%C@cJ%cJCH%C@qJ%aIqB1I%PCDI`I%BAaICH%KH+@'JH+@KP*@%S@3P%H@ABhIaBBI%P@S@PC#", 14 | *j, *e; 15 | 16 | typedef float x; 17 | 18 | x U(x a) { return a<0?0:a>1?1:a; } 19 | 20 | typedef struct { x c,a,t; } y; 21 | 22 | y W={1,1,1}, Z={0,0,0}, B[99], P, C, M, N, K, p, s, d, h; 23 | 24 | y G(x t, x a, x c) { K.c=t; K.t=c; K.a=a; return K; } 25 | 26 | int T=-1, b=0, r, F=-111, (*m)(int) = putchar, X=40, z=5, o, a, c, t=0, n, R; 27 | 28 | y A(y a, y b, x c) { return G(a.c+b.c*c, a.a+c*b.a, b.t*c+a.t); } 29 | 30 | x H=.5, Y=.66, I, l=0, q, w, u, i, g; 31 | 32 | 33 | x O(y a, y b) { return q=a.t*b.t+b.c*a.c+a.a*b.a; } 34 | 35 | x Q() { 36 | return A(P,M,T), O(K,K)t+H*a ? o : w > t ? t : w1 ? 1[z=0, k] : J; *e && l<24; ++e) 73 | for (o=a=0, j=J+9; (c=*++j)&&!(o&&c2), 1 : 77 | (o = (a = (c-=X)<0 ? w=c+6, t=a+1 : c ? (t?0:m(c),a) : *++j) == 78 | ((*e|32)^z)) ); 79 | 80 | for (z=3*(L<3); ++F<110; ) 81 | 82 | for (L=-301;p=Z,++L<300;m(p.c),m(p.a),m(p.t)) 83 | 84 | for (c=T; ++c<=z;) 85 | 86 | for (h=G(-4,4.6,29), 87 | d=V( A( A( A(Z, V(G(5,0,2)), L+L+c/2 ), 88 | V(G(2,-73,0)), F+F+c%2), 89 | G(30.75,-6,-75), 90 | 20) ), 91 | g=R=255-(n=z)*64; R*n+R; g*=H) 92 | 93 | { 94 | 95 | for (u=i=R=0;!R&&94>(u+=i=D(h=A(h,d,i)));R=i<.01); 96 | 97 | for (N = V(A(P,C,T)), 98 | q = d.t*d.t, 99 | s = M, 100 | u=1; 101 | ++i<6*R; 102 | u -= U(i/3-D(A(h,N,i/3)))/pow(2,i)); 103 | 104 | s = R ? 105 | i = pow(U(O(N,V(A(M=V(G(T,1,2)),d,T)))),X), 106 | p = A(p, W, g*i), 107 | u *= U(O(N,M))*H*Y+Y, 108 | g *= n--?Y-Y*i:1-i, 109 | s 110 | : 111 | G(q, q, 1); 112 | 113 | p = A(p,s,g*u); 114 | h = A(h,N,.1); 115 | d = A(d,N,-2*O(d,N)); 116 | 117 | } 118 | 119 | 120 | return 0; 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/miniray_4.6.c: -------------------------------------------------------------------------------- 1 | // This file is identical to the final zucker.c entry, except for formatting. 2 | 3 | #include 4 | #include 5 | #define E return 6 | #define S for 7 | 8 | /* 9 | _abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 10 | iiivc fvfccfFiivfivif fttiFvvFPiFffcvivvFvFiPiFFvifv 11 | * * 12 | */ 13 | 14 | 15 | char* J = "LJFFF%7544x^H^XXHZZXHZ]]2#( #@@DA#(.@@%(0CAaIqDCI$IDEH%P@T@qL%PEaIpBJCAI%KBPBEP%CBPEaIqBAI%CAaIqBqDAI%U@PE%AAaIqBcDAI%ACaIaCqDCI%(aHCcIpBBH%E@aIqBAI%AAaIqB%AAaIqBEH%AAPBaIqB%PCDHxL%H@hIcBBI%E@qJBH#C@@D%aIBI@D%E@QB2P#E@'C@qJBHqJBH%C@qJBH%AAaIqBAI%C@cJ%cJCH%C@qJ%aIqB1I%PCDI`I%BAaICH%KH+@'JH+@KP*@%S@3P%H@ABhIaBBI%P@S@PC#", 16 | *j, *e; 17 | 18 | typedef float x; 19 | 20 | x U(x a) { return a<0?0:a>1?1:a; } 21 | 22 | typedef struct { x c,a,t; } y; 23 | 24 | y W={1,1,1}, Z={0,0,0}, B[99], P, C, M, N, K, p, s, d, h; 25 | 26 | y G(x t, x a, x c) { K.c=t; K.t=c; K.a=a; return K; } 27 | 28 | int T=-1, b=0, r, F=-111, (*m)(int) = putchar, X=40, z=5, o, a, c, t=0, n, R; 29 | 30 | y A(y a, y b, x c) { return G(a.c+b.c*c, a.a+c*b.a, b.t*c+a.t); } 31 | 32 | x H=.5, Y=.66, I, l=0, q, w, u, i, g; 33 | 34 | 35 | x O(y a, y b) { return q=a.t*b.t+b.c*a.c+a.a*b.a; } 36 | 37 | x Q() { 38 | return A(P,M,T), O(K,K)t+H*a ? o : w > t ? t : w1 ? 1[z=0, k] : J; *e && l<24; ++e) 75 | for (o=a=0, j=J+9; (c=*++j)&&!(o&&c2), 1 : 79 | (o = (a = (c-=X)<0 ? w=c+6, t=a+1 : c ? (t?0:m(c),a) : *++j) == 80 | ((*e|32)^z) && 1[j]-X) ); 81 | 82 | for (z=3*(L<3); ++F<110; ) 83 | 84 | for (L=-301;p=Z,++L<300;m(p.c),m(p.a),m(p.t)) 85 | 86 | for (c=T; ++c<=z;) 87 | 88 | for (h=G(-4,4.6,29), 89 | d=V( A( A( A(Z, V(G(5,0,2)), L+L+c/2 ), 90 | V(G(2,-73,0)), F+F+c%2), 91 | G(30.75,-6,-75), 92 | 20) ), 93 | g=R=255-(n=z)*64; R*n+R; g*=H) 94 | 95 | { 96 | 97 | for (u=i=R=0;!R&&94>(u+=i=D(h=A(h,d,i)));R=i<.01); 98 | 99 | for (N = V(A(P,C,T)), 100 | q = d.t*d.t, 101 | s = M, 102 | u=1; 103 | ++i<6*R; 104 | u -= U(i/3-D(A(h,N,i/3)))/pow(2,i)); 105 | 106 | s = R ? 107 | i = pow(U(O(N,V(A(M=V(G(T,1,2)),d,T)))),X), 108 | p = A(p, W, g*i), 109 | u *= U(O(N,M))*H*Y+Y, 110 | g *= n--?Y-Y*i:1-i, 111 | s 112 | : 113 | G(q, q, 1); 114 | 115 | p = A(p,s,g*u); 116 | h = A(h,N,.1); 117 | d = A(d,N,-2*O(d,N)); 118 | 119 | } 120 | 121 | 122 | return 0; 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/zucker.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define E return 4 | #define S for 5 | char*J="LJFFF%7544x^H^XXHZZXHZ]]2#( #@@DA#(.@@%(0CAaIqDCI$IDEH%P@T@qL%PEaIpBJCA\ 6 | I%KBPBEP%CBPEaIqBAI%CAaIqBqDAI%U@PE%AAaIqBcDAI%ACaIaCqDCI%(aHCcIpBBH%E@aIqBAI%A\ 7 | AaIqB%AAaIqBEH%AAPBaIqB%PCDHxL%H@hIcBBI%E@qJBH#C@@D%aIBI@D%E@QB2P#E@'C@qJBHqJBH\ 8 | %C@qJBH%AAaIqBAI%C@cJ%" "cJ" "CH%C@qJ%aIqB1I%PCDI`I%BAaICH%KH+@'JH+@KP*@%S@\ 9 | 3P%H@ABhIaBBI%P@S@PC#", *j ,*e;typedef float x;x U(x a){E a<0?0:a>1?1:a; } 10 | typedef struct{x c,a,t; } y;y W={1,1,1},Z={0,0,0},B[99],P,C,M,N,K,p,s,d,h 11 | ;y G(x t,x a,x c){K.c=t ; K.t=c; K.a=a;E K;}int T=-1,b=0,r,F=-111,(*m)(i\ 12 | nt)=putchar,X=40,z=5,o, a, c,t=0 ,n,R;y A(y a,y b,x c){E G(a.c+b.c*c,a.a 13 | +c*b.a,b.t*c+a.t);}x H= .5,Y =.66 ,I,l=0,q,w,u,i,g;x O(y a,y b){E q=a.t* 14 | b.t+b.c*a.c+a.a*b.a;}x Q(){E A(P,M,T ),O(K,K)t+H*a?o: w>t?t:w1?1[z= 0, k]:J ;*e &&l<24 ; 21 | ++e)S(o=a =0,j =J+9;(c= *++j)&& !(o&&c< X&&(q=l+=w) );o ?o=*j++/ 22 | 32,b++[B] =G(q +=*j/8&3,* j&7,0 ),B[r =b++]=G((c/8& 3)*( o<2? 23 | T:1), (c& 7)+ 1e-4,o>2),1: (o =(a =(c-=X)<0?w=c+6 ,t= a+1:c?(t 24 | ?0:m(c),a ):*++j)==((*e|32 ) ^z)&&1[j]-X));S(z =3*( L<3);++ 25 | F<110;)S(L=-301;p=Z,++L<300;m( p.c),m(p.a),m(p.t))S(c=T;++c<=z;)S(h 26 | =G(-4,4.6,29),d=V(A(A(A(Z,V(G(5,0 ,2)),L+L+c/2),V(G(2,-73,0)),F+F+c%2),G 27 | (30.75,-6,-75),20)),g=R=255-(n=z)*64; R*n+R;g*=H){S(u=i=R=0;!R&&94>(u+=i=D(h= 28 | A(h,d,i)));R=i<.01);S(N=V(A(P,C, T)),q=d.t*d.t,s=M,u=1;++i<6*R;u-= 29 | U(i/3-D(A(h,N,i/3)))/pow( 2,i));s=R?i=pow(U(O(N,V(A( 30 | M=V(G(T,1,2)),d,T)))) ,X),p=A(p,W,g*i),u*=U( 31 | O(N,M))*H*Y+Y,g*= n--?Y-Y*i:1-i,s:G( 32 | q,q,1); p=A(p,s ,g*u);h=A(h,N,.1 33 | );d=A(d,N,-2*O (d,N));}E 0;} 34 | --------------------------------------------------------------------------------