| 
		 After Width: | Height: | Size: 11 MiB  | 
| 
		 After Width: | Height: | Size: 336 KiB  | 
@ -0,0 +1,360 @@
 | 
				
			|||||||
 | 
					<script src=lib1.js></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					<center>
 | 
				
			||||||
 | 
					<canvas id='canvas1' width=600 height=600></canvas>
 | 
				
			||||||
 | 
					</center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_vertex_shader' type='x-shader/x-vertex'>
 | 
				
			||||||
 | 
					   attribute vec3 aPos;
 | 
				
			||||||
 | 
					   varying   vec3 vPos;
 | 
				
			||||||
 | 
					   void main() {
 | 
				
			||||||
 | 
					      gl_Position = vec4(aPos, 1.);
 | 
				
			||||||
 | 
					      vPos = aPos;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_fragment_shader' type='x-shader/x-fragment'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 uniform float uTime;   // TIME, IN SECONDS
 | 
				
			||||||
 | 
					 uniform int flags;
 | 
				
			||||||
 | 
					 varying vec3 vPos;     // -1 < vPos.x < +1
 | 
				
			||||||
 | 
					                        // -1 < vPos.y < +1
 | 
				
			||||||
 | 
					                        //      vPos.z == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform sampler2D uSampler;
 | 
				
			||||||
 | 
					 // YOU MUST DEFINE A main() FUNCTION.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 void main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 ////////////////////////////////////////////////
 | 
				
			||||||
 | 
					 //
 | 
				
			||||||
 | 
					 // HERE, FOR YOUR HOMEWORK, YOU CAN WRITE ANY
 | 
				
			||||||
 | 
					 // CODE YOU LIKE
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    //DEFINE A COLOR FOR THIS FRAGMENT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // LIGHT DIRECTION AND COLOR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vec3 LDir = vec3(1, 1, 1);
 | 
				
			||||||
 | 
					    vec3 LCol = vec3(1.,.98,.9);
 | 
				
			||||||
 | 
					    vec3 VDir = vec3(0., 0., 1.);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    float R = 0.5 + 0.3*sin(uTime/10.);
 | 
				
			||||||
 | 
					    // vPos IS THE 3D LOCATION OF THIS FRAGMENT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // SURFACE REFLECTANCE PROPERTIES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vec3 diffuse = vec3(.7,.7,.6);
 | 
				
			||||||
 | 
					    vec3 ambient = vec3(.1,.1,.09);
 | 
				
			||||||
 | 
					    vec3 specular = vec3(.35,.35,.3);
 | 
				
			||||||
 | 
					    // CREATE A WACKY BACKGROUND PATTERN.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    vec3 color = vec3(.5 + .5 * sin(20. * vPos.x + sin(10. * vPos.y + 5. * uTime)),
 | 
				
			||||||
 | 
					                      .5,
 | 
				
			||||||
 | 
					                      .5 + .5 * sin(20. * vPos.y + sin(10. * vPos.x + 5. * uTime)));
 | 
				
			||||||
 | 
					    vec3 specularlight; //specular light should disregard object color.
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					    float x = vPos.x;
 | 
				
			||||||
 | 
					    float y = vPos.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // CREATE BOUNCING ANIMATION.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    y += .5 - 2. * abs(.5 * sin(uTime));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // FIGURE OUT WHETHER THIS PIXEL IS ON THE SPHERE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    float rr = x * x + y * y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // IF SO, THEN SHADE THE SPHERE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rr < R*R) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       // COMPUTE THE z AND NORMAL OF THE SPHERE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       float z = R * sqrt(1. - rr/(R*R));
 | 
				
			||||||
 | 
					       vec3 N = vec3(x,y,z) / R;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       // APPLY SHADING AND LIGHTING.
 | 
				
			||||||
 | 
					       vec3 realVPos = vec3(vPos.x, vPos.y, z);
 | 
				
			||||||
 | 
					       //*DIRECTIONS ARE NORMALIZED TO GET THE CORRECT PHONG LIGHTING
 | 
				
			||||||
 | 
					       LDir = normalize(LDir - realVPos);
 | 
				
			||||||
 | 
					       VDir = normalize(VDir - realVPos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       vec3 lcolor = ambient;
 | 
				
			||||||
 | 
					       lcolor += diffuse * max(0., dot(N, LDir)) * LCol;
 | 
				
			||||||
 | 
					       //*SPECULAR LIGHTS ARE ADDED
 | 
				
			||||||
 | 
					       specularlight = specular * 
 | 
				
			||||||
 | 
					                  pow(max(0.,dot(2.*dot(N, LDir) * N - LDir, VDir)),3.) * LCol;
 | 
				
			||||||
 | 
					       // ROTATE THE TEXTURE OVER TIME.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					       float angle = 0.4 * uTime;
 | 
				
			||||||
 | 
					       float px =  cos(angle) * N.x + sin(angle) * N.z;
 | 
				
			||||||
 | 
					       float pz = -sin(angle) * N.x + cos(angle) * N.z;
 | 
				
			||||||
 | 
					       vec3 P = vec3(px, N.y, pz);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					       // APPLY PROCEDURAL NOISE TEXTURE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       float cloud = min(0.85, max(-0.05, 2. * noise(1.1 * P)));
 | 
				
			||||||
 | 
					       //const float rspeed = 10.;
 | 
				
			||||||
 | 
					      //*CALCULATING THE TEXTURE COORDINATE.
 | 
				
			||||||
 | 
					      const float pi = 3.14159265359;
 | 
				
			||||||
 | 
					      float tex_x = acos(abs(x)/sqrt(R*R-y*y));
 | 
				
			||||||
 | 
					      if(x > 0.)
 | 
				
			||||||
 | 
					         tex_x = pi - tex_x;
 | 
				
			||||||
 | 
					      tex_x = R * tex_x;
 | 
				
			||||||
 | 
					      tex_x *= 1.5708;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					      tex_x = tex_x + float(uTime)*R;
 | 
				
			||||||
 | 
					      float _2pir = 2. * pi * R;
 | 
				
			||||||
 | 
					      float quo = float(int(tex_x/_2pir));
 | 
				
			||||||
 | 
					      tex_x = (tex_x - quo * _2pir) / _2pir;
 | 
				
			||||||
 | 
					      //*TEXTURE MAPPING
 | 
				
			||||||
 | 
					      vec3 texture_color;
 | 
				
			||||||
 | 
					      if(flags /*& 0x1*/ == 0)
 | 
				
			||||||
 | 
					         texture_color = texture2D(uSampler, vec2(tex_x, ((R - y)/(2.*R)))).xyz;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         texture_color = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					      color = lcolor * 
 | 
				
			||||||
 | 
					            (cloud + texture_color) + specularlight;
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //*CALCULATING LIGHTING AND SHADOWS FOR THE BACKGROUND
 | 
				
			||||||
 | 
					    else{
 | 
				
			||||||
 | 
					      vec3 realVPos = vec3(vPos.x, vPos.y, -1.);
 | 
				
			||||||
 | 
					      vec3 N = vec3(0., 0., 1.);
 | 
				
			||||||
 | 
					      vec3 C = vec3(0., vPos.y - y, 0.);
 | 
				
			||||||
 | 
					      // APPLY SHADING AND LIGHTING.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      vec3 lcolor = 6.*ambient;
 | 
				
			||||||
 | 
					      //*CALCULATING DISTANCE BETWEEN SPHERE CENTER TO THE RAY 
 | 
				
			||||||
 | 
					       //BETWEEN THE POINT TO LIGHT SOURCE
 | 
				
			||||||
 | 
					      vec3 LV = realVPos - LDir;
 | 
				
			||||||
 | 
					      vec3 LC = C - LDir;
 | 
				
			||||||
 | 
					      vec3 VC = C - realVPos;
 | 
				
			||||||
 | 
					      float lLV = dot(LV, LV);
 | 
				
			||||||
 | 
					      float lLC = dot(LC, LC);
 | 
				
			||||||
 | 
					      float lVC = dot(VC, VC);
 | 
				
			||||||
 | 
					      float RR = R*R;
 | 
				
			||||||
 | 
					      float d_VCVL = -dot(VC, LV);
 | 
				
			||||||
 | 
					      float dist = min(lLC, lVC);
 | 
				
			||||||
 | 
					      if (d_VCVL > 0.)
 | 
				
			||||||
 | 
					         dist = min(dist, lVC - d_VCVL*d_VCVL/lLV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      //*CALCULATE DISTANCE BETWEEN SPHERE CENTER TO THE RAY BETWEEN POINT TO CAMERA
 | 
				
			||||||
 | 
					      vec3 EV = realVPos - VDir;
 | 
				
			||||||
 | 
					      vec3 EC = C - VDir;
 | 
				
			||||||
 | 
					      float lEV = dot(EV, EV);
 | 
				
			||||||
 | 
					      float lEC = dot(EC, EC);
 | 
				
			||||||
 | 
					      float d_VCVE = -dot(VC, EV);
 | 
				
			||||||
 | 
					      float dist2 = min(lEC, lVC);
 | 
				
			||||||
 | 
					      if (d_VCVE > 0.)
 | 
				
			||||||
 | 
					         dist2 = min(dist2, lVC - d_VCVE*d_VCVE/lEV);
 | 
				
			||||||
 | 
					      //*AMBIENT LIGHT WILL DECAY WHEN BACKGROUND POINT IS CLOSER TO THE SPHERE
 | 
				
			||||||
 | 
					      //*FIRST THE DISTANCE IS NORMALIZED, THEN I CURVED IT WITH LOGISTIC FUNCTION
 | 
				
			||||||
 | 
					      float aratio0 = 1./(1.+pow(2.71828,15.*(.2-(sqrt(lVC) - R - .4806)/1.381)));
 | 
				
			||||||
 | 
					      lcolor *= aratio0;
 | 
				
			||||||
 | 
					      diffuse *= pow(aratio0, 0.3);
 | 
				
			||||||
 | 
					      //*TEST IF CAMERA CAN SEE THE POINT
 | 
				
			||||||
 | 
					      if(dist2 < RR)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         specular *= 0.;
 | 
				
			||||||
 | 
					         float d = sqrt(dist2);
 | 
				
			||||||
 | 
					         float ratio = pow(2., sqrt(dist2)/R) - 1.;
 | 
				
			||||||
 | 
					         diffuse *= ratio;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      //*TEST IF THE LIGHT CAN REACH THE BACKGROUND POINT DIRECTLY
 | 
				
			||||||
 | 
					      if(dist < RR)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         specular *= 0.;
 | 
				
			||||||
 | 
					         float ratio = pow(2.7, sqrt(dist)/R) - 1.7;
 | 
				
			||||||
 | 
					         float aratio = pow(2., sqrt(dist)/R) - 1.;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         if(ratio < 0.)
 | 
				
			||||||
 | 
					            ratio = 0.;
 | 
				
			||||||
 | 
					         diffuse *= ratio;
 | 
				
			||||||
 | 
					         lcolor *= aratio;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      LDir = normalize(LDir - realVPos);
 | 
				
			||||||
 | 
					      VDir = normalize(VDir - realVPos); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      lcolor += 1.2*diffuse * max(0., dot(N, LDir)) * LCol;
 | 
				
			||||||
 | 
					      specularlight = 0.3*specular * 
 | 
				
			||||||
 | 
					            pow(max(0., dot(2.*dot(N, LDir) * N - LDir, VDir)),32.) * LCol;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      color = color * lcolor + specularlight;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // APPLY GAMMA CORRECTION AND SET THE PIXEL COLOR.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gl_FragColor = vec4(sqrt(color), 1.0);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- CREATE A PROPERLY DESCRIPTIVE TITLE BELOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_title' type='text/html'>
 | 
				
			||||||
 | 
					The Bouncing Earth
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- HERE IS WHERE YOU CAN PROVIDE A LONGER TEXT DESCRIPTION -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_instructions' type='text/html'><font color=#909090>
 | 
				
			||||||
 | 
					<p style="font-size:30px; ">This is a description 
 | 
				
			||||||
 | 
					of my cool homework 
 | 
				
			||||||
 | 
					that you are seeing now.</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					<i style="font-size:25px;">Here is how it works:</i>
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					   <li>First, I added <a href="http://planetpixelemporium.com/download/download.php?earthmap1k.jpg">texture</a> to the sphere. The code to load the texture is from 
 | 
				
			||||||
 | 
					      <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL">here</a>. Please wait a sec for the texture to download.</li>
 | 
				
			||||||
 | 
					   <li>Then, I mapped the 3D sphere surface to the rectangular 2D texture picture.  </li>
 | 
				
			||||||
 | 
					   <li>I also make it look like it's rotating by adding uTime to the offset of the texture and reset the offset to 0 whenever it exceeds
 | 
				
			||||||
 | 
					       the width of the texture.</li>
 | 
				
			||||||
 | 
					   <li>I used Perlin Noise to generate fake clouds.</li>
 | 
				
			||||||
 | 
					   <li> I modified the lighting so that the light source won't move with the sphere and 
 | 
				
			||||||
 | 
					      the lighting will change when the sphere moves. I also added specular lights to make it shinier.</li>
 | 
				
			||||||
 | 
					   <li> I tried to add some 'soft shadow' to it. I used a mix of methods inspired by Ambient Occlusion and Ray Tracing.<br>
 | 
				
			||||||
 | 
					      <ul>
 | 
				
			||||||
 | 
					         <li>The Ambient lights and diffusion lights are reduced with respect to the distance between the background point and the sphere.</li>
 | 
				
			||||||
 | 
					         <li>The specular light of the background wall is eliminated and the diffusion factor is reduced when the ray shooting from the background point 
 | 
				
			||||||
 | 
					         towards the light source or from the background point towards the camera position intersect with the sphere.</li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					   <li>I added basic interactions such as press ctrl + 't' key to hide/show texture, click on the above canvas to pause/unpause animations. 
 | 
				
			||||||
 | 
					      Just a proof of concept.</li>   
 | 
				
			||||||
 | 
					   <li>Finally, I made some small changes like changing R over time and refined the UI a little bit. I used 
 | 
				
			||||||
 | 
					      <a href="https://ace.c9.io">Ace</a> for code highlighting and autocompletion on the edit panel.</li>
 | 
				
			||||||
 | 
					   <li>Comments begin with '//*' are added by me.</li>
 | 
				
			||||||
 | 
					   <li>Repo on <a href="https://github.com/sunyinqi0508/graphics_hw1">Github</a>.</li>
 | 
				
			||||||
 | 
					   </li>
 | 
				
			||||||
 | 
					 </ul>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY DON'T WANT TO CHANGE ANYTHING BELOW FOR NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CREATE THE HTML DOCUMENT
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					let vs = my_vertex_shader.innerHTML,
 | 
				
			||||||
 | 
					    fs = my_fragment_shader.innerHTML;
 | 
				
			||||||
 | 
					    fs = fs.substring(1, fs.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.body.innerHTML = [''
 | 
				
			||||||
 | 
					   ,'<font size=7 color=#909090>' + my_title.innerHTML
 | 
				
			||||||
 | 
					   ,'<TABLE cellspacing=0 cellpadding=0><TR>'
 | 
				
			||||||
 | 
					   ,'<td><font color=red size=5><div id=errorMessage></div></font></td>'
 | 
				
			||||||
 | 
					   ,'</TR><TR>'
 | 
				
			||||||
 | 
					   ,'<table cellspacing=0>'
 | 
				
			||||||
 | 
					   ,'<tr>'
 | 
				
			||||||
 | 
					   ,'<td valign=top>'
 | 
				
			||||||
 | 
					   ,'<div id="ace" style="width:800px;height:1780px;"></div>'
 | 
				
			||||||
 | 
					   ,'</td><td valign=top>' + document.body.innerHTML  + '<div style=\'font-size:25px\'>' + my_instructions.innerHTML + '</div>' + '</td>'
 | 
				
			||||||
 | 
					   ,'</tr></table>'
 | 
				
			||||||
 | 
					   ,'</TR></TABLE>'
 | 
				
			||||||
 | 
					   ].join('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let text = fs.split('\n'), cols = 0;
 | 
				
			||||||
 | 
					for (let i = 0 ; i < text.length ; i++)
 | 
				
			||||||
 | 
					   cols = Math.max(cols, text[i].length);
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					   canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					let lastTime = Date.now();
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let ctrl = false;
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      lastTime = Date.now();
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					   animating = !animating;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   ctrl = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					else if(ctrl && e.code == 'KeyT')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)*mask);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// SET THE CURRENT TIME IN SECONDS BEFORE RENDERING EACH FRAME.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let startTime = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', (Date.now() - startTime) / 1000);
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', (lastTime - startTime) / 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// START EVERYTHING.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;         // IS THIS THE FIREFOX BROWSER?
 | 
				
			||||||
 | 
					let errorMsg = '';
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Initialize a texture and load an image.
 | 
				
			||||||
 | 
					// When the image finished loading copy it into the texture.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					function loadTexture(gl, url) {
 | 
				
			||||||
 | 
					   const texture = gl.createTexture();
 | 
				
			||||||
 | 
					   gl.bindTexture(gl.TEXTURE_2D, texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   // Because images have to be downloaded over the internet
 | 
				
			||||||
 | 
					   // they might take a moment until they are ready.
 | 
				
			||||||
 | 
					   // Until then put a single pixel in the texture so we can
 | 
				
			||||||
 | 
					   // use it immediately. When the image has finished downloading
 | 
				
			||||||
 | 
					   // we'll update the texture with the contents of the image.
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					   gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					      width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					      pixel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // WebGL1 has different requirements for power of 2 images
 | 
				
			||||||
 | 
					      // vs non power of 2 images so check if the image is a
 | 
				
			||||||
 | 
					      // power of 2 in both dimensions.
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         // Yes, it's a power of 2. Generate mips.
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         // No, it's not a power of 2. Turn off mips and set
 | 
				
			||||||
 | 
					         // wrapping to clamp to edge
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   return texture;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let gl = this.gl, program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = '<br>';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader + fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let texture = loadTexture(gl, './earthmap1k.jpg') //Texture loading.
 | 
				
			||||||
 | 
					         // Tell WebGL we want to affect texture unit 0
 | 
				
			||||||
 | 
					         gl.activeTexture(gl.TEXTURE0);
 | 
				
			||||||
 | 
					         // Bind the texture to texture unit 0
 | 
				
			||||||
 | 
					         gl.bindTexture(gl.TEXTURE_2D, texture);
 | 
				
			||||||
 | 
					         // Tell the shader we bound the texture to texture unit 0
 | 
				
			||||||
 | 
					         gl.uniform1i(gl.getUniformLocation(program, 'uSampler'), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					            [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 0, 0);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let gl;
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					   (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "version": "0.1.0",
 | 
				
			||||||
 | 
					    "configurations": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "Launch index.html",
 | 
				
			||||||
 | 
					            "type": "chrome",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "file": "${workspaceFolder}/index.html",
 | 
				
			||||||
 | 
					            "runtimeExecutable": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
 | 
				
			||||||
 | 
					            "runtimeArgs": ["--args", "--allow-file-access-from-files"]
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "windows",
 | 
				
			||||||
 | 
					            "type": "chrome",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "file": "${workspaceFolder}/index.html",
 | 
				
			||||||
 | 
					            "runtimeExecutable": "C:/Users/sunyi/AppData/Local/Google/Chrome SxS/Application/chrome.exe",
 | 
				
			||||||
 | 
					            "runtimeArgs": ["--args", "--allow-file-access-from-files"]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "python.pythonPath": "/usr/local/bin/python",
 | 
				
			||||||
 | 
					    "svg.preview.background": "black"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.7 KiB  | 
@ -0,0 +1,301 @@
 | 
				
			|||||||
 | 
					let lerp = (a,b,t) => a + t * (b - a); // LINEAR INTERPOLATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let N = 0; // GREATER N INCREASES "NERVOUSNESS" OF BIG OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TIMING TABLE FOR THE ANIMATION SEQUENCE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let timing = [
 | 
				
			||||||
 | 
					   [0, lerp(1,.5,N)],
 | 
				
			||||||
 | 
					   [1.8, lerp(2.3,2.1,N)], 
 | 
				
			||||||
 | 
					   [lerp(2,2.5,N), 2.8],
 | 
				
			||||||
 | 
					   [2.0, 3.2],
 | 
				
			||||||
 | 
					   [3.4, 3.9],
 | 
				
			||||||
 | 
					   [4.3, 5.0],
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EASE CURVE TO ACCELERATE FROM REST AND THEN DECELERATE TO REST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let sCurve = t => (3 - 2 * t) * t * t;
 | 
				
			||||||
 | 
					let jCurve =  t => t*t*t*t;
 | 
				
			||||||
 | 
					let jCurve3 = t => t*t*t;
 | 
				
			||||||
 | 
					// EVALUATE THE TIMING OF ONE ANIMATION PARAMETER FOR THIS FRAME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let evalTiming = n => {
 | 
				
			||||||
 | 
					   let t0 = timing[n][0];
 | 
				
			||||||
 | 
					   let t1 = timing[n][1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if (animationTime < t0)
 | 
				
			||||||
 | 
					      return 0;
 | 
				
			||||||
 | 
					   if (animationTime > t1)
 | 
				
			||||||
 | 
					      return 1;
 | 
				
			||||||
 | 
					   return sCurve((animationTime - t0) / (t1 - t0));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let bounce = t => Math.sin(Math.PI * t);
 | 
				
			||||||
 | 
					let wiggle = t => Math.sin(6 * Math.PI * t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let trees = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function add_tree(pos) {
 | 
				
			||||||
 | 
					    trees.append(new Float32Array(pos))
 | 
				
			||||||
 | 
					    createMesh(32,32,uvToCone,-1, 20);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class State {
 | 
				
			||||||
 | 
					    constructor(idx = 0, step = 1) {
 | 
				
			||||||
 | 
					        this.leg = true;
 | 
				
			||||||
 | 
					        this.progress = 0;
 | 
				
			||||||
 | 
					        this.rh = this.lh = .5 * pi;
 | 
				
			||||||
 | 
					        this.lf = this.rf = 0;
 | 
				
			||||||
 | 
					        this.running = 0;
 | 
				
			||||||
 | 
					        this.direction_l = [0, 0];
 | 
				
			||||||
 | 
					        this.dir_sdl = 0;
 | 
				
			||||||
 | 
					        this.delta_l = [0, 0];
 | 
				
			||||||
 | 
					        this.wiggle_t = 0;
 | 
				
			||||||
 | 
					        this.punch_t = 1;
 | 
				
			||||||
 | 
					        this.idx = idx;
 | 
				
			||||||
 | 
					        if(rebuild[idx] === undefined)
 | 
				
			||||||
 | 
					            rebuild.push(true);
 | 
				
			||||||
 | 
					        states[this.idx] = this;
 | 
				
			||||||
 | 
					        this.fig_rot_t = 0;
 | 
				
			||||||
 | 
					        this.figure_rot = pi;
 | 
				
			||||||
 | 
					        this.old_figure_rot = pi;
 | 
				
			||||||
 | 
					        this.curr_figure_rot = pi;
 | 
				
			||||||
 | 
					        this.target_figure_rot = pi;
 | 
				
			||||||
 | 
					        this.delta_height = 0;
 | 
				
			||||||
 | 
					        this.delta = const_multiply(step, [-.7*pi , 0.5 * pi, 0.44 * pi, 0.55 * pi]);
 | 
				
			||||||
 | 
					        this.stepSize = step;
 | 
				
			||||||
 | 
					        this.turnStep = .1;
 | 
				
			||||||
 | 
					        this.stepLength = this.stepSize*(1.8522);
 | 
				
			||||||
 | 
					        this.life = 3;
 | 
				
			||||||
 | 
					        this.damage = .05;
 | 
				
			||||||
 | 
					        this.dead = false;
 | 
				
			||||||
 | 
					        this.death_t = 0;
 | 
				
			||||||
 | 
					        this.hitID = 19;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    reset(){
 | 
				
			||||||
 | 
					        this.running = 0;    
 | 
				
			||||||
 | 
					        this.leg = true;
 | 
				
			||||||
 | 
					        this.progress = 0;
 | 
				
			||||||
 | 
					        this.delta_height = 0;
 | 
				
			||||||
 | 
					        this.dir_sdl = 0;
 | 
				
			||||||
 | 
					        this.rh = this.lh = .5 * pi;
 | 
				
			||||||
 | 
					        this.lf = this.rf = 0;
 | 
				
			||||||
 | 
					        this.dead = false;
 | 
				
			||||||
 | 
					        this.wiggle_t = 0;
 | 
				
			||||||
 | 
					        this.death_t = 0;        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    initialize() {
 | 
				
			||||||
 | 
					        this.figure_rot = pi;
 | 
				
			||||||
 | 
					        this.old_figure_rot = pi;
 | 
				
			||||||
 | 
					        this.curr_figure_rot = pi;
 | 
				
			||||||
 | 
					        this.target_figure_rot = pi;
 | 
				
			||||||
 | 
					        this.reset();
 | 
				
			||||||
 | 
					        this.wiggle_t = 0;
 | 
				
			||||||
 | 
					        this.punch_t = 1;
 | 
				
			||||||
 | 
					        this.fig_rot_t = 0;
 | 
				
			||||||
 | 
					        this.direction_l = [0, 0];
 | 
				
			||||||
 | 
					        this.delta_l = [0, 0];
 | 
				
			||||||
 | 
					        this.life = 3;
 | 
				
			||||||
 | 
					        this.delta_l = [0,0];
 | 
				
			||||||
 | 
					        this.direction_l = [0, 0];
 | 
				
			||||||
 | 
					        this.dir_sdl = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    set_stepSize(step){
 | 
				
			||||||
 | 
					        this.delta = const_multiply(step, [-.7*pi , 0.5 * pi, 0.44 * pi, 0.55 * pi]);
 | 
				
			||||||
 | 
					        this.stepSize = step;
 | 
				
			||||||
 | 
					        this.stepLength = this.stepSize*(1.8522);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    hitTest(punchProg){
 | 
				
			||||||
 | 
					        states.forEach((st, i)=>{
 | 
				
			||||||
 | 
					            if(i != this.idx){
 | 
				
			||||||
 | 
					                //1.15=.5*.23*10; .92 = .4*.23*10 .23=figure_scale, 10=overall_scale
 | 
				
			||||||
 | 
					                const armlength = 1.15*cos(punchProg*pi/4)+.92*cos(-.53*pi*punchProg)
 | 
				
			||||||
 | 
					                let dir = normalize(this.direction_l);
 | 
				
			||||||
 | 
					                let punchpos = plus(plus(this.delta_l, 
 | 
				
			||||||
 | 
					                    const_multiply(.3, [dir[1],-dir[0]])),
 | 
				
			||||||
 | 
					                    const_multiply(armlength, dir));
 | 
				
			||||||
 | 
					                if(vec_len(minus(punchpos, st.delta_l)) < .65){
 | 
				
			||||||
 | 
					                    st.hit(this);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    start_punch(){
 | 
				
			||||||
 | 
					        if(this.punch_t >= 1){
 | 
				
			||||||
 | 
					            this.punch_t = 0;
 | 
				
			||||||
 | 
					            rebuild[this.idx] = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    punch(){
 | 
				
			||||||
 | 
					        if(this.punch_t < 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            rebuild[this.idx] = true;
 | 
				
			||||||
 | 
					            this.punch_t+=.05;
 | 
				
			||||||
 | 
					            if(this.punch_t <= .05)
 | 
				
			||||||
 | 
					                return 1.2;
 | 
				
			||||||
 | 
					            else 
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                let punchProg;
 | 
				
			||||||
 | 
					                if(this.punch_t <= .4)
 | 
				
			||||||
 | 
					                    punchProg = 1.2*(1-jCurve((this.punch_t- .05)/.35));
 | 
				
			||||||
 | 
					                else 
 | 
				
			||||||
 | 
					                    punchProg = 1-jCurve(2-2*(this.punch_t+.1)/1.1);
 | 
				
			||||||
 | 
					                if(this.hitTest(punchProg))
 | 
				
			||||||
 | 
					                    this.punch_t = 1;
 | 
				
			||||||
 | 
					                return punchProg;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    restoreID(st){
 | 
				
			||||||
 | 
					        objects[st.idx].forEach(
 | 
				
			||||||
 | 
					            (obj, i)=>{
 | 
				
			||||||
 | 
					                changeID(st.orig_objid[i], obj[0]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    defaultHit(){
 | 
				
			||||||
 | 
					        if(objects[this.idx][0][0][0] != this.hitID){
 | 
				
			||||||
 | 
					            this.orig_objid = [];
 | 
				
			||||||
 | 
					            objects[this.idx].forEach(
 | 
				
			||||||
 | 
					                (obj, i) => {
 | 
				
			||||||
 | 
					                    this.orig_objid[i] = (obj[0])[0];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            objects[this.idx].forEach(
 | 
				
			||||||
 | 
					                (obj, i) => {
 | 
				
			||||||
 | 
					                    changeID(this.hitID, obj[0]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            setTimeout(this.restoreID, 100, this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(this.dead&&this.wiggle_t<=0){
 | 
				
			||||||
 | 
					            rebuild[this.idx] = true;
 | 
				
			||||||
 | 
					            this.wiggle_t = 2.5;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if(this.life > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.life -= this.damage;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            this.death();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    defaultDeath(){
 | 
				
			||||||
 | 
					        this.dead = true;
 | 
				
			||||||
 | 
					        this.death_t = 1;
 | 
				
			||||||
 | 
					        rebuild[this.idx] = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    hit(hitter){this.defaultHit(hitter);}
 | 
				
			||||||
 | 
					    death() {if(!this.dead){this.defaultDeath();}}
 | 
				
			||||||
 | 
					    animated_turn(){
 | 
				
			||||||
 | 
					        if(this.target_figure_rot != this.figure_rot)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					           this.fig_rot_t = 1;
 | 
				
			||||||
 | 
					           this.figure_rot %= 2*pi;
 | 
				
			||||||
 | 
					           if(this.figure_rot < 0) this.figure_rot += 2*pi;
 | 
				
			||||||
 | 
					           this.curr_figure_rot %= 2*pi;
 | 
				
			||||||
 | 
					           if(this.curr_figure_rot < 0) this.curr_figure_rot += 2*pi;
 | 
				
			||||||
 | 
					           if((this.curr_figure_rot - this.figure_rot) > pi)
 | 
				
			||||||
 | 
					              this.curr_figure_rot -= 2*pi;
 | 
				
			||||||
 | 
					           else if (this.curr_figure_rot - this.figure_rot < -pi)
 | 
				
			||||||
 | 
					              this.figure_rot -= 2*pi;
 | 
				
			||||||
 | 
					           this.old_figure_rot = this.curr_figure_rot;
 | 
				
			||||||
 | 
					           this.target_figure_rot = this.figure_rot;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(this.fig_rot_t > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					           this.fig_rot_t-=this.turnStep;
 | 
				
			||||||
 | 
					           this.curr_figure_rot = lerp(
 | 
				
			||||||
 | 
					              this.old_figure_rot, this.figure_rot, sCurve(1-this.fig_rot_t));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    turn(pt, animated = true){
 | 
				
			||||||
 | 
					        this.direction_l = [pt[0] - this.delta_l[0]/10, pt[1] - this.delta_l[1]/10];
 | 
				
			||||||
 | 
					        if(this.direction_l[1] == 0)
 | 
				
			||||||
 | 
					            this.direction_l[1] = 0.0000000000000001;
 | 
				
			||||||
 | 
					        this.figure_rot =  atan(this.direction_l[0]/this.direction_l[1]);
 | 
				
			||||||
 | 
					        if(this.direction_l[1] < 0)
 | 
				
			||||||
 | 
					            this.figure_rot = pi + this.figure_rot; 
 | 
				
			||||||
 | 
					        if(!animated)
 | 
				
			||||||
 | 
					        {    
 | 
				
			||||||
 | 
					            this.curr_figure_rot = this.target_figure_rot = this.figure_rot;
 | 
				
			||||||
 | 
					            this.fig_rot_t = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    walk(){
 | 
				
			||||||
 | 
					        this.dir_sdl = vec_len(this.direction_l)*10;
 | 
				
			||||||
 | 
					        this.direction_l = normalize(this.direction_l);
 | 
				
			||||||
 | 
					        rebuild[this.idx] = true;
 | 
				
			||||||
 | 
					        this.running = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    next() {
 | 
				
			||||||
 | 
					       //return this.presentation();
 | 
				
			||||||
 | 
					       if (this.running <= 0)
 | 
				
			||||||
 | 
					       {   
 | 
				
			||||||
 | 
					            this.reset();
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                rh: .5 * pi,
 | 
				
			||||||
 | 
					                lh: .5 * pi,
 | 
				
			||||||
 | 
					                rf: 0,
 | 
				
			||||||
 | 
					                lf: 0,
 | 
				
			||||||
 | 
					                dh: 0,
 | 
				
			||||||
 | 
					                dl: 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					       this.running--;
 | 
				
			||||||
 | 
					       const steps = 28;
 | 
				
			||||||
 | 
					       let dl = 0;
 | 
				
			||||||
 | 
					       if (this.progress >= steps / 2) {
 | 
				
			||||||
 | 
					          this.progress = 0;
 | 
				
			||||||
 | 
					          this.leg = !this.leg;
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       let delta = deepcopy(this.delta);
 | 
				
			||||||
 | 
					       for (let i = 0; i < 4; ++i) delta[i] /= steps;
 | 
				
			||||||
 | 
					       if (this.leg) {
 | 
				
			||||||
 | 
					          if (this.progress < steps / 4) {
 | 
				
			||||||
 | 
					             this.lh += delta[0];
 | 
				
			||||||
 | 
					             this.rh += delta[3];
 | 
				
			||||||
 | 
					             this.lf += delta[1];
 | 
				
			||||||
 | 
					             this.rf += delta[2];
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					             this.lh -= delta[0];
 | 
				
			||||||
 | 
					             this.rh -= delta[3];
 | 
				
			||||||
 | 
					             this.lf -= delta[1];
 | 
				
			||||||
 | 
					             this.rf -= delta[2];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					       } else {
 | 
				
			||||||
 | 
					          if (this.progress < steps / 4) {
 | 
				
			||||||
 | 
					             this.lh += delta[3];
 | 
				
			||||||
 | 
					             this.rh += delta[0];
 | 
				
			||||||
 | 
					             this.lf += delta[2];
 | 
				
			||||||
 | 
					             this.rf += delta[1];
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					             this.lh -= delta[3];
 | 
				
			||||||
 | 
					             this.rh -= delta[0];
 | 
				
			||||||
 | 
					             this.lf -= delta[2];
 | 
				
			||||||
 | 
					             this.rf -= delta[1];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       let delta_h = Math.max((1 - cos(abs(this.lh - pi / 2))) * .5 + (1 - cos(abs(this.lf))) * .6, (1 - cos(abs(this.rh - pi / 2))) * .5 + (1 - cos(abs(this.rf))) * .6);
 | 
				
			||||||
 | 
					       this.progress++;
 | 
				
			||||||
 | 
					       return {
 | 
				
			||||||
 | 
					          lh: this.lh,
 | 
				
			||||||
 | 
					          lf: this.lf,
 | 
				
			||||||
 | 
					          rh: this.rh,
 | 
				
			||||||
 | 
					          rf: this.rf,
 | 
				
			||||||
 | 
					          dh: delta_h,
 | 
				
			||||||
 | 
					          dl: this.stepLength / steps
 | 
				
			||||||
 | 
					       };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    presentation(){
 | 
				
			||||||
 | 
					       return {lh:.4*pi, lf:pi/6,rh:.7*pi, rf:pi/8, dh:0, dl: 0};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function update_tree(idx){
 | 
				
			||||||
 | 
					    //scale, add leaves, add branch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,105 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//------ CREATING MESH SHAPES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CREATE A MESH FROM A PARAMETRIC FUNCTION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createMesh = (nu, nv, f, data) => {
 | 
				
			||||||
 | 
					   let tmp = [];
 | 
				
			||||||
 | 
					   for (let v = 0 ; v < 1 ; v += 1/nv) {
 | 
				
			||||||
 | 
					      for (let u = 0 ; u <= 1 ; u += 1/nu) {
 | 
				
			||||||
 | 
					         tmp = tmp.concat(f(u,v,data));
 | 
				
			||||||
 | 
					         tmp = tmp.concat(f(u,v+1/nv,data));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      tmp = tmp.concat(f(1,v,data));
 | 
				
			||||||
 | 
					      tmp = tmp.concat(f(0,v+1/nv,data));
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return new Float32Array(tmp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GLUE TWO MESHES TOGETHER INTO A SINGLE MESH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let glueMeshes = (a, b) => {
 | 
				
			||||||
 | 
					   let c = [];
 | 
				
			||||||
 | 
					   for (let i = 0 ; i < a.length ; i++)
 | 
				
			||||||
 | 
					      c.push(a[i]);                           // a
 | 
				
			||||||
 | 
					   for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					      c.push(a[a.length - VERTEX_SIZE + i]);  // + last vertex of a
 | 
				
			||||||
 | 
					   for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					      c.push(b[i]);                           // + first vertex of b
 | 
				
			||||||
 | 
					   for (let i = 0 ; i < b.length ; i++)
 | 
				
			||||||
 | 
					      c.push(b[i]);                           // + b
 | 
				
			||||||
 | 
					   return new Float32Array(c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createSquareMesh = (i, z) => {
 | 
				
			||||||
 | 
					   let m = [], n = 6, j = z < 0 ? (i + 2) % 3 : (i + 1) % 3,
 | 
				
			||||||
 | 
					                      k = z < 0 ? (i + 1) % 3 : (i + 2) % 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   m[i] = m[1*n+i] = m[2*n+i] = m[3*n+i] =  z;
 | 
				
			||||||
 | 
					   m[j] = m[2*n+j] = m[2*n+k] = m[3*n+k] = -1;
 | 
				
			||||||
 | 
					   m[k] = m[1*n+j] = m[1*n+k] = m[3*n+j] =  1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   m[3+i] = m[1*n+3+i] = m[2*n+3+i] = m[3*n+3+i] = z < 0 ? -1 : 1;
 | 
				
			||||||
 | 
					   m[3+j] = m[1*n+3+j] = m[2*n+3+j] = m[3*n+3+j] = 0;
 | 
				
			||||||
 | 
					   m[3+k] = m[1*n+3+k] = m[2*n+3+k] = m[3*n+3+k] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   return new Float32Array(m);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let squareMesh = createSquareMesh(2, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let cubeMesh = glueMeshes(
 | 
				
			||||||
 | 
					               glueMeshes(glueMeshes(createSquareMesh(0,-1),createSquareMesh(0,1)),
 | 
				
			||||||
 | 
					                          glueMeshes(createSquareMesh(1,-1),createSquareMesh(1,1))),
 | 
				
			||||||
 | 
					                          glueMeshes(createSquareMesh(2,-1),createSquareMesh(2,1)) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToTorus = (u,v,r) => {
 | 
				
			||||||
 | 
					   let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					   let phi   = 2 * Math.PI * v;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   let x = Math.cos(theta) * (1 + r * Math.cos(phi));
 | 
				
			||||||
 | 
					   let y = Math.sin(theta) * (1 + r * Math.cos(phi));
 | 
				
			||||||
 | 
					   let z = r * Math.sin(phi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   let nx = Math.cos(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					   let ny = Math.sin(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					   let nz = Math.sin(phi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   return [x,y,z, nx,ny,nz];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToSphere = (u,v) => {
 | 
				
			||||||
 | 
					   let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					   let phi   = Math.PI * (v - .5);
 | 
				
			||||||
 | 
					   let x = Math.cos(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					   let y = Math.sin(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					   let z = Math.sin(phi);
 | 
				
			||||||
 | 
					   return [x,y,z, x,y,z];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToTube = (u,v) => {
 | 
				
			||||||
 | 
					   let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					   let x = Math.cos(theta);
 | 
				
			||||||
 | 
					   let y = Math.sin(theta);
 | 
				
			||||||
 | 
					   let z = 2 * v - 1;
 | 
				
			||||||
 | 
					   return [x,y,z, x,y,0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToDisk = (u,v,dz) => {
 | 
				
			||||||
 | 
					   if (dz === undefined)
 | 
				
			||||||
 | 
					      dz = 0;
 | 
				
			||||||
 | 
					   let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					   let x = Math.cos(theta) * v;
 | 
				
			||||||
 | 
					   let y = Math.sin(theta) * v;
 | 
				
			||||||
 | 
					   let z = dz;
 | 
				
			||||||
 | 
					   return [x,y,z, 0,0,dz ? Math.sign(dz) : 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let torusMesh    = createMesh(32, 16, uvToTorus, .5);
 | 
				
			||||||
 | 
					let sphereMesh   = createMesh(32, 16, uvToSphere);
 | 
				
			||||||
 | 
					let tubeMesh     = createMesh(32, 2, uvToTube);
 | 
				
			||||||
 | 
					let diskMesh     = createMesh(32, 2, uvToDisk);
 | 
				
			||||||
 | 
					let diskNMesh    = createMesh(32, 2, uvToDisk, -1);
 | 
				
			||||||
 | 
					let diskPMesh    = createMesh(32, 2, uvToDisk,  1);
 | 
				
			||||||
 | 
					let cylinderMesh = glueMeshes(glueMeshes(tubeMesh, diskPMesh), diskNMesh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,201 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					function implicitSurfaceTriangleMesh(implicitFunction, n, args, id = 8) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   // HERE IS WHERE MOST OF THE WORK HAPPENS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   let marchingTetrahedra = function(V, ni, nj) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // CONVENIENCE FUNCTIONS TO COMPUTE (i,j,k) FROM VOLUME INDEX n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function n2i(n) { return  n             % ni; }
 | 
				
			||||||
 | 
					      function n2j(n) { return (n / dj >>> 0) % nj; }
 | 
				
			||||||
 | 
					      function n2k(n) { return  n / dk >>> 0      ; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // ADD A VERTEX, AND RETURN A UNIQUE ID FOR THAT VERTEX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function E(a, b) {
 | 
				
			||||||
 | 
					         if (a > b) { let tmp = a; a = b; b = tmp; }
 | 
				
			||||||
 | 
					         let ai = n2i(a), aj = n2j(a), ak = n2k(a),
 | 
				
			||||||
 | 
					             bi = n2i(b), bj = n2j(b), bk = n2k(b);
 | 
				
			||||||
 | 
					         let m = (n << 6) + (ai & bi ?  1 << 6 : ai      | bi << 3)
 | 
				
			||||||
 | 
					                          + (aj & bj ? dj << 6 : aj << 1 | bj << 4)
 | 
				
			||||||
 | 
					                          + (ak & bk ? dk << 6 : ak << 2 | bk << 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         // ADD TO VERTEX ARRAY ONLY THE FIRST TIME THE VERTEX IS ENCOUNTERED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         if (vertexID[m] === undefined) {
 | 
				
			||||||
 | 
					            vertexID[m] = P.length / 3;
 | 
				
			||||||
 | 
					            let t = -V[n+a] / (V[n+b] - V[n+a]),
 | 
				
			||||||
 | 
					                c = function(i,a,b) { return (i + (1-t)*a + t*b) / ni * 2 - 1; };
 | 
				
			||||||
 | 
					            P.push( c(i,ai,bi), c(j,aj,bj), c(k,ak,bk) );
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         return vertexID[m];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // CASE WHERE WE ADD ONE TRIANGLE IN A TETRAHEDRON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function tri(a, b, c, d) {
 | 
				
			||||||
 | 
					         T.push(E(a,b), E(a,c), E(a,d));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // CASE WHERE WE ADD TWO TRIANGLES IN A TETRAHEDRON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function quad(a, b, c, d) {
 | 
				
			||||||
 | 
					         let ac = E(a,c), bc = E(b,c), ad = E(a,d), bd = E(b,d);
 | 
				
			||||||
 | 
					         T.push(bc, ac, ad);
 | 
				
			||||||
 | 
					         T.push(ad, bd, bc);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // DECLARE VARIABLES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let nk = V.length / (ni * nj), di = 1, dj = ni, dk = ni * nj;
 | 
				
			||||||
 | 
					      let dij = di + dj, dik = di + dk, djk = dj + dk, dijk = di + dj + dk;
 | 
				
			||||||
 | 
					      let P = [], T = [], vertexID = [], i, j, k, m = 0, n, S = [0,di,dij,dijk];
 | 
				
			||||||
 | 
					      let lo = new Array(nj * nk),
 | 
				
			||||||
 | 
					          hi = new Array(nj * nk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // THE SIX POSSIBLE INTERMEDIATE PATHS THROUGH A TETRAHEDRON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let S1 = [di , dj , dk , di , dj , dk ];
 | 
				
			||||||
 | 
					      let S2 = [dij, djk, dik, dik, dij, djk];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // THERE ARE 16 CASES TO CONSIDER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let cases = [ [0         ], [1, 0,1,2,3], [1, 1,2,0,3], [2, 0,1,2,3],
 | 
				
			||||||
 | 
					                    [1, 2,3,0,1], [2, 0,2,3,1], [2, 1,2,0,3], [1, 3,1,2,0],
 | 
				
			||||||
 | 
					                    [1, 3,0,2,1], [2, 0,3,1,2], [2, 1,3,2,0], [1, 2,1,0,3],
 | 
				
			||||||
 | 
					                    [2, 2,3,0,1], [1, 1,3,0,2], [1, 0,3,2,1], [0         ], ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // FOR EACH (Y,Z), DON'T DO ANY WORK OUTSIDE OF X RANGE WHERE SURFACE MIGHT BE
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      for (k = 0 ; k < nk ; k++)
 | 
				
			||||||
 | 
					         for (j = 0 ; j < nj ; j++, m++) {
 | 
				
			||||||
 | 
					            let n0 = m * ni, n1 = n0 + ni - 1;
 | 
				
			||||||
 | 
					            for (n = n0 ; n <= n1 && V[n] > 0 ; n++) ;
 | 
				
			||||||
 | 
					            lo[m] = Math.max(0, n-1 - n0);
 | 
				
			||||||
 | 
					            for (n = n1 ; n >= n0 && V[n] > 0 ; --n) ;
 | 
				
			||||||
 | 
					            hi[m] = Math.min(ni-1, n+1 - n0);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // FOR ALL Y AND Z IN THE VOLUME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (k = 0 ; k < nk - 1 ; k++) {
 | 
				
			||||||
 | 
					         let i0, i1, m = k * nj, n1, s0, s1;
 | 
				
			||||||
 | 
					         for (j = 0 ; j < nj - 1 ; j++, m++) {
 | 
				
			||||||
 | 
					            i0 = Math.min(lo[m], lo[m+1], lo[m+ni], lo[m+1+ni]);
 | 
				
			||||||
 | 
					            i1 = Math.max(hi[m], hi[m+1], hi[m+ni], hi[m+1+ni]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    // GO THROUGH RANGE OF X WHERE THE SURFACE MIGHT BE (IE: WITH ANY POSITIVE VALUES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (i0 <= i1) {
 | 
				
			||||||
 | 
					               n  = m * ni + i0;
 | 
				
			||||||
 | 
					               n1 = m * ni + i1;
 | 
				
			||||||
 | 
					               s0 = (V[n]>0) + (V[n+dj]>0) + (V[n+dk]>0) + (V[n+djk]>0);
 | 
				
			||||||
 | 
					               for (i = i0 ; n <= n1 ; i++, n++, s0 = s1) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  // FOR EACH CUBE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  s1 = (V[n+di]>0) + (V[n+dij]>0) + (V[n+dik]>0) + (V[n+dijk]>0);
 | 
				
			||||||
 | 
					                  if (s0 + s1 & 7) {
 | 
				
			||||||
 | 
					                     let C14 = (V[n] > 0) | (V[n+dijk] > 0) << 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							     // CYCLE THROUGH THE SIX TETRAHEDRA THAT TILE THE CUBE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                     for (let p = 0 ; p < 6 ; p++) {
 | 
				
			||||||
 | 
					                        let C = cases [ C14 | (V[n+S1[p]] > 0) << 1 | (V[n+S2[p]] > 0) << 2 ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// FOR EACH TETRAHEDRON, OUTPUT EITHER ZERO, ONE OR TWO TRIANGLES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (C[0]) {       // C[0] == number of triangles to be created.
 | 
				
			||||||
 | 
					                           S[1] = S1[p];  // assign 2nd and 3rd corners of simplex.
 | 
				
			||||||
 | 
					                           S[2] = S2[p];
 | 
				
			||||||
 | 
					                           (C[0]==1 ? tri : quad)(S[C[1]], S[C[2]], S[C[3]], S[C[4]]);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // MAKE SURE ALL TRIANGLE VERTICES ARE LISTED IN COUNTERCLOCKWISE ORDER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let m = 0 ; m < T.length ; m += 3) {
 | 
				
			||||||
 | 
					         let a = 3 * T[m], b = 3 * T[m+1], c = 3 * T[m+2],
 | 
				
			||||||
 | 
					             n = Math.floor(ni*(P[a  ]+1)/2)      +
 | 
				
			||||||
 | 
						         Math.floor(ni*(P[a+1]+1)/2) * dj +
 | 
				
			||||||
 | 
							 Math.floor(ni*(P[a+2]+1)/2) * dk,
 | 
				
			||||||
 | 
					             u = cross([P[b] - P[a], P[b+1] - P[a+1], P[b+2] - P[a+2]],
 | 
				
			||||||
 | 
					                       [P[c] - P[b], P[c+1] - P[b+1], P[c+2] - P[b+2]]),
 | 
				
			||||||
 | 
					             v = [ V[n+1] - V[n], V[n+dj] - V[n], V[n+dk] - V[n] ];
 | 
				
			||||||
 | 
					         if (dot(u, v) < 0) { let tmp = T[m]; T[m] = T[m + 2]; T[m + 2] = tmp; }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // RETURN POINTS AND TRIANGLES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return [P, T];
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   // SAMPLE THE VOLUME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   let F = i => (i - n/2) / (n/2);
 | 
				
			||||||
 | 
					   let volume = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for (let k = 0 ; k < n ; k++)
 | 
				
			||||||
 | 
					   for (let j = 0 ; j < n ; j++)
 | 
				
			||||||
 | 
					   for (let i = 0 ; i < n ; i++)
 | 
				
			||||||
 | 
					      volume.push(implicitFunction(F(i), F(j), F(k), args));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   // FIND ALL VERTICES AND TRIANGLES IN THE VOLUME
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   let VT = marchingTetrahedra(volume, n, n);
 | 
				
			||||||
 | 
					   let V = VT[0];
 | 
				
			||||||
 | 
					   let T = VT[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   // COMPUTE SURFACE NORMALS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   let N = new Array(V.length);
 | 
				
			||||||
 | 
					   for (let i = 0 ; i < V.length ; i += 3) {
 | 
				
			||||||
 | 
					      let x = V[i], y = V[i+1], z = V[i+2], e = .001,
 | 
				
			||||||
 | 
					          f0 = implicitFunction(x  ,y  ,z  , args),
 | 
				
			||||||
 | 
					          fx = implicitFunction(x+e,y  ,z  , args),
 | 
				
			||||||
 | 
					          fy = implicitFunction(x  ,y+e,z  , args),
 | 
				
			||||||
 | 
					          fz = implicitFunction(x  ,y  ,z+e, args),
 | 
				
			||||||
 | 
					          normal = normalize([f0-fx,f0-fy,f0-fz]);
 | 
				
			||||||
 | 
					      for (let j = 0 ; j < 3 ; j++)
 | 
				
			||||||
 | 
					         N[i+j] = normal[j];
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   // CONSTRUCT AND RETURN THE TRIANGLES MESH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   let mesh = [];
 | 
				
			||||||
 | 
					   for (let i = 0; i < T.length; i += 3) {
 | 
				
			||||||
 | 
					      let a = 3 * T[i    ],
 | 
				
			||||||
 | 
					          b = 3 * T[i + 1],
 | 
				
			||||||
 | 
						  c = 3 * T[i + 2];
 | 
				
			||||||
 | 
					      mesh.push( id, V[a],V[a+1],V[a+2] , N[a],N[a+1],N[a+2] ,
 | 
				
			||||||
 | 
					                 id, V[b],V[b+1],V[b+2] , N[b],N[b+1],N[b+2] ,
 | 
				
			||||||
 | 
					                 id, V[c],V[c+1],V[c+2] , N[c],N[c+1],N[c+2] );
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return new Float32Array(mesh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let blob = (center, radius, x, y, z) => {
 | 
				
			||||||
 | 
					   x -= center[0];
 | 
				
			||||||
 | 
					   y -= center[1];
 | 
				
			||||||
 | 
					   z -= center[2];
 | 
				
			||||||
 | 
					   return Math.max(0, 1 - .16 * (x*x + y*y + z*z) / (radius * radius));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var implicitFunction = (x,y,z,args) => {
 | 
				
			||||||
 | 
					   let ret = -.5;
 | 
				
			||||||
 | 
					   let x4 = _x => _x*_x*_x*_x;
 | 
				
			||||||
 | 
					   args.forEach((paras, _)=>{
 | 
				
			||||||
 | 
					      const center = paras[0],
 | 
				
			||||||
 | 
					            radius = paras[1];
 | 
				
			||||||
 | 
					      ret += x4(blob(center, radius, x, y, z));
 | 
				
			||||||
 | 
					   });
 | 
				
			||||||
 | 
					   return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src=lib10.header.js></script>
 | 
				
			||||||
 | 
					<script src=animation.js></script>
 | 
				
			||||||
 | 
					<script src=implicitSurface.js></script>
 | 
				
			||||||
 | 
					<script src=lib10.js></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<font size=7 color=#909090>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Pikachu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>
 | 
				
			||||||
 | 
					<TABLE cellspacing=0 cellpadding=0 style="width:50%"><TR>
 | 
				
			||||||
 | 
					<td><font color=red size=5><div id=errorMessage></div></font></td>
 | 
				
			||||||
 | 
					</TR><TR>
 | 
				
			||||||
 | 
					<table cellspacing=0>
 | 
				
			||||||
 | 
					<tr>
 | 
				
			||||||
 | 
					<td valign=top>
 | 
				
			||||||
 | 
					<div id="ace" style="opacity:90%;width:300px;height:700px;"hidden=true></div>
 | 
				
			||||||
 | 
					<div id = 'usage' style="opacity:90%;width:300px;height:700px;">
 | 
				
			||||||
 | 
					      <font color=#000000>
 | 
				
			||||||
 | 
					      <i style="font-size:28px;">What's new: </i>
 | 
				
			||||||
 | 
					      <ul style="font-size:24px;">
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					      <p style="font-size:24px;"> 
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					</td><td valign=top style="background-color:azure;opacity: 100%;">
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					   <center>
 | 
				
			||||||
 | 
					      <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					   <canvas id='canvas1' style=" background-color:#333333;opacity: 100%;overflow: hidden !important; width: 600px !important; height:600px !important;" width=1199 height=1199></canvas>
 | 
				
			||||||
 | 
					   </center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					<div id="controls">
 | 
				
			||||||
 | 
					<input type="number" id="ins" style="display:none;margin-left:0px;font-size:24px;width:35px;height:45px" value="5" max="5" min = "1">
 | 
				
			||||||
 | 
					<button id="bns" style="display:none;margin-left:0px;font-size:24px;width:105px;height:45px">Spheres</button>
 | 
				
			||||||
 | 
					<input type="number" id="insamp" style="margin-left:2px;font-size:24px;width:60px;height:45px" value="2" max="10" min = "0.1" step="0.2">
 | 
				
			||||||
 | 
					<button id="bnsamp" style="margin-left:0px;font-size:24px;width:190px;height:45px">Super Sampling</button>
 | 
				
			||||||
 | 
					<button id="bnfs" style="margin-left:2px;font-size:24px;width:180px;height:45px">Fullscreen</button>
 | 
				
			||||||
 | 
					<button id="clrsel" style="display:none;margin-left:0px;font-size:24px;width:180px;height:45px">Clear Selection</button>
 | 
				
			||||||
 | 
					<button id="reset" style="margin-left:0px;font-size:24px;width:100px;height:45px">Reset</button>
 | 
				
			||||||
 | 
					<button id="mov" style="margin-left:0px;font-size:24px;width:180px;height:45px">Move Lighting</button>
 | 
				
			||||||
 | 
					<button id="pause" style="margin-left:0px;font-size:24px;width:100px;height:45px">Pause</button>
 | 
				
			||||||
 | 
					<div style='font-size:25px;'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <!-- <font color=#000000>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					   <i style="font-size:28px;">What's new: </i>
 | 
				
			||||||
 | 
					   <p style="font-size:24px;"> 
 | 
				
			||||||
 | 
					   </p> -->
 | 
				
			||||||
 | 
					   <div id="howitworks">
 | 
				
			||||||
 | 
					   </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div></td>
 | 
				
			||||||
 | 
					</tr></table>
 | 
				
			||||||
 | 
					</TR></TABLE>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script src="lib10.ext.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					   setInterval(() => {
 | 
				
			||||||
 | 
					      if(window.vs != null && window.fs != null&& canvas1.setShaders === undefined)
 | 
				
			||||||
 | 
					         gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					   }, 200);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -0,0 +1,809 @@
 | 
				
			|||||||
 | 
					//Header file, contains global variable definitions, 
 | 
				
			||||||
 | 
					// asynchronized shader loading and utility functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mousedx = 0,
 | 
				
			||||||
 | 
					    mousedy = 0,
 | 
				
			||||||
 | 
					    mousedz = 0;
 | 
				
			||||||
 | 
					let seldx = 0,
 | 
				
			||||||
 | 
					    seldy = 0,
 | 
				
			||||||
 | 
					    seldz = 0;
 | 
				
			||||||
 | 
					var enableSelection = false;
 | 
				
			||||||
 | 
					var cx = 1,
 | 
				
			||||||
 | 
					    cy = 1,
 | 
				
			||||||
 | 
					    sx = 0,
 | 
				
			||||||
 | 
					    sy = 0,
 | 
				
			||||||
 | 
					    shaders = [];
 | 
				
			||||||
 | 
					var mouselastX, mouselastY
 | 
				
			||||||
 | 
					    ;
 | 
				
			||||||
 | 
					var fl = 3;
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					var vs, fs;
 | 
				
			||||||
 | 
					var bezierMat = [-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0],
 | 
				
			||||||
 | 
					    hermiteMat = [2, -3, 0, 1, -2, 3, 0, 0, 1, -2, 1, 0, 1, -1, 0, 0],
 | 
				
			||||||
 | 
					    catmullRomMat = [-.5, 1, -.5, 0, 1.5, -2.5, 0, 1, -1.5, 2, .5, 0, .5, -.5, 0, 0];
 | 
				
			||||||
 | 
					var starColors = [0.9921, 0.5378, 0.7109,
 | 
				
			||||||
 | 
					        0.65, 0.56, 0.992,
 | 
				
			||||||
 | 
					        0.992, 0.7994, 0.2402,
 | 
				
			||||||
 | 
					        0.1760, 0.5094, 0.5378,
 | 
				
			||||||
 | 
					        .1164, .1274, .2289,
 | 
				
			||||||
 | 
					        .9784, .71, .4482,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    n_shapes = starColors.length / 3;
 | 
				
			||||||
 | 
					var editor = undefined
 | 
				
			||||||
 | 
					var cos = Math.cos,
 | 
				
			||||||
 | 
					    sin = Math.sin,
 | 
				
			||||||
 | 
					    tan = Math.tan,
 | 
				
			||||||
 | 
					    acos = Math.acos,
 | 
				
			||||||
 | 
					    asin = Math.asin,
 | 
				
			||||||
 | 
					    atan = Math.atan,
 | 
				
			||||||
 | 
					    sqrt = Math.sqrt,
 | 
				
			||||||
 | 
					    pi = Math.PI,
 | 
				
			||||||
 | 
					    abs = Math.abs,
 | 
				
			||||||
 | 
					    pow = Math.pow,
 | 
				
			||||||
 | 
					    log = Math.log;
 | 
				
			||||||
 | 
					var positionsupdated = true;
 | 
				
			||||||
 | 
					var paths = [],
 | 
				
			||||||
 | 
					    origpath = [],
 | 
				
			||||||
 | 
					    path_misc = [];
 | 
				
			||||||
 | 
					var canvas_controls = [];
 | 
				
			||||||
 | 
					var states = [];
 | 
				
			||||||
 | 
					function deepcopy(obj) {
 | 
				
			||||||
 | 
					    return JSON.parse(JSON.stringify(obj));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let vsfetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					vsfetch.open('GET', './shader.vert');
 | 
				
			||||||
 | 
					vsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    vs = vsfetch.responseText;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					vsfetch.send();
 | 
				
			||||||
 | 
					//* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					let fsfetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					fsfetch.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					fsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    fs = (fsfetch.responseText);
 | 
				
			||||||
 | 
					    //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					    if (editor != undefined)
 | 
				
			||||||
 | 
					        editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					fsfetch.send();
 | 
				
			||||||
 | 
					let pathFetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					pathFetch.open('GET', './paths.txt');
 | 
				
			||||||
 | 
					pathFetch.onloadend = function () {
 | 
				
			||||||
 | 
					    let text = pathFetch.responseText;
 | 
				
			||||||
 | 
					    let currX = 0,
 | 
				
			||||||
 | 
					        currY = 0,
 | 
				
			||||||
 | 
					        maxX = -10000,
 | 
				
			||||||
 | 
					        maxY = -10000,
 | 
				
			||||||
 | 
					        minX = 10000,
 | 
				
			||||||
 | 
					        minY = 10000;
 | 
				
			||||||
 | 
					    var currShape = [],
 | 
				
			||||||
 | 
					        currCurve = [];
 | 
				
			||||||
 | 
					    let i = 0;
 | 
				
			||||||
 | 
					    let postProcess = () => {
 | 
				
			||||||
 | 
					        if (currShape.length) {
 | 
				
			||||||
 | 
					            let spanX = maxX - minX;
 | 
				
			||||||
 | 
					            let spanY = maxY - minY;
 | 
				
			||||||
 | 
					            let span = Math.max(spanX, spanY);
 | 
				
			||||||
 | 
					            let l_total = 0;
 | 
				
			||||||
 | 
					            for (var k = 0; k < currShape.length; ++k) {
 | 
				
			||||||
 | 
					                let funcs = [];
 | 
				
			||||||
 | 
					                const curve = currShape[k];
 | 
				
			||||||
 | 
					                for (let j = 0; j < curve.length; j += 2) {
 | 
				
			||||||
 | 
					                    curve[j] = (curve[j] - minX) / span - spanX / (span * 2);
 | 
				
			||||||
 | 
					                    curve[j + 1] = (curve[j + 1] - minY) / span - spanY / (span * 2);
 | 
				
			||||||
 | 
					                    origpath.push(1, curve[j], curve[j + 1], 0, 0, 0, 1);
 | 
				
			||||||
 | 
					                    if (j % 6 == 0 && j > 5) {
 | 
				
			||||||
 | 
					                        let X = [],
 | 
				
			||||||
 | 
					                            Y = [];
 | 
				
			||||||
 | 
					                        for (let k = j - 6; k <= j + 1; k += 2) {
 | 
				
			||||||
 | 
					                            X.push(curve[k]);
 | 
				
			||||||
 | 
					                            Y.push(curve[k + 1]);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        let l = (vec_len(minus([X[3], Y[3]], [X[0], Y[0]])) +
 | 
				
			||||||
 | 
					                            vec_len(minus([X[3], Y[3]], [X[2], Y[2]])) +
 | 
				
			||||||
 | 
					                            vec_len(minus([X[2], Y[2]], [X[1], Y[1]])) +
 | 
				
			||||||
 | 
					                            vec_len(minus([X[1], Y[1]], [X[0], Y[0]]))) / 2.;
 | 
				
			||||||
 | 
					                        l_total += l;
 | 
				
			||||||
 | 
					                        funcs.push([matrix_multiply(bezierMat, X),
 | 
				
			||||||
 | 
					                            matrix_multiply(bezierMat, Y), l
 | 
				
			||||||
 | 
					                        ]);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                paths.push(funcs);
 | 
				
			||||||
 | 
					                path_misc.push([l_total, spanX / (2 * span), spanY / (2 * span)]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let read_num = () => {
 | 
				
			||||||
 | 
					        let num = 0,
 | 
				
			||||||
 | 
					            sign = 1,
 | 
				
			||||||
 | 
					            accepted = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (i < text.length && (text[i] < '0' || text[i] > '9') && text[i] != '-') ++i;
 | 
				
			||||||
 | 
					        if (text[i] == '-') {
 | 
				
			||||||
 | 
					            sign = -1;
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while (i < text.length && text[i] >= '0' && text[i] <= '9') {
 | 
				
			||||||
 | 
					            let n = text[i++] - '0';
 | 
				
			||||||
 | 
					            accepted *= 10;
 | 
				
			||||||
 | 
					            accepted += n;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        num += accepted;
 | 
				
			||||||
 | 
					        if (text[i] == '.') {
 | 
				
			||||||
 | 
					            i++;
 | 
				
			||||||
 | 
					            let multiplier = 0.1;
 | 
				
			||||||
 | 
					            accepted = 0;
 | 
				
			||||||
 | 
					            while (i < text.length && text[i] >= '0' && text[i] <= '9') {
 | 
				
			||||||
 | 
					                let n = text[i++] - '0';
 | 
				
			||||||
 | 
					                accepted += n * multiplier;
 | 
				
			||||||
 | 
					                multiplier /= 10;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            num += accepted;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return num * sign;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let cRevs = [],
 | 
				
			||||||
 | 
					        c_idx = 0,
 | 
				
			||||||
 | 
					        prevX = 0,
 | 
				
			||||||
 | 
					        prevY = 0,
 | 
				
			||||||
 | 
					        getC = () => {
 | 
				
			||||||
 | 
					            return cRevs[c_idx--];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    let get_next = (delta = false) => {
 | 
				
			||||||
 | 
					        if (delta) {
 | 
				
			||||||
 | 
					            currX = prevX + read_num();
 | 
				
			||||||
 | 
					            currY = prevY + read_num();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            currX = read_num();
 | 
				
			||||||
 | 
					            currY = read_num();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        maxX = currX > maxX ? currX : maxX;
 | 
				
			||||||
 | 
					        maxY = currY > maxY ? currY : maxY;
 | 
				
			||||||
 | 
					        minX = currX < minX ? currX : minX;
 | 
				
			||||||
 | 
					        minY = currY < minY ? currY : minY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        currCurve.push(currX);
 | 
				
			||||||
 | 
					        currCurve.push(currY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while (i < text.length) {
 | 
				
			||||||
 | 
					        if (text[i] == 'z') {
 | 
				
			||||||
 | 
					            currCurve.length && currShape.push(currCurve);
 | 
				
			||||||
 | 
					            currCurve = [];
 | 
				
			||||||
 | 
					            ++i
 | 
				
			||||||
 | 
					        } else if (text[i] == 'N') {
 | 
				
			||||||
 | 
					            postProcess();
 | 
				
			||||||
 | 
					            currShape = [];
 | 
				
			||||||
 | 
					            maxX = -1000, maxY = -1000, minX = 1000, minY = 1000;
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					        } else if (text[i] == 'c') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            prevX = currX;
 | 
				
			||||||
 | 
					            prevY = currY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (let j = 0; j < 3; ++j) {
 | 
				
			||||||
 | 
					                get_next(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (text[i] == 'C') {
 | 
				
			||||||
 | 
					            for (let j = 0; j < 3; ++j) {
 | 
				
			||||||
 | 
					                get_next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (text[i] == 'M') {
 | 
				
			||||||
 | 
					            get_next();
 | 
				
			||||||
 | 
					        } else ++i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					pathFetch.send();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let vec_len = v => {
 | 
				
			||||||
 | 
					    let len = 0;
 | 
				
			||||||
 | 
					    for (let i = 0; i < v.length; ++i)
 | 
				
			||||||
 | 
					        len += v[i] * v[i];
 | 
				
			||||||
 | 
					    return sqrt(len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_inverse = src => {
 | 
				
			||||||
 | 
					    let dst = [],
 | 
				
			||||||
 | 
					        det = 0,
 | 
				
			||||||
 | 
					        cofactor = (c, r) => {
 | 
				
			||||||
 | 
					            let s = (i, j) => src[c + i & 3 | (r + j & 3) << 2];
 | 
				
			||||||
 | 
					            return (c + r & 1 ? -1 : 1) * ((s(1, 1) * (s(2, 2) * s(3, 3) - s(3, 2) * s(2, 3))) -
 | 
				
			||||||
 | 
					                (s(2, 1) * (s(1, 2) * s(3, 3) - s(3, 2) * s(1, 3))) +
 | 
				
			||||||
 | 
					                (s(3, 1) * (s(1, 2) * s(2, 3) - s(2, 2) * s(1, 3))));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    for (let n = 0; n < 16; n++) dst.push(cofactor(n >> 2, n & 3));
 | 
				
			||||||
 | 
					    for (let n = 0; n < 4; n++) det += src[n] * dst[n << 2];
 | 
				
			||||||
 | 
					    for (let n = 0; n < 16; n++) dst[n] /= det;
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let scale = (v, s) => [ s * v[0] , s * v[1] , s * v[2] ];
 | 
				
			||||||
 | 
					let norm = v => Math.sqrt(dot(v,v));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// I HAVE IMPLEMENTED THESE FUNCTIONS FOR YOU
 | 
				
			||||||
 | 
					let matrix_identity = () => {
 | 
				
			||||||
 | 
					    return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_translate = (x, y, z) => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[12] = x;
 | 
				
			||||||
 | 
					    m[13] = y;
 | 
				
			||||||
 | 
					    m[14] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_perspective = (m) => {
 | 
				
			||||||
 | 
					    let ret = []
 | 
				
			||||||
 | 
					    for (let i = 0; i < 16; i++)
 | 
				
			||||||
 | 
					        ret[i] = m[i];
 | 
				
			||||||
 | 
					    for (let i = 2; i < 15; i += 4) {
 | 
				
			||||||
 | 
					        ret[i] = -ret[i];
 | 
				
			||||||
 | 
					        ret[i + 1] += ret[i] / fl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// YOU NEED TO PROPERLY IMPLEMENT THE FOLLOWING FIVE FUNCTIONS:
 | 
				
			||||||
 | 
					let matrix_rotateX = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    m[6] = sin(theta);
 | 
				
			||||||
 | 
					    m[9] = -sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let matrix_rotateY = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[2] = -sin(theta);
 | 
				
			||||||
 | 
					    m[8] = sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_rotateZ = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[1] = sin(theta);
 | 
				
			||||||
 | 
					    m[4] = -sin(theta);
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_scale = (x, y, z) => {
 | 
				
			||||||
 | 
					    if (y === undefined)
 | 
				
			||||||
 | 
					        y = z = x;
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = x;
 | 
				
			||||||
 | 
					    m[5] = y;
 | 
				
			||||||
 | 
					    m[10] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_multiply = (a, b, m = 4, n = 4) => { //dim=mn*nm=mm
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    if (b.length < m * n) { //mat-vec multiply (i did this for my convenience)
 | 
				
			||||||
 | 
					        for (let i = 0; i < m; ++i) {
 | 
				
			||||||
 | 
					            res[i] = 0;
 | 
				
			||||||
 | 
					            for (let j = 0; j < n; ++j)
 | 
				
			||||||
 | 
					                res[i] += b[j] * a[m * j + i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    } //otherwise mm multiply
 | 
				
			||||||
 | 
					    for (let i = 0; i < m; ++i)
 | 
				
			||||||
 | 
					        for (let j = 0; j < m; ++j) {
 | 
				
			||||||
 | 
					            var t = 0;
 | 
				
			||||||
 | 
					            for (let k = 0; k < n; ++k)
 | 
				
			||||||
 | 
					                t += a[k * m + j] * b[i * n + k];
 | 
				
			||||||
 | 
					            res.push(t);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let const_multiply = (c, a, add = 0) => {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for (let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = (a[i] + add)* c;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function dot(a, b) {
 | 
				
			||||||
 | 
					    b=b?b:a;
 | 
				
			||||||
 | 
					    let m = 0;
 | 
				
			||||||
 | 
					    for (let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m += a[i] * b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function cross(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    m[0] = a[1]*b[2] - a[2]*b[1];
 | 
				
			||||||
 | 
					    m[1] = a[2]*b[0] - a[0]*b[2];
 | 
				
			||||||
 | 
					    m[2] = a[0]*b[1] - a[1]*b[0];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function plus(a, b) {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for (let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] + b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function minus(a, b) {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for (let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] - b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function normalize(v) {
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    sum = 0;
 | 
				
			||||||
 | 
					    for (let i = 0; i < v.length; ++i)
 | 
				
			||||||
 | 
					        sum += v[i] * v[i];
 | 
				
			||||||
 | 
					    sum = sqrt(sum);
 | 
				
			||||||
 | 
					    for (let i = 0; i < v.length; ++i)
 | 
				
			||||||
 | 
					        res[i] = v[i] / sum;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let Matrix = function () {
 | 
				
			||||||
 | 
					    let top = 0,
 | 
				
			||||||
 | 
					        m = [matrix_identity()];
 | 
				
			||||||
 | 
					    this.identity = () => m[top] = matrix_identity();
 | 
				
			||||||
 | 
					    this.translate = (x, y, z) => m[top] = matrix_multiply(m[top], matrix_translate(x, y, z));
 | 
				
			||||||
 | 
					    this.rotateX = theta => m[top] = matrix_multiply(m[top], matrix_rotateX(theta));
 | 
				
			||||||
 | 
					    this.rotateY = theta => m[top] = matrix_multiply(m[top], matrix_rotateY(theta));
 | 
				
			||||||
 | 
					    this.rotateZ = theta => m[top] = matrix_multiply(m[top], matrix_rotateZ(theta));
 | 
				
			||||||
 | 
					    this.scale = (x, y, z) => m[top] = matrix_multiply(m[top], matrix_scale(x, y, z));
 | 
				
			||||||
 | 
					    this.apply = (m1) => m[top] = matrix_multiply(m[top], m1); 
 | 
				
			||||||
 | 
					    this.applyl = (m1) => m[top] = matrix_multiply(m1, m[top]); 
 | 
				
			||||||
 | 
					    this.value = () => m[top];
 | 
				
			||||||
 | 
					    this.save = () => {
 | 
				
			||||||
 | 
					        m[top + 1] = m[top].slice();
 | 
				
			||||||
 | 
					        top++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.restore = () => --top;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest_sphere(ray, sphere, r) {
 | 
				
			||||||
 | 
					    let B = dot(ray, sphere);
 | 
				
			||||||
 | 
					    let C = dot(sphere, sphere) - r*r;
 | 
				
			||||||
 | 
					    let D = B * B - C;
 | 
				
			||||||
 | 
					    if (D > 0.) {
 | 
				
			||||||
 | 
					        //console.log(D);
 | 
				
			||||||
 | 
					        //let t = -B - sqrt(D);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest_square(pt, invMatrix, shape){
 | 
				
			||||||
 | 
					    pt.push(1);
 | 
				
			||||||
 | 
					    const V = dot_xyz(matrix_multiply(invMatrix, [0,0,fl,1])),
 | 
				
			||||||
 | 
					     pos = dot_xyz(matrix_multiply(invMatrix, pt)),
 | 
				
			||||||
 | 
					     W = minus(pos, V),
 | 
				
			||||||
 | 
					     A = shape.slice(1,4),
 | 
				
			||||||
 | 
					     B = shape.slice(8,11),
 | 
				
			||||||
 | 
					     C = shape.slice(15,18),
 | 
				
			||||||
 | 
					     AB = minus(B, A),
 | 
				
			||||||
 | 
					     AC = minus(C, A),
 | 
				
			||||||
 | 
					     AB_AC = cross(AB, AC),
 | 
				
			||||||
 | 
					     VA = minus(V, A),
 | 
				
			||||||
 | 
					     t = - dot(AB_AC, VA)/dot(W, AB_AC),
 | 
				
			||||||
 | 
					     P = plus(V, const_multiply(t, W)),
 | 
				
			||||||
 | 
					     AP = minus(P, A),
 | 
				
			||||||
 | 
					     d_AP_AC = dot(AP, AC),
 | 
				
			||||||
 | 
					     d_AP_AB = dot(AP, AB);
 | 
				
			||||||
 | 
					    if(0 <d_AP_AC && d_AP_AC < dot(AC, AC) && 0 < d_AP_AB && d_AP_AB< dot(AB, AB))
 | 
				
			||||||
 | 
					        return P; 
 | 
				
			||||||
 | 
					    else return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let dot_xyz = (v) => {
 | 
				
			||||||
 | 
					    let ret = [];
 | 
				
			||||||
 | 
					    if(v[3])
 | 
				
			||||||
 | 
					        for(let i = 0; i < 3; ++i)
 | 
				
			||||||
 | 
					            ret[i] = v[i]/v[3];
 | 
				
			||||||
 | 
					    else ret = v.slice(0,3);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let Button = function (onclick = () => {}, shape = [], outlineTy = 'sphere') {
 | 
				
			||||||
 | 
					    this.shape = shape;
 | 
				
			||||||
 | 
					    this.enabled = true;
 | 
				
			||||||
 | 
					    this.outlineTy = outlineTy;
 | 
				
			||||||
 | 
					    this.onClick = onclick;
 | 
				
			||||||
 | 
					    this.updateMatrix = (m) => {this.matrix = matrix_perspective(m); this.invMatrix = matrix_inverse(m);};
 | 
				
			||||||
 | 
					    this.updateMatrix(matrix_identity());
 | 
				
			||||||
 | 
					    this.hovering = false;
 | 
				
			||||||
 | 
					    this.activated = false;
 | 
				
			||||||
 | 
					    this.getShape = () => this.shape;
 | 
				
			||||||
 | 
					    this.draw = () => {setUniform('Matrix4fv', 'uMatrix', false, this.matrix);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'invMatrix', false, this.invMatrix); drawMesh(this.shape);}
 | 
				
			||||||
 | 
					    this.resetShape = (_sh) => {
 | 
				
			||||||
 | 
					        if(this.shape) delete this.shape;
 | 
				
			||||||
 | 
					        this.shape = new Float32Array(_sh);
 | 
				
			||||||
 | 
					        let maxV =  new Array(3).fill(-Infinity), minV = new Array(3).fill(Infinity);
 | 
				
			||||||
 | 
					        for(let i = 0; i < _sh.length; i += 7){
 | 
				
			||||||
 | 
					            const v = [_sh[i + 1], _sh[i + 2], _sh[i + 3]];
 | 
				
			||||||
 | 
					            v.forEach((c, j) => {
 | 
				
			||||||
 | 
					                maxV[j] = maxV[j] > c ? maxV[j] : c;
 | 
				
			||||||
 | 
					                minV[j] = minV[j] < c ? minV[j] : c;
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //build outline
 | 
				
			||||||
 | 
					        switch(this.outlineTy){
 | 
				
			||||||
 | 
					            case 'sphere':
 | 
				
			||||||
 | 
					                this.origin = const_multiply(.5, plus(maxV, minV));
 | 
				
			||||||
 | 
					                //this.origin.push(1);
 | 
				
			||||||
 | 
					                this.radius = 0.6*vec_len(minus(maxV, minV))/2.;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'square':
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'circle':
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        switch(this.outlineTy){
 | 
				
			||||||
 | 
					        case 'sphere':
 | 
				
			||||||
 | 
					            this.hitTest = (pt) => {
 | 
				
			||||||
 | 
					                pt.push(1);
 | 
				
			||||||
 | 
					                const V = dot_xyz(matrix_multiply(this.invMatrix, [0,0,fl,1])),
 | 
				
			||||||
 | 
					                 pos = dot_xyz(matrix_multiply(this.invMatrix, pt));
 | 
				
			||||||
 | 
					                let W = normalize((minus(pos, V)));
 | 
				
			||||||
 | 
					                let Vp = minus(V, this.origin);
 | 
				
			||||||
 | 
					                return hitTest_sphere(W, Vp, this.radius);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'square':
 | 
				
			||||||
 | 
					            this.hitTest = (pt) => {
 | 
				
			||||||
 | 
					                this.P = hitTest_square(pt, this.invMatrix, this.shape);
 | 
				
			||||||
 | 
					                return this.P;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 'circle':
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if(!shape || shape.length != 0)
 | 
				
			||||||
 | 
					        this.resetShape(shape);
 | 
				
			||||||
 | 
					    canvas_controls.push(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let setM = (m) => {
 | 
				
			||||||
 | 
					    let mm = matrix_perspective(m);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'uMatrix', false, mm);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'invMatrix', false, matrix_inverse(mm));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//------ CREATING MESH SHAPES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CREATE A MESH FROM A PARAMETRIC FUNCTION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createMesh = (nu, nv, f, data, oid = 0) => {
 | 
				
			||||||
 | 
					    let tmp = [];
 | 
				
			||||||
 | 
					    for (let v = 0; v < 1; v += 1 / nv) {
 | 
				
			||||||
 | 
					        for (let u = 0; u <= 1; u += 1 / nu) {
 | 
				
			||||||
 | 
					            tmp = tmp.concat(f(u, v, oid, data));
 | 
				
			||||||
 | 
					            tmp = tmp.concat(f(u, v + 1 / nv, oid, data));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tmp = tmp.concat(f(1, v, oid, data));
 | 
				
			||||||
 | 
					        tmp = tmp.concat(f(0, v + 1 / nv, oid, data));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new Float32Array(tmp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//Create a Mesh from Splines
 | 
				
			||||||
 | 
					let createMeshFromSpline = (idx,
 | 
				
			||||||
 | 
					    nu, nv, oid = 16, additional_offset = 0, f = () => {}) => {
 | 
				
			||||||
 | 
					    let S = paths[idx],
 | 
				
			||||||
 | 
					        meta = path_misc[idx];
 | 
				
			||||||
 | 
					    const n_min = 2;
 | 
				
			||||||
 | 
					    let ds = meta[0] / nv,
 | 
				
			||||||
 | 
					        curr_s = 0,
 | 
				
			||||||
 | 
					        curr_d = S[0][2] / Math.ceil(S[0][2] / ds),
 | 
				
			||||||
 | 
					        i = 0,
 | 
				
			||||||
 | 
					        s = 0;
 | 
				
			||||||
 | 
					    let tmp = [],
 | 
				
			||||||
 | 
					        ret = undefined;
 | 
				
			||||||
 | 
					    while (s < meta[0] - 1 / 100000) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let u = 0; u <= 1; u += 1 / nu) {
 | 
				
			||||||
 | 
					            tmp = tmp.concat(getSurface(S[i][1], S[i][0], u, curr_s, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					            tmp = tmp.concat(getSurface(S[i][1], S[i][0], u, curr_s + curr_d, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tmp = tmp.concat(getSurface(S[i][1], S[i][0], 0, curr_s, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					        tmp = tmp.concat(getSurface(S[i][1], S[i][0], 1, curr_s + curr_d, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					        if (ret = f(i, tmp, oid)) {
 | 
				
			||||||
 | 
					            oid = ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        curr_s += curr_d;
 | 
				
			||||||
 | 
					        if (curr_s >= 1) {
 | 
				
			||||||
 | 
					            s += S[i][2];
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					            if (i >= S.length)
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            let curr_n = Math.ceil(S[i][2] / ds);
 | 
				
			||||||
 | 
					            curr_n = curr_n < n_min ? n_min : curr_n;
 | 
				
			||||||
 | 
					            curr_d = 1 / curr_n;
 | 
				
			||||||
 | 
					            curr_s = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new Float32Array(tmp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// GLUE TWO MESHES TOGETHER INTO A SINGLE MESH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let glueMeshes = (a, b) => {
 | 
				
			||||||
 | 
					    let c = [];
 | 
				
			||||||
 | 
					    for (let i = 0; i < a.length; i++)
 | 
				
			||||||
 | 
					        c.push(a[i]); // a
 | 
				
			||||||
 | 
					    for (let i = 0; i < VERTEX_SIZE; i++)
 | 
				
			||||||
 | 
					        c.push(a[a.length - VERTEX_SIZE + i]); // + last vertex of a
 | 
				
			||||||
 | 
					    for (let i = 0; i < VERTEX_SIZE; i++)
 | 
				
			||||||
 | 
					        c.push(b[i]); // + first vertex of b
 | 
				
			||||||
 | 
					    for (let i = 0; i < b.length; i++)
 | 
				
			||||||
 | 
					        c.push(b[i]); // + b
 | 
				
			||||||
 | 
					    return new Float32Array(c);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToCone = (u, v, i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta)*(1-v);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta)*(1-v);
 | 
				
			||||||
 | 
					    let z = 2 * v - 1;
 | 
				
			||||||
 | 
					    return [i, x, y, z].concat(normalize([x, y, 0]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToSphere = (u, v, i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let phi = Math.PI * (v - .5);
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let z = Math.sin(phi);
 | 
				
			||||||
 | 
					    return [i, x, y, z].concat(normalize([x, y, z]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToTube = (u, v, i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta);
 | 
				
			||||||
 | 
					    let z = 2 * v - 1;
 | 
				
			||||||
 | 
					    return [i, x, y, z].concat(normalize([x, y, 0]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let uvToDisk = (u, v, i, dz) => {
 | 
				
			||||||
 | 
					    if (dz === undefined)
 | 
				
			||||||
 | 
					        dz = 0;
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * v;
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * v;
 | 
				
			||||||
 | 
					    let z = dz;
 | 
				
			||||||
 | 
					    return [i, x, y, z].concat([0, 0, Math.sign(z)]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let uvToTorus = (u, v, i, r) => {
 | 
				
			||||||
 | 
					    let theta = 2 * pi;
 | 
				
			||||||
 | 
					    let phi = theta * v;
 | 
				
			||||||
 | 
					    theta *= u;
 | 
				
			||||||
 | 
					    let x = 1 + r * cos(phi);
 | 
				
			||||||
 | 
					    let y = sin(theta) * x;
 | 
				
			||||||
 | 
					    x *= cos(theta);
 | 
				
			||||||
 | 
					    let z = r * sin(phi);
 | 
				
			||||||
 | 
					    let tx = -sin(theta),
 | 
				
			||||||
 | 
					        ty = cos(theta),
 | 
				
			||||||
 | 
					        tsx = sin(phi),
 | 
				
			||||||
 | 
					        tsy = tsx * tx,
 | 
				
			||||||
 | 
					        tsz = cos(phi);
 | 
				
			||||||
 | 
					    tsx *= -ty;
 | 
				
			||||||
 | 
					    return [i, x, y, z].concat(normalize([ty * tsz * 0.5, -tx * tsz, tx * tsy - ty * tsx]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createCube = (w, h, l, id) => {
 | 
				
			||||||
 | 
					    let mesh = [];
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, -l / 2, 0, -1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, l / 2, 0, -1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, -l / 2, 0, -1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, l / 2, 0, -1, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, l / 2, 0, -1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, l / 2, 0, 0, 1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, l / 2, 0, 0, 1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, l / 2, 0, 0, 1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, l / 2, 0, 0, 1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, l / 2, 0, 0, 1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, l / 2, 0, 0, 1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, l / 2, -1, 0, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, l / 2, -1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, l / 2, -1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, -l / 2, -1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, -l / 2, -1, 0, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, -l / 2, -1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, -l / 2, 0, 0, -1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, -h / 2, -l / 2, 0, 0, -1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, -l / 2, 0, 0, -1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, -l / 2, 0, 0, -1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, -l / 2, 0, 0, -1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, -l / 2, 0, 0, -1]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, -l / 2, 1, 0, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, -l / 2, 1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, l / 2, 1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, -l / 2, 1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, l / 2, 1, 0, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, -h / 2, l / 2, 1, 0, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, l / 2, 0, 1, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, l / 2, 0, 1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, w / 2, h / 2, -l / 2, 0, 1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, l / 2, 0, 1, 0]);
 | 
				
			||||||
 | 
					    mesh = mesh.concat([id, -w / 2, h / 2, -l / 2, 0, 1, 0]);
 | 
				
			||||||
 | 
					    return new Float32Array(mesh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updatePositions() {
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    setUniform('3f', 'V0', m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz));
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz) / (fl + 1), m);
 | 
				
			||||||
 | 
					    setUniform('Matrix3fv', 'transformation', false, [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]);
 | 
				
			||||||
 | 
					    positionsupdated = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function controls_hitTest(pos, clicked = false){
 | 
				
			||||||
 | 
					    // let iMin = -1, tMin = 10000.;
 | 
				
			||||||
 | 
					    canvas_controls.forEach((c, i) => {
 | 
				
			||||||
 | 
					        if(c.enabled && c.hitTest && (c.hover||clicked) ){
 | 
				
			||||||
 | 
					            let t = c.hitTest(pos);
 | 
				
			||||||
 | 
					            if(t != -1){
 | 
				
			||||||
 | 
					                if(clicked)
 | 
				
			||||||
 | 
					                    c.onClick();
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    c.hover(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                if(c.hovering)
 | 
				
			||||||
 | 
					                    c.hover(false);
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    //ground
 | 
				
			||||||
 | 
					    if(ground_m && ground){
 | 
				
			||||||
 | 
					        let invG = matrix_inverse(ground_m);
 | 
				
			||||||
 | 
					        let P = hitTest_square(pos, invG, ground);
 | 
				
			||||||
 | 
					        //let Vp = minus(matrix_multiply(invG,[0,0,fl, 1]).slice(0,3), this.origin);
 | 
				
			||||||
 | 
					        if(P!=-1)
 | 
				
			||||||
 | 
					            if(near_magician){
 | 
				
			||||||
 | 
					                if(slider.dragging === true){
 | 
				
			||||||
 | 
					                    slider_dl += 10 * (P[0] - slider.lastPos);
 | 
				
			||||||
 | 
					                    if(slider_dl < 0) slider_dl = 0;
 | 
				
			||||||
 | 
					                    else if (slider_dl > 9) slider_dl = 9;
 | 
				
			||||||
 | 
					                    slider.lastPos = P[0];
 | 
				
			||||||
 | 
					                    // onUpdate
 | 
				
			||||||
 | 
					                    let id = 1 + .45*slider_dl/9;
 | 
				
			||||||
 | 
					                    changeID(id, cylinderMesh);
 | 
				
			||||||
 | 
					                } else if(clicked) {
 | 
				
			||||||
 | 
					                    const PO = minus([slider_dl/10-.25, .7], [P[0], P[1]]);
 | 
				
			||||||
 | 
					                    const rr = PO[0]*PO[0] + PO[1] * PO[1];
 | 
				
			||||||
 | 
					                    if(rr < .003){
 | 
				
			||||||
 | 
					                        slider.dragging = true;
 | 
				
			||||||
 | 
					                        slider.lastPos = P[0];
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (!state.dead){
 | 
				
			||||||
 | 
					                if(clicked || state.running<=0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    state.turn(P, clicked);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                //if(state.figure_rot < 0) state.figure_rot += pi;
 | 
				
			||||||
 | 
					                //updateStatus([state.figure_rot, state.direction_l[0]/state.direction_l[1]]);
 | 
				
			||||||
 | 
					                if(clicked)
 | 
				
			||||||
 | 
					                {   
 | 
				
			||||||
 | 
					                    state.walk();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //return iMin;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest(pos) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    let V = [m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz)];
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz) / (fl + 1), m);
 | 
				
			||||||
 | 
					    let trPos = matrix_multiply([m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]], [pos[0], -pos[1], -1], 3, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let W = normalize(minus(trPos, V));
 | 
				
			||||||
 | 
					    let tMin = 10000.;
 | 
				
			||||||
 | 
					    let iMin = -1;
 | 
				
			||||||
 | 
					    for (let i = 0; i < cns; i++) {
 | 
				
			||||||
 | 
					        let Vp = minus(V, matrix_multiply(SphTr[i], Sph[i]));
 | 
				
			||||||
 | 
					        let B = dot(W, Vp);
 | 
				
			||||||
 | 
					        let C = dot(Vp, Vp) - Sph[i][4] * Sph[i][4];
 | 
				
			||||||
 | 
					        let D = B * B - C;
 | 
				
			||||||
 | 
					        if (D > 0.) {
 | 
				
			||||||
 | 
					            let t = -B - sqrt(D);
 | 
				
			||||||
 | 
					            if (t > 0.0 && t < tMin) {
 | 
				
			||||||
 | 
					                tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					                iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return iMin;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_transform = (m, p) => {
 | 
				
			||||||
 | 
					    let x = p[0],
 | 
				
			||||||
 | 
					        y = p[1],
 | 
				
			||||||
 | 
					        z = p[2],
 | 
				
			||||||
 | 
					        w = p[3] === undefined ? 1 : p[3];
 | 
				
			||||||
 | 
					    let q = [m[0] * x + m[4] * y + m[8] * z + m[12] * w,
 | 
				
			||||||
 | 
					        m[1] * x + m[5] * y + m[9] * z + m[13] * w,
 | 
				
			||||||
 | 
					        m[2] * x + m[6] * y + m[10] * z + m[14] * w,
 | 
				
			||||||
 | 
					        m[3] * x + m[7] * y + m[11] * z + m[15] * w
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    return p[3] === undefined ? [q[0] / q[3], q[1] / q[3], q[2] / q[3]] : q;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let evalSpline = (h, t) => {
 | 
				
			||||||
 | 
					    // t *= (h.length - 2) / 2;
 | 
				
			||||||
 | 
					    // let n = 2 * Math.floor(t);
 | 
				
			||||||
 | 
					    // t = t % 1;
 | 
				
			||||||
 | 
					    // let C = matrix_transform(type, [h[n+0],h[n+2],h[n+1],h[n+3]]);
 | 
				
			||||||
 | 
					    // return t*t*t*C[0] + t*t*C[1] + t*C[2] + C[3];
 | 
				
			||||||
 | 
					    return t * t * t * h[0] + t * t * h[1] + t * h[2] + h[3];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let getSurface = (S0, S1, u, v, offsetidx, id = 15, additional_offset = 0) => {
 | 
				
			||||||
 | 
					    const epsilon = .001;
 | 
				
			||||||
 | 
					    let z0 = evalSpline(S0, v),
 | 
				
			||||||
 | 
					        z1 = evalSpline(S0, v + epsilon),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r0 = evalSpline(S1, v) - path_misc[offsetidx][1] + additional_offset,
 | 
				
			||||||
 | 
					        r1 = evalSpline(S1, v + epsilon),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tilt = Math.atan2(r0 - r1, z1 - z0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let xx = cos(2 * pi * u),
 | 
				
			||||||
 | 
					        yy = sin(2 * pi * u);
 | 
				
			||||||
 | 
					    let x = r0 * xx, // POSITION
 | 
				
			||||||
 | 
					        y = r0 * yy,
 | 
				
			||||||
 | 
					        z = z0,
 | 
				
			||||||
 | 
					        nx = cos(tilt), // NORMAL
 | 
				
			||||||
 | 
					        ny = nx * yy,
 | 
				
			||||||
 | 
					        nz = sin(tilt);
 | 
				
			||||||
 | 
					    nx *= xx;
 | 
				
			||||||
 | 
					    return [id, x, y, z, nx, ny, nz];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let concat = (a, b) => b.forEach(e => a.push(e));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let transform_mesh = (m,arr) => {
 | 
				
			||||||
 | 
					    for(let i = 0; i < arr.length; i+=7){
 | 
				
			||||||
 | 
					        const mod = dot_xyz(
 | 
				
			||||||
 | 
					            matrix_multiply(m, [arr[i+1], arr[i+2], arr[i+3], 1]));
 | 
				
			||||||
 | 
					        const mod_nor = normalize(dot_xyz(
 | 
				
			||||||
 | 
					            matrix_multiply(m, [arr[i+4], arr[i+5], arr[i+6], 0])));
 | 
				
			||||||
 | 
					        arr[i+1] = mod[0];
 | 
				
			||||||
 | 
					        arr[i+2] = mod[1];
 | 
				
			||||||
 | 
					        arr[i+3] = mod[2];
 | 
				
			||||||
 | 
					        arr[i+4] = mod_nor[0];
 | 
				
			||||||
 | 
					        arr[i+5] = mod_nor[1];
 | 
				
			||||||
 | 
					        arr[i+6] = mod_nor[2];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let thicken_contour = (thickness, contour) =>{
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    let inner_contour = contour.slice();
 | 
				
			||||||
 | 
					    transform_mesh(matrix_scale(thickness), inner_contour);
 | 
				
			||||||
 | 
					    for(let i = 0; i < contour.length - 7; i+=7){
 | 
				
			||||||
 | 
					        for (let j = 0; j < 7; ++ j)
 | 
				
			||||||
 | 
					            res.push(contour[i + j]);
 | 
				
			||||||
 | 
					        res.push(contour[0]);
 | 
				
			||||||
 | 
					        for (let j = 1; j < 7; ++ j)
 | 
				
			||||||
 | 
					            res.push((inner_contour[i + j]+inner_contour[i+7+j])/2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (let j = 0; j < 7; ++ j)
 | 
				
			||||||
 | 
					        res.push(contour[contour.length - 7 + j]);
 | 
				
			||||||
 | 
					    res.push(contour[0]);
 | 
				
			||||||
 | 
					    for (let j = 1; j < 7; ++ j)
 | 
				
			||||||
 | 
					        res.push((inner_contour[contour.length - 7 + j]+inner_contour[j])/2);
 | 
				
			||||||
 | 
					    for (let j = 0; j < 7; ++ j)
 | 
				
			||||||
 | 
					        res.push(contour[j]);
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let sqlen = (a, b) => { return a*a + b*b; }
 | 
				
			||||||
@ -0,0 +1,266 @@
 | 
				
			|||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = ['' // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;', '#define _NDEBUG\n','float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {', '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +', '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);', '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);', '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;', '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);', '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					var ns = 5,
 | 
				
			||||||
 | 
					   cns = 5;
 | 
				
			||||||
 | 
					fragmentShaderHeader += 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					var fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					var status = '';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					      bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let stack = function (){
 | 
				
			||||||
 | 
					   this.storage = ['Ready.'];
 | 
				
			||||||
 | 
					   this.len = 1;
 | 
				
			||||||
 | 
					   this.pop = ()=>{return this.storage[--this.len-1];}
 | 
				
			||||||
 | 
					   this.push = (o)=>{this.storage[this.len++] = o;}
 | 
				
			||||||
 | 
					   this.update = (o)=>{this.storage[this.len-1] = o;}
 | 
				
			||||||
 | 
					   this.top = () => {return this.storage[this.len - 1];}
 | 
				
			||||||
 | 
					   this.clear = () => this.len = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let status_history = new stack();
 | 
				
			||||||
 | 
					function updateStatus(val){
 | 
				
			||||||
 | 
					   status_history.update(status);
 | 
				
			||||||
 | 
					   status = val;
 | 
				
			||||||
 | 
					   errorMessage.innerHTML = val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function pushStatus(val){
 | 
				
			||||||
 | 
					   status_history.push(status);
 | 
				
			||||||
 | 
					   status = val;
 | 
				
			||||||
 | 
					   errorMessage.innerHTML = val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function restoreStatus(val){
 | 
				
			||||||
 | 
					   status = status_history.pop();
 | 
				
			||||||
 | 
					   errorMessage.innerHTML = status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function resetStatus() {
 | 
				
			||||||
 | 
					   status_history.clear();
 | 
				
			||||||
 | 
					   updateStatus('Ready.');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var texture = [], 
 | 
				
			||||||
 | 
					   gl, program;
 | 
				
			||||||
 | 
					let textures = [];
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null) {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0 + i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0 + i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function initTextures(gl, program){
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function initVideoTexture(gl, i) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function updateVideoTexture(gl, v_control, i){
 | 
				
			||||||
 | 
					   //return;
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					   gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					                 srcFormat, srcType, v_control);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function buildShaders(vertexShader, fragmentShader){
 | 
				
			||||||
 | 
					   let curr_program = canvas1.gl.createProgram();
 | 
				
			||||||
 | 
					   let compile_shaders = (type, src) => {
 | 
				
			||||||
 | 
					      let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					      gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					      gl.compileShader(shader);
 | 
				
			||||||
 | 
					      gl.attachShader(curr_program, shader);
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   compile_shaders(gl.VERTEX_SHADER, vertexShader);
 | 
				
			||||||
 | 
					   compile_shaders(gl.FRAGMENT_SHADER, fragmentShaderHeader + fragmentShaderDefs + fragmentShader);
 | 
				
			||||||
 | 
					   gl.linkProgram(curr_program);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   return curr_program;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) { // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					   console.log('glstart');
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl'); // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) {
 | 
				
			||||||
 | 
					         throw 'Sorry, your browser does not support WebGL.';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) { // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram(); // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) { // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = status;
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg,
 | 
				
			||||||
 | 
					                     type: "error"
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line + 1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            } else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader); // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader + fragmentShaderDefs + fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program); // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         if(!gl.shaders)
 | 
				
			||||||
 | 
					            gl.shaders = [program];
 | 
				
			||||||
 | 
					         else gl.shaders[0] = program;
 | 
				
			||||||
 | 
					         //initTextures(gl, program);
 | 
				
			||||||
 | 
					         positionsupdated = true;
 | 
				
			||||||
 | 
					         let attribs = [
 | 
				
			||||||
 | 
					            .05, .05, .1, .5, .5, 1., 1., .5, .5, 20., 0., .0, 1.3,
 | 
				
			||||||
 | 
					            .1, .05, .05, 1., .5, .5, 1., .5, .5, 10., .3, 1., 1.3,
 | 
				
			||||||
 | 
					            .1, .05, .05, .71, .71, .71, .71, .71, .71, 10., 0.3, .0, 1.5,
 | 
				
			||||||
 | 
					            .1, .1, .1, .71, .71, .71, .71, .71, .71, 10., 0.05, 0., 1.,
 | 
				
			||||||
 | 
					            .0, .0, .0, .0, .0, .0, .0, .0, .0, 40., 0., .85, 1.5
 | 
				
			||||||
 | 
					         ]
 | 
				
			||||||
 | 
					         var offset = 0;
 | 
				
			||||||
 | 
					         for (let i = 0; i < ns; i++) {
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Ambient[' + i + ']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Diffuse[' + i + ']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('4fv', 'Specular[' + i + ']', attribs.slice(offset, offset += 4));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'ks[' + i + ']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kr[' + i + ']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kf[' + i + ']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         offset = 0;
 | 
				
			||||||
 | 
					         for (let i = 0; i < n_shapes; i++) {
 | 
				
			||||||
 | 
					            setUniform('3fv', 'starColors[' + i + ']', starColors.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         // gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					         //    [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					         gl.enable(gl.DEPTH_TEST);
 | 
				
			||||||
 | 
					         gl.depthFunc(gl.LEQUAL);
 | 
				
			||||||
 | 
					         gl.clearDepth(-1);
 | 
				
			||||||
 | 
					         gl.enable(gl.BLEND);  
 | 
				
			||||||
 | 
					         gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
 | 
				
			||||||
 | 
					         let oid = gl.getAttribLocation(program, 'oid'); // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(oid);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(oid, 1, gl.FLOAT, false, 4 * 7, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos'); // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 4 * 7, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let normal = gl.getAttribLocation(program, 'normal'); // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(normal);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(normal, 3, gl.FLOAT, false, 4 * 7, 4 * 4);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader); // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () { // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined) // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now(); //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         //gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   if (gl) {
 | 
				
			||||||
 | 
					      let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					      (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//let VERTEX_SIZE = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let VERTEX_SIZE = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var drawMesh = (mesh, func = gl.TRIANGLE_STRIP) => {
 | 
				
			||||||
 | 
					   gl.bufferData(gl.ARRAY_BUFFER, mesh, gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					   gl.drawArrays(func, 0, mesh.length / VERTEX_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					M11.02,39.45c-2.67-2.97-5.37-5.93-8.01-8.94c-2.42-2.76-2.92-5.66-1.11-8.78c0.81-1.39,1.97-2.41,3.65-2.76c3.9-0.82,7.78-1.71,11.67-2.56c0.86-0.19,1.5-0.51,1.99-1.38c1.9-3.42,3.92-6.76,5.89-10.14c2.6-4.46,9.11-4.47,11.71-0.04
 | 
				
			||||||
 | 
					c1.98,3.37,3.99,6.72,5.89,10.14c0.48,0.86,1.08,1.23,1.96,1.42c3.94,0.85,7.88,1.68,11.81,2.6c2.44,0.57,3.73,2.34,4.36,4.65c0.77,2.82-0.27,5.08-2.16,7.14c-2.52,2.74-4.97,5.53-7.44,8.32c-0.18,0.2-0.41,0.49-0.38,0.72c0.18,1.94,0.41,3.87,0.63,5.8
 | 
				
			||||||
 | 
					c0.12,1.04,0.33,2.07,0.36,3.11c0.05,1.93,0.55,3.8,0.17,5.81c-0.65,3.42-4.81,6.08-8.02,4.95c-1.83-0.64-3.65-1.36-5.44-2.11
 | 
				
			||||||
 | 
					c-2.24-0.94-4.48-1.89-6.67-2.95c-0.75-0.36-1.36-0.27-2.02,0.03c-2.75,1.22-5.47,2.48-8.24,3.66c-1.3,0.56-2.64,1.08-4.01,1.43
 | 
				
			||||||
 | 
					c-2.45,0.63-4.53-0.26-6.14-2.08c-1.65-1.86-2.05-4.09-1.55-6.54c0.26-1.25,0.25-2.55,0.37-3.83
 | 
				
			||||||
 | 
					C10.52,44.62,10.77,42.12,11.02,39.45z M56.81,25.75c0.02-1.65-1.04-2.64-2.79-3.01c-4.04-0.84-8.06-1.74-12.1-2.57
 | 
				
			||||||
 | 
					c-0.91-0.19-1.58-0.65-2.04-1.42c-0.98-1.64-1.93-3.29-2.89-4.93c-1.32-2.26-2.6-4.55-3.98-6.77c-1.12-1.79-2.96-1.74-4.13,0.04
 | 
				
			||||||
 | 
					c-0.65,0.99-1.23,2.04-1.83,3.07c-1.66,2.84-3.32,5.68-4.97,8.52c-0.48,0.83-1.17,1.32-2.14,1.5c-1.82,0.34-3.62,0.74-5.42,1.14
 | 
				
			||||||
 | 
					c-2.45,0.54-4.92,1.04-7.34,1.68C5,23.57,4.46,25.5,5.92,27.15c1.64,1.85,3.31,3.69,4.95,5.54c1.33,1.5,2.68,2.97,3.92,4.54
 | 
				
			||||||
 | 
					c0.38,0.48,0.61,1.21,0.61,1.82c0.01,1.33-0.17,2.65-0.29,3.98c-0.09,0.99-0.19,1.98-0.3,2.97c-0.26,2.26-0.58,4.51-0.77,6.78
 | 
				
			||||||
 | 
					c-0.05,0.52,0.18,1.14,0.48,1.59c0.8,1.19,1.9,1.37,3.54,0.65c3.75-1.66,7.49-3.32,11.22-5.02c1.06-0.48,2.04-0.61,3.13-0.1
 | 
				
			||||||
 | 
					c1.94,0.92,3.9,1.78,5.86,2.65c2.05,0.91,4.11,1.78,6.15,2.69c0.93,0.42,1.77,0.3,2.52-0.37c0.76-0.68,1.19-1.49,0.83-2.55
 | 
				
			||||||
 | 
					c-0.08-0.22-0.12-0.46-0.14-0.7c-0.21-2.51-0.38-5.02-0.61-7.53c-0.12-1.32-0.38-2.63-0.51-3.95c-0.11-1.09-0.17-2.16,0.7-3.09
 | 
				
			||||||
 | 
					c1.83-1.95,3.6-3.95,5.37-5.94c1.23-1.39,2.46-2.79,3.64-4.22C56.54,26.51,56.69,25.99,56.81,25.75z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M66.36,818.02c-106.2-110.9-61-662.8-36.4-813.56c71.19,1.55,58.77-12.26,72.22,57.92c12.21-15.09,10.15-62.97,37.19-55.8
 | 
				
			||||||
 | 
					c-11.66,49.82-40.93,95.92-1.62,142.63c15.22,3.36,56.55-137.38,59.66-136.45c2.49,0.74-22.25,91.36-42.07,162.69
 | 
				
			||||||
 | 
					c8.65,35.12,58.93,87.86,92.29,98.19c14.23-79.7,33.22-361.27,73.99-244.33c41.13-55.27-7.85,38.44-11.46,55.28
 | 
				
			||||||
 | 
					c-18.92,98.99-27.77,241.63,53.45,119.52c20.21-34.31,20.1-114.01,53.68-126.53c3.84-12.82,10.48-73.87,24.02-73.1
 | 
				
			||||||
 | 
					c12.83-0.56,65.91-1.83,35.15,7.41c-61.79-15.5-48.75,200.28-45.07,243.92c2.25,20.42,27.14,13.8,38.12,25.45
 | 
				
			||||||
 | 
					c6.03,4.39,36.44,27.66,18.27,21.91c-40.8-27.63-66.71-54.35-46.2,16.36c-19.89-38.23,1.59-50.13-50.98-60.73
 | 
				
			||||||
 | 
					c8.31-2.96,35.82,10.04,30.87-4.68c-5.47-26.59-6.9-54.75-14.96-80.46c-22.25,80.4-137.99,191.25-134.59,255.33
 | 
				
			||||||
 | 
					c28.43-24.91,73.72-62.68,120.64-46.55c78.08,7.49,7.79-16.2-21.17-22.89c25.68-8.32,88.81,23.09,96.53,50.48
 | 
				
			||||||
 | 
					c-14.88-13.87-8.97-8.07-4.72,6.57c-20.12-14.39-11.58-35.73-44.46-26.75c28.79,18.11,36.81,27.82,49.27,59.28
 | 
				
			||||||
 | 
					c-15.78,0.19,5.06,35.44-28.02-9.3c-39.56-53.22-130.39-50.05-158.76,12.21c-0.57,107.56,60.34,213.63,68.06,323.78
 | 
				
			||||||
 | 
					c1.71,10.93,25.65,17.02,33.27,28.59c-11.57-2.96-19.66-12.97-31.03-16.47c-1.22,193.89-65.94,75.43,75.87,233.86
 | 
				
			||||||
 | 
					c-37.15-15.29-59.1-63.14-92.21-88.24c-15.18-7.04-28.22,43.71-46.26,43.68c57.38-81.24-1.81-123.16,10.19-218.4
 | 
				
			||||||
 | 
					c8.56,76.16-24.52,144.42-59.52,208.52c-8.14,12.44,0.12,54.47-13.87,54.44c9.71-16.15,13.17-61.15-18.44-81.22
 | 
				
			||||||
 | 
					C166.51,916.66,113.43,878.18,66.36,818.02z M925.87,407.64c-54.74-44.89,19.53-197.95-29.21-257.87
 | 
				
			||||||
 | 
					c-7.8,0.23,0.01,139.34-12.78,138.06c-0.76-11.74,2.94-57.56-13.24-57.45c-12.13,43.49-18.05,56.87-20.76,56.35
 | 
				
			||||||
 | 
					c-3.44-0.66-1.37-22.36-9.37-26.3c-1.4-0.69-3.39-0.47-6.27,1.08c-37.75,31.13-5.8-23.15-21.95-34.81
 | 
				
			||||||
 | 
					c-10.77-4.3-7.19,51.51-13.81,37.09c-6.3-84.43-23.11-192.91-70.65-258.62c15.21,86.12,50.46,187.09,38.31,278.79
 | 
				
			||||||
 | 
					c-21.94-86.63-52.72-175.52-70.62-266.49c2.29-9.8-18.19-21-13.94-4.4c30.28,57.1,21.26,334.09,14.6,185.12
 | 
				
			||||||
 | 
					c-1.5-9.87,2.15-67.2-7.12-67.14c-2.9,30.13-5.79,60.27-8.69,90.4c-32.81-59.32-16.97-176.63-52.31-212.83
 | 
				
			||||||
 | 
					c11.12,94.4-6.13,188.39-24.34,280.85c3.07-43.88,20.04-96.61,8.43-137.16c-6.3,14.9-20.93,66.96-26.59,61.57
 | 
				
			||||||
 | 
					c-8.59-0.89-9.05-48.09-14.45-48.15c-3.39-0.04-6.04,18.34-7.95,31.07c-7.59,50.46-15.93,93.98-17.18,93.85
 | 
				
			||||||
 | 
					c8.57-40.75,5.67-198.5-18.91-251.56c4.95,62.89-1.02,125.94-10.23,188.11c3.54-69.31,13.94-164.75-15.9-222.74
 | 
				
			||||||
 | 
					c32.11,126.08-28.75,489.29,30.52,197.35c28.79,98.72-65.28,261.35,58.73,108.86c-37.19,187.32,36.13-32.28,47.76-103.08
 | 
				
			||||||
 | 
					c8.96,94.67-2.01-42.55,6.66-79.88c30.75,97.92,53.06,199.4-5.06,292.92C737.6,336.4,694.28,5.48,752.2,275.59
 | 
				
			||||||
 | 
					c12.58,35.83-30.59,24.88-39.09,50.66c61.29-24.55,38.95-35.44,52.83,53.39c0.4,3.52-0.24,7.19-4.7,7.28
 | 
				
			||||||
 | 
					c-25.86,1.03-45.18,18.23-57.25,38.9c13.43-3.39,50.98-46.17,61.23-33.44c-21.97,29.52-78.97,40.99-72.67,90.22
 | 
				
			||||||
 | 
					c3.55-15.72,78.25-89.59,75.21-54.58c-1.37,4.97-0.6,13.02-7.63,13.72c-61.1,2.32-80.25,119.34-40.63,125.28
 | 
				
			||||||
 | 
					c-13.21-11.3-15.2-27.18-9.08-34.25c7.41-8.57,27.36-4.95,29.07,0.51c0.78,2.5-2.15,5.13-0.96,7.46c0.58,1.13,2.72,1.77,8.48,1.56
 | 
				
			||||||
 | 
					c38.89-7.77,7.11,28.36-12.62,33.66c17.65,7.15,41.53-6.09,43.26-25.21c-13.61-10.4-3.01-29.64,12.23-22.19
 | 
				
			||||||
 | 
					c39.17-39.2-23.35-78.46-17.83-98.65c2.53-4.97,11.94-9.86,47.83-3.67c17.2,5.95,27.38,81.41,34.69,33.83
 | 
				
			||||||
 | 
					c26.79,65.65,1.08,95.95-22.65,157.49c-19.8,84.29-61.4,159.4-148.77,185.06c-117.87,55.02-132.92,97.58-258.09,25.2
 | 
				
			||||||
 | 
					c46.48,32.06,76.67,55,136.6,42.95c-16.18,37.26-58.98,60.98-65.42,102.39c20.1-25.76,40.19-51.51,60.29-77.27
 | 
				
			||||||
 | 
					c-8.67,85.19,10.27,58.11-48.65,125.91c90.48-25.72,17.5-180.83,122.56-177.14c18.96,52.7-4.18,120.02,8.63,173.54
 | 
				
			||||||
 | 
					c2.68-39.19,12.24-88.12,46.19-106.21c456.17,81.79,348.93-736.88,256.65-896.72c22.97,42.24,68.59,278.45,36,201.55
 | 
				
			||||||
 | 
					c-3.91-9.81-16.93-10.42-12.04,2.06c-3.92,64.31,14.29,179.15-11.75,192.94z M348.31,563.23c5.68,9.7,20.47-3.9,12.83-8.26c-3.76-6.73-7.6-13.49-12.17-19.69
 | 
				
			||||||
 | 
					c-8.79-11.93,9.75-6.48,8.3-13.53c21.55,9.97,28.08,14.2,46.14-5.3c-0.61,18.31-0.16,38.03-18.36,50.23
 | 
				
			||||||
 | 
					c18.72,10.53,30.46-6.95,33.62-24.89c-25.93,2.12,1.38-48.33,8.9-22.45c7.53-11.49,6.87-26.71,9.65-39.21
 | 
				
			||||||
 | 
					C420.8,350.18,268.58,459.17,348.31,563.23z M517.13,804.37c-10.18-5.07-29.37-7.14-13.37-22.49
 | 
				
			||||||
 | 
					c18.15-20.96,102.96-23.38,73.03,12.59c29.3-17.57-7.7-35.22-30.46-31.69C518.69,758.1,459.7,799.43,517.13,804.37z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M106.8,0c-3.3,4.6-6.3,9.4-8.8,14.5c-2.8-5-5.7-9.8-8.8-14.5C52.9,32.5,56.8,74.2,98,99.6c0,0,0,0,0,0c0,0,0,0,0,0C139.5,74,142.9,32.2,106.8,0z M5.4,60.7c3.7,4.5,7.4,8.8,11,12.8c-5.4,1-10.9,2.3-16.5,3.9 c19.6,44.6,60.5,53.8,97.4,22.5c0,0,0,0,0,0c0,0,0,0,0,0C85.9,52.4,47.2,36.3,5.4,60.7z M31.2,174.9c5.3-1.5,10.5-3.8,15.6-6.6c-0.8,5.7-1.2,11.3-1.4,16.8c48.5-4.9,69.9-40.9,51.5-85.7c0,0,0,0-0.1,0c0,0,0,0,0,0C48.2,95.8,20.9,127.6,31.2,174.9zM148.3,186.1c-0.4-5.5-0.9-11.1-1.4-16.8c5.1,2.4,10.3,4.6,15.6,6.6c10.4-47.6-17.3-79.1-65.6-75.5c0,0,0,0,0,0c0,0-0.1,0-0.1,0C78.3,145.5,100.1,181.3,148.3,186.1z M195.1,76.9c-5.9-1.5-11.5-2.9-16.5-3.9c3.9-4,7.6-8.3,11-12.8c-42.1-24.6-80.6-8-92.1,39.1c0,0,0,0,0,0c0,0,0,0,0,0C134.9,130.9,175.6,121.2,195.1,76.9z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M35.2,14.9c-2.4,0-4.8,1-6.5,2.7c-1.7-1.7-4.1-2.7-6.5-2.7c-5.6,0.2-10,5-9.8,10.6c0,9.7,13.1,17.8,14.6,18.6c1,0.6,2.3,0.6,3.3,0C31.8,43.2,45,35.2,45,25.5C45.2,19.8,40.8,15.1,35.2,14.9z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M140 20C73 20 20 74 20 140c0 135 136 170 228 303 c88-132 229-173 229-303 c0-66-54-120-120-120c-48 0-90 28-109 69c-19-41-60-69-108-69z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M96,2.86c-2.05,4.41-4.22,9.48-6.33,15.17
 | 
				
			||||||
 | 
						c-1.08,2.92-3,8.28-4.95,15.1c-3.16,11.03-4.62,19.6-5.81,26.71c-2.49,14.88-3.28,26.75-3.45,30.36c-0.02,0.43-0.08,1.78-0.2,3.64
 | 
				
			||||||
 | 
						c-0.36,5.44-0.87,9.65-1.16,11.83c0,0-0.56,4.27-1.3,8.34c-0.19,1.07-0.4,2.13-0.4,2.13c-0.02,0.09-0.03,0.16-0.03,0.17
 | 
				
			||||||
 | 
						c-0.05,0.25-5.9,30.37-5.91,40.92c0,0.85,0.03,3.62-1.34,4.24c-0.46,0.21-0.96,0.13-1.34,0.01c-7.07,0.06-12.87,0.76-16.99,1.42
 | 
				
			||||||
 | 
						c0,0-13,2.1-30.7,9.21c-3.62,1.46-7.03,3-7.34,3.14c-2.48,1.13-4.67,2.19-6.52,3.12c1.83-0.17,4-0.52,6.39-1.21
 | 
				
			||||||
 | 
						c1.84-0.53,3.45-1.16,4.82-1.78c0,0,10.45-3.6,19.4-5.26c5.58-1.03,6.34-0.55,17.45-1.7c6.41-0.66,11.59-1.36,14.88-1.84
 | 
				
			||||||
 | 
						c7.74-1.12,10.4-0.32,11,1.04c0.13,0.29,0.13,0.55,0.11,0.94c-0.24,5.58-3.01,9.41-2.26,13.44c0.04,0.22,0.07,0.33,0.33,1.59
 | 
				
			||||||
 | 
						c0.13,0.62,0.56,2.75,0.85,4.34c0.4,2.22,0.41,2.72,0.72,4.65c0.6,3.67,0.9,5.5,1.48,6.82c1.14,2.59,2.86,4.11,4.88,5.88
 | 
				
			||||||
 | 
						c2.01,1.76,3.74,2.73,6.91,4.49c2.61,1.45,4.85,2.52,6.44,3.23z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M12.43,1.78c0.4,0.5,0.94,1.28,1.36,2.32
 | 
				
			||||||
 | 
						c0.67,1.66,0.67,3.07,0.67,4.45c0,0.92,0.04,4.84,0,6.15c-0.19,6.59,0.61,7.24,0,11.71c-0.34,2.51-0.83,4.02-1.19,4.96
 | 
				
			||||||
 | 
						c-0.18,0.48-0.94,2.43-2.52,4.74c-0.44,0.64-1.1,1.54-3.04,3.63c-3.35,3.61-5.27,4.39-5.19,5.19c0.13,1.28,5.07,2.54,25.78,2.55z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M105,654.21c-7.27-2.1-16.75-4.87-27.83-8.17
 | 
				
			||||||
 | 
						c-40.23-11.98-49.04-15.35-58.28-22.6c-5.71-4.47-14.05-12.37-21.32-25.91C2.14,588.3,8.74,575.32,17.11,560
 | 
				
			||||||
 | 
						c13.51-24.74,22.16-40.57,35.49-58.91c7.85-10.79,19.4-25.32,35.36-41.18c0.72-5.12,1.23-9.06,1.53-11.49
 | 
				
			||||||
 | 
						c0.57-4.57,0.8-6.77,2.34-9.27c1.46-2.37,3.38-3.84,4.75-4.7c0.63-143.54,1.26-287.08,1.89-430.62z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M204.68,0.14c-1.76,0.11-4.62,0.27-8.17,0.38
 | 
				
			||||||
 | 
						c-6.7,0.21-8.06-0.01-10.6,0.77c-3.92,1.2-3.97,2.71-8.07,4.59c-2.36,1.08-3.84,1.26-12.22,2.17c-5.45,0.59-10.87,1.53-16.34,1.91
 | 
				
			||||||
 | 
						c-5.84,0.41-9.63,0.36-12,3.2c-1.04,1.25-1.47,2.63-1.66,3.56c-3.32,18.64-2.48,32.37-1.02,41.62c0.57,3.57,3.63,21.7,0.89,34.76
 | 
				
			||||||
 | 
						c-0.17,0.79-0.64,2.93-1.15,5.97c-0.28,1.67-1.58,9.69-1.66,17.62c-0.05,5.4,1.24,12.84,3.83,27.7c0.5,2.88,1.27,7.13,2.17,13.28
 | 
				
			||||||
 | 
						c0.59,4.02,1.01,7.31,1.28,9.45c-0.52,3.62-0.43,6.53-0.26,8.55c0.29,3.26,0.86,4.56,0.13,6.77c-0.77,2.31-1.92,2.45-2.43,4.85
 | 
				
			||||||
 | 
						c-0.48,2.29,0.42,2.86-0.15,4.95c-0.41,1.49-1.13,2.2-2.79,4.24c-1.48,1.82-2.74,3.8-4.21,5.62c-4.31,5.35-8.49,10.81-12.89,16.09
 | 
				
			||||||
 | 
						c-5.78,6.93-6.86,8.58-17.49,21.96c-18.52,23.3-21.63,26.32-32.55,40.21c-24.98,31.79-37.81,53.07-40.72,57.96
 | 
				
			||||||
 | 
						c0,0-7.82,13.11-17.62,36.64c-2.39,5.73-5.45,13.54-6.38,24.13c-0.58,6.56-0.34,12.62,0,12.64c0.41,0.02,0.43-8.67,2.7-18.95
 | 
				
			||||||
 | 
						c1.86-8.39,4.48-14.51,8.17-22.47c8.35-18.03,12.53-27.04,19.74-39.15c9.69-16.26,19.31-28.61,38.55-53.32
 | 
				
			||||||
 | 
						c5.65-7.26,4.63-5.77,17.11-21.45c13.19-16.57,27.11-32.56,39.85-49.48c0.35-0.47,1.41-1.88,3.13-3.42c0,0,2.37-2.12,5.36-3.58
 | 
				
			||||||
 | 
						c6.09-2.99,20.05-2.23,25.95-2c7.4,0.28,14.81-0.1,22.22-0.1c8.52,0,15.39-0.01,19.63-0.01z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M0.94,0.6c2.08,18.15,2.97,32.18,3.39,41.88
 | 
				
			||||||
 | 
						c0,0,0.86,19.42,2.87,34.97c1.76,13.6,2.61,14.56,5.45,32.49c1.14,7.2,1.2,8.27,5.73,44.13c3.64,28.81,4.03,31.51,4.32,38.54
 | 
				
			||||||
 | 
						c0.2,4.94,0.57,17.17-0.63,32.88c-0.89,11.66-2.25,19.73-3,24.73c-3.72,24.69-3.65,45.64-3.59,66.15
 | 
				
			||||||
 | 
						c0.04,13.85,0.17,33.71,3.42,59.26c2.56,20.15,6,35.46,6.44,62.42c0.01,0.88,0.13,1.85,0.2,3.47c0.31,6.41-0.11,11.45-0.35,14.17
 | 
				
			||||||
 | 
						c-3.35,37.28-5.52,47.52-5.52,47.52c-1.06,4.71-2.95,10.98-0.08,13.41c1.1,0.94,2.42,0.94,9.8,0.98c3.87,0.02,7.02,0.04,8.28,0.05z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M9.22,0C6.92,4.49,4,11.35,2.55,20.09
 | 
				
			||||||
 | 
						c-1.21,7.29-0.82,12.5-0.33,20.94C3.3,59.23,3.79,73.41,3.9,76.76c0.65,20.48-0.9,19.3,0.05,35.96c0.7,12.33,2.2,24.62,2.98,30.95
 | 
				
			||||||
 | 
						c1.78,14.5,2.82,18.69,2.45,27.6c-0.42,10.1-1.94,8.9-2.49,20.33c-0.54,11.15,0.83,13.91,0.19,27.57c-0.35,7.5-0.78,6.96-0.98,13.91
 | 
				
			||||||
 | 
						c-0.12,4.35-0.01,6.38,0.61,21.61c0.24,5.92,0.64,10.99,0.78,17.78c0.12,6.38,0.06,11.89,0.02,14.77
 | 
				
			||||||
 | 
						c-0.07,5.78-0.11,8.68-0.27,11.31c-0.96,16.14-5.06,22.75-1.69,25.57c0.93,0.78,1.57,0.55,8.39,0.78c4.83,0.16,8.78,0.42,11.44,0.61z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M
 | 
				
			||||||
 | 
					M7.97,1.32c-1.2,2.4-2.58,5.53-3.81,9.3c-1.89,5.82-2.51,10.42-2.64,11.39c-0.28,2.2-0.69,6.44,0.73,18.39c0.57,4.79,1.47,11.13,2.94,18.58c0.94,0.01,1.87,0.03,2.81,0.04z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _NDEBUG
 | 
				
			||||||
 | 
					    precision highp float;
 | 
				
			||||||
 | 
					    const int ns = 5;
 | 
				
			||||||
 | 
					    const int cns = 5;
 | 
				
			||||||
 | 
					    float noise(vec3 v){return 1.;}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					uniform vec3 starColors[10];
 | 
				
			||||||
 | 
					uniform vec3 V0;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					varying vec3 texPos;
 | 
				
			||||||
 | 
					vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 color =foregroundColor.xyz;
 | 
				
			||||||
 | 
					   float sp = 0.4, df = 0.4, amb = 0.4, ex=5., alpha = 1.;
 | 
				
			||||||
 | 
					   vec3 l = vec3(1,1,1);
 | 
				
			||||||
 | 
					   float alp = 2.*abs(.49999 - fract(id+.00001));
 | 
				
			||||||
 | 
					   if(id <-1.5) {color = vec3(.05,.05,.05);sp = 1.; df=.4; amb = .3, ex = 5.;}
 | 
				
			||||||
 | 
					   else if(id <-.5) {color = vec3(0.,1.,0.2034);}
 | 
				
			||||||
 | 
					   else if(id < 1.5) {color = vec3(1.0000, 0.659, 0.0384);sp = .2; df=.4; amb = .7, ex = 1.;l = color = vec3(1.0000, 0.7, 0.04);}
 | 
				
			||||||
 | 
					   else if (id < 2.5) color = vec3(1.,.16,.36);
 | 
				
			||||||
 | 
					   else if (id < 3.5) {color = vec3(1.0000, 0.7725, 0.7725);sp = .5; df=.8; amb = .05;}
 | 
				
			||||||
 | 
					   else if (id < 4.5) {color = vec3(0.9612,0.3057,0.3369);sp = .5; df=.5; amb = .5; ex=20.;}
 | 
				
			||||||
 | 
					   else if (id < 6.5) {}
 | 
				
			||||||
 | 
					   else if (id < 7.5) {color = starColors[0]; sp = 0.3, df = 0.3, amb = 0.8, ex=5.;}
 | 
				
			||||||
 | 
					   else if (id < 8.5) {color = starColors[1]; sp = 0.05, df = 0.1, amb = 0.8, ex=10.,l = color;alp*=1.1;}
 | 
				
			||||||
 | 
					   else if (id < 9.5) {color = starColors[2]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 10.5) {color = starColors[3]; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 12.5) {color = starColors[4]; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 13.5) {color = starColors[4]*2.; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 14.5) {
 | 
				
			||||||
 | 
					       color = .4*foregroundColor + .8*starColors[4]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;
 | 
				
			||||||
 | 
					        if(texPos.y > .3)
 | 
				
			||||||
 | 
					            color = vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (id < 15.5) {color = .3*vec3(0.9612,0.3057,0.3369)+.8*starColors[4]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 16.5) {gl_FragColor=vec4(1.,1.,1., alp);return;}
 | 
				
			||||||
 | 
					   else if (id < 17.5) {color = vec3(.35,.35,.35);sp = .3; df=.6; amb = .1, ex = 1.;} 
 | 
				
			||||||
 | 
					   else if (id < 18.5) {
 | 
				
			||||||
 | 
					       color = vec3(.6,.29,.12);sp = .1; df=.2; amb = .7, ex = 1.;
 | 
				
			||||||
 | 
					       vec3 P = vec3(sin(texPos.y*1.), sin(texPos.x*1.5+1.),  cos(texPos.z*1.));
 | 
				
			||||||
 | 
					   // APPLY PROCEDURAL NOISE TEXTURE.
 | 
				
			||||||
 | 
					       float cloud = min(0.99, max(0., 1. * noise(.8 * P)));
 | 
				
			||||||
 | 
					       color =  (1.-cloud)*color + starColors[5] * cloud*3.;
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					   else if (id < 19.5) {color = vec3(.4,.4,.4);sp = .0; df=.0; amb = 1., ex = 1.,alp=1.;} 
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   if(id < 0. &&id > -1.5){
 | 
				
			||||||
 | 
					       vec3 P = vec3(sin(glpos.y*1.), sin(glpos.x*1.5+1.),  cos(glpos.z*1.));
 | 
				
			||||||
 | 
					   // APPLY PROCEDURAL NOISE TEXTURE.
 | 
				
			||||||
 | 
					       float cloud = min(0.99, max(0., 1. * noise(1. * P)));
 | 
				
			||||||
 | 
					       color =  (1.-cloud)*color + starColors[5] * cloud*3.;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=normalize(glpos-V);
 | 
				
			||||||
 | 
					   vec3 realLDir=normalize(LDir - glpos);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   color = color*(amb+ df*max(0.,dot(norm,realLDir)))
 | 
				
			||||||
 | 
					                        + sp*pow(max(0., dot(2.*dot(norm, realLDir)*norm-realLDir, -W)),ex)*l;
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(color), alp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					uniform mat4 uMatrix;
 | 
				
			||||||
 | 
					uniform mat4 invMatrix;
 | 
				
			||||||
 | 
					uniform mat3 transformation;
 | 
				
			||||||
 | 
					attribute float oid;
 | 
				
			||||||
 | 
					attribute vec3 aPos;
 | 
				
			||||||
 | 
					attribute vec3 normal;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					varying vec3 texPos;
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    vec4 pos = uMatrix * vec4(aPos, 1.);
 | 
				
			||||||
 | 
					    texPos = aPos;
 | 
				
			||||||
 | 
					    gl_Position = pos ;
 | 
				
			||||||
 | 
					    glpos = pos.xyz;
 | 
				
			||||||
 | 
					    id = oid;
 | 
				
			||||||
 | 
					    norm = normalize(vec4(normal,0.)*invMatrix).xyz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 11 MiB  | 
@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					# graphics_hw2
 | 
				
			||||||
 | 
					[link](https://billsun.dev/graphics/hw2)
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.5 KiB  | 
| 
		 After Width: | Height: | Size: 6.7 KiB  | 
@ -0,0 +1,350 @@
 | 
				
			|||||||
 | 
					<script src=lib2.js></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					<center>
 | 
				
			||||||
 | 
					   <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					<canvas id='canvas1' style="overflow: auto; width: 600px; height:600px;" width=1200 height=1200></canvas>
 | 
				
			||||||
 | 
					</center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_vertex_shader' type='x-shader/x-vertex'>
 | 
				
			||||||
 | 
					   attribute vec3 aPos;
 | 
				
			||||||
 | 
					   varying   vec3 vPos;
 | 
				
			||||||
 | 
					   void main() {
 | 
				
			||||||
 | 
					      gl_Position = vec4(aPos, 1.);
 | 
				
			||||||
 | 
					      vPos = aPos;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					<!--script src="shader.frag" id='my_fragment_shader' type='x-shader/x-fragment'> </script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- CREATE A PROPERLY DESCRIPTIVE TITLE BELOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_title' type='text/html'>
 | 
				
			||||||
 | 
					Solar RTX
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- HERE IS WHERE YOU CAN PROVIDE A LONGER TEXT DESCRIPTION -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_instructions' type='text/html'><font color=#909090>
 | 
				
			||||||
 | 
					<p style="font-size:30px; ">In this homework, I implemented Global illumination w/ 
 | 
				
			||||||
 | 
					   Realtime Recursive Ray Tracing! 
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					<i style="font-size:25px;">Usage: </i>
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+T: Toggle Texture.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+S: Download fragment shader.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+R: Toggle Recursive Ray Tracing.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+N: Reset ViewPoint.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+P: Toggle Pause/Resume.</li>
 | 
				
			||||||
 | 
					   <li style="color:red;">Please unfocus the Editing area (click somewhere else on the page) to use hotkeys.</li>
 | 
				
			||||||
 | 
					   <li>Double Click on canvas (WITHOUT key modifiers): Toggle Pause/Resume.</li>
 | 
				
			||||||
 | 
					   <li>MOUSE DRAG, SCROLL/WHEEL ZOOM: Changing Viewing point.</li>
 | 
				
			||||||
 | 
					   <li>Use Chromium based browser for better performance.</li>
 | 
				
			||||||
 | 
					</ul>
 | 
				
			||||||
 | 
					<i style="font-size:25px;">How it works:</i>
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					   <li>First, I started with what I've already done in <a href="https://billsun.dev/graphics/hw1">homework 1</a>. Which already included complete Phong shading with 
 | 
				
			||||||
 | 
					      Specular light and much more (spherical texture mapping, simple interactions, improved UI/shader editor).
 | 
				
			||||||
 | 
					   </li>
 | 
				
			||||||
 | 
					   <li> I then merged the code from hw2 and added texture to each sphere.</li>
 | 
				
			||||||
 | 
					   <li> I modified the ray tracing algorithm so that when hitting an object, instead of just returning color calculated from 
 | 
				
			||||||
 | 
					      Phong model:<br>
 | 
				
			||||||
 | 
					      <ul>
 | 
				
			||||||
 | 
					         <li>It recursively bounces and/or refract(NOT IMPLEMENTED YET) itself spawning new rays.</li>
 | 
				
			||||||
 | 
					         <li>The color of this pixel equals to Ambient + Diffuse + ks*color[Reflected] + kt*color[Refracted]. 
 | 
				
			||||||
 | 
					            (<a href="https://www.cs.drexel.edu/~david/Classes/Papers/p343-whitted.pdf">Turner Whitted Model</a>)</li>
 | 
				
			||||||
 | 
					         <li>The tracing will stop when a ray was not hitting any object or was reflected/refracted n_ref times. </li> 
 | 
				
			||||||
 | 
					         <li>The color/intensity of the final lights are computed via specular component from the Phong model.</li>
 | 
				
			||||||
 | 
					         <li>You may increase n_ref for more iterations, but please proceed with caution, because it may halt the computer.  
 | 
				
			||||||
 | 
					         </li>
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					   <li>I added more interactions, you can now change the viewpoint by 
 | 
				
			||||||
 | 
					      holding shift and alt key while dragging on canvas to rotate,
 | 
				
			||||||
 | 
					      or holding shift and alt while scrolling on canvas to change focal length.
 | 
				
			||||||
 | 
					      This is implemented by applying a transformation matrix to the viewpoint and projection surface.
 | 
				
			||||||
 | 
					   </li>   
 | 
				
			||||||
 | 
					   <li>Finally, I used super sampling via doubling the render dimensions of the canvas to reduce aliasing. SEE comments on index.html</li>
 | 
				
			||||||
 | 
					   <li>Repo on <a href="https://github.com/sunyinqi0508/graphics_hw1">Github</a>.</li>
 | 
				
			||||||
 | 
					   </li>
 | 
				
			||||||
 | 
					 </ul>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CREATE THE HTML DOCUMENT
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					let vs = my_vertex_shader.innerHTML;
 | 
				
			||||||
 | 
					    //* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					    var client = new XMLHttpRequest();
 | 
				
			||||||
 | 
					    client.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					    client.onloadend = function() {
 | 
				
			||||||
 | 
					      fs = (client.responseText);
 | 
				
			||||||
 | 
					      //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					      gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					      editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					      editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					         if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					            setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   client.send();
 | 
				
			||||||
 | 
					document.body.innerHTML = [''
 | 
				
			||||||
 | 
					   ,'<font size=7 color=#909090>' + my_title.innerHTML
 | 
				
			||||||
 | 
					   ,'<img id="rtx" style="float:right;" src="./RTXon.svg" type="image/svg+xml"'
 | 
				
			||||||
 | 
					   ,' alt="Turn Ray Tracing On/OFF" title="Turn Ray Tracing On/OFF" height=60px /img>' 
 | 
				
			||||||
 | 
					   ,'<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>' 
 | 
				
			||||||
 | 
					   ,'<TABLE cellspacing=0 cellpadding=0><TR>'
 | 
				
			||||||
 | 
					   ,'<td><font color=red size=5><div id=errorMessage></div></font></td>'
 | 
				
			||||||
 | 
					   ,'</TR><TR>'
 | 
				
			||||||
 | 
					   ,'<table cellspacing=0>'
 | 
				
			||||||
 | 
					   ,'<tr>'
 | 
				
			||||||
 | 
					   ,'<td valign=top>'
 | 
				
			||||||
 | 
					   ,'<div id="ace" style="width:800px;height:2200px;"></div>'
 | 
				
			||||||
 | 
					   ,'</td><td valign=top>' + document.body.innerHTML
 | 
				
			||||||
 | 
					   ,'<input type="number" id="ins" style="margin-left:3px;font-size:24px;width:100px;height:45px" value="4">'
 | 
				
			||||||
 | 
					   ,'<button id="bns" style="margin-left:5px;font-size:24px;width:150px;height:45px">Set Spheres</button>'
 | 
				
			||||||
 | 
					   ,'<div style=\'font-size:25px\'>' + my_instructions.innerHTML + '</div>' + '</td>'
 | 
				
			||||||
 | 
					   ,'</tr></table>'
 | 
				
			||||||
 | 
					   ,'</TR></TABLE>'
 | 
				
			||||||
 | 
					   ].join('');
 | 
				
			||||||
 | 
					bns.onclick=function(e){
 | 
				
			||||||
 | 
					   if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
 | 
				
			||||||
 | 
					   {   
 | 
				
			||||||
 | 
					      cns = ins.value;
 | 
				
			||||||
 | 
					      fragmentShaderDefs = '\n const int cns = ' + cns + ';';
 | 
				
			||||||
 | 
					      if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					            setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					delete editor.KeyBinding;
 | 
				
			||||||
 | 
					let lastTime = Date.now();
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
 | 
				
			||||||
 | 
					let mousedx = 0, mousedy = 0, mousedz = 0;
 | 
				
			||||||
 | 
					let cx = 1, cy = 1, sx = 0, sy = 0;
 | 
				
			||||||
 | 
					let mouselastX, mouselastY;
 | 
				
			||||||
 | 
					let lastClick = undefined;
 | 
				
			||||||
 | 
					let pause_resume = function(){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					         lastTime = Date.now();
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					      animating = !animating;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(!(shift && alt) && lastClick&& Date.now()-lastClick<400)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   lastClick = Date.now();
 | 
				
			||||||
 | 
					   //moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseover', function(e){
 | 
				
			||||||
 | 
					   over = true;
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags |= mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousedown', function(e){
 | 
				
			||||||
 | 
					      moving = true
 | 
				
			||||||
 | 
					      mouselastX = mouselastY =  undefined;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousemove', function(e){
 | 
				
			||||||
 | 
					      if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
 | 
				
			||||||
 | 
					         mousedx -= (mouselastX - e.offsetX)/60;
 | 
				
			||||||
 | 
					         mousedy -= (mouselastY - e.offsetY)/60;
 | 
				
			||||||
 | 
					         cx = Math.cos(mousedx);
 | 
				
			||||||
 | 
					         sx = Math.sin(mousedx);
 | 
				
			||||||
 | 
					         cy = Math.cos(mousedy);
 | 
				
			||||||
 | 
					         sy = Math.sin(mousedy);
 | 
				
			||||||
 | 
					         setUniform('4f', 'rot', cx, sx, cy, sy);
 | 
				
			||||||
 | 
					         const mask = 0x4;
 | 
				
			||||||
 | 
					         flags |= mask;
 | 
				
			||||||
 | 
					         setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // if(over){
 | 
				
			||||||
 | 
					      //    let x=e.offsetX/300-1;
 | 
				
			||||||
 | 
					      //    let y=e.offsetY/300-1;
 | 
				
			||||||
 | 
					      //    let z=-1-3-mousedz;
 | 
				
			||||||
 | 
					      //    let tx = cx*x+sy*sx*y+sx*cy*z;
 | 
				
			||||||
 | 
					      //    let ty = cy*y-sy*z;
 | 
				
			||||||
 | 
					      //    let tz = -sx*x+cx*sy*y+cx*cy*z;
 | 
				
			||||||
 | 
					      //    let len = Math.sqrt(tx*tx + ty*ty+tz*tz);
 | 
				
			||||||
 | 
					      //    setUniform('3f', 'fDir', tx/len, ty/len, tz/len);
 | 
				
			||||||
 | 
					      // }
 | 
				
			||||||
 | 
					      mouselastX = e.offsetX;
 | 
				
			||||||
 | 
					      mouselastY = e.offsetY;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseup', function(e){
 | 
				
			||||||
 | 
					   // if(ctrl && alt && moving){
 | 
				
			||||||
 | 
					   // }
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseout', function(e){
 | 
				
			||||||
 | 
					   // if(ctrl && alt && moving){
 | 
				
			||||||
 | 
					   // }
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags &= !mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   over = false;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('wheel', function(e){
 | 
				
			||||||
 | 
					      mousedz += e.wheelDelta/600;
 | 
				
			||||||
 | 
					      setUniform('1f', 'dFL', mousedz);
 | 
				
			||||||
 | 
					      e.stopImmediatePropagation();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.scroll(function(e) {e.stopPropagation();});
 | 
				
			||||||
 | 
					rtx.style.cursor="pointer";
 | 
				
			||||||
 | 
					let rtswitch = function(){
 | 
				
			||||||
 | 
					   const mask = 0x2;
 | 
				
			||||||
 | 
					   let rtstatus = !(flags&mask);
 | 
				
			||||||
 | 
					   if (rtstatus)
 | 
				
			||||||
 | 
					      rtx.src='./RTXoff.svg';
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					   flags = (flags&(!mask)) | (rtstatus?mask:0);
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					rtx.addEventListener('click', rtswitch);
 | 
				
			||||||
 | 
					var requestAnimationFrame = window.requestAnimationFrame ||
 | 
				
			||||||
 | 
					 window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 | 
				
			||||||
 | 
					let fpscounter = function(time){
 | 
				
			||||||
 | 
					      if (start === undefined)
 | 
				
			||||||
 | 
					         start = time;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
 | 
				
			||||||
 | 
					      start = time;
 | 
				
			||||||
 | 
					      if(fpson)
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         start = undefined;
 | 
				
			||||||
 | 
					         fps.innerHTML = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = true;
 | 
				
			||||||
 | 
					   else if(ctrl && alt && e.code == 'KeyT'){
 | 
				
			||||||
 | 
					      const mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)?mask:0);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (ctrl &&e.code == 'KeyS'){
 | 
				
			||||||
 | 
					      let a = document.createElement('a');
 | 
				
			||||||
 | 
					      a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
 | 
				
			||||||
 | 
					      a.download = 'shader.frag';
 | 
				
			||||||
 | 
					      a.click();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyR')
 | 
				
			||||||
 | 
					      rtswitch();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyN')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      flags = 0;
 | 
				
			||||||
 | 
					      moving = false;
 | 
				
			||||||
 | 
					      mousedx = mousedy = mousedz = 0;
 | 
				
			||||||
 | 
					      cx = Math.cos(mousedx);
 | 
				
			||||||
 | 
					      sx = Math.sin(mousedx);
 | 
				
			||||||
 | 
					      cy = Math.cos(mousedy);
 | 
				
			||||||
 | 
					      sy = Math.sin(mousedy);
 | 
				
			||||||
 | 
					      rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					      setUniform('4f', 'rot', cx, sx, cy, sy);
 | 
				
			||||||
 | 
					      setUniform('1f', 'dFL', mousedz);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyP')
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyF')
 | 
				
			||||||
 | 
					      if(!fpson)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         fpson = true;
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fpson = false;
 | 
				
			||||||
 | 
					   // else if(e.code =='KeyV')
 | 
				
			||||||
 | 
					   //    alert(' '+ mousedx+ ' ' + mousedy + ' '+mousedz)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// SET THE CURRENT TIME IN SECONDS BEFORE RENDERING EACH FRAME.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let startTime = Date.now();
 | 
				
			||||||
 | 
					let lastFrameTime = 0;
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', (Date.now() - startTime) / 1000);
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', (lastTime - startTime) / 1000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,185 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					let ns = 4, cns = 4;
 | 
				
			||||||
 | 
					fragmentShaderHeader+= 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					let fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;         // IS THIS THE FIREFOX BROWSER?
 | 
				
			||||||
 | 
					let errorMsg = '';
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Initialize a texture and load an image.
 | 
				
			||||||
 | 
					// When the image finished loading copy it into the texture.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					     bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   } 
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let texture = [], gl, program;
 | 
				
			||||||
 | 
					let textures = []; 
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   // Because images have to be downloaded over the internet
 | 
				
			||||||
 | 
					   // they might take a moment until they are ready.
 | 
				
			||||||
 | 
					   // Until then put a single pixel in the texture so we can
 | 
				
			||||||
 | 
					   // use it immediately. When the image has finished downloading
 | 
				
			||||||
 | 
					   // we'll update the texture with the contents of the image.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      // WebGL1 has different requirements for power of 2 images
 | 
				
			||||||
 | 
					      // vs non power of 2 images so check if the image is a
 | 
				
			||||||
 | 
					      // power of 2 in both dimensions.
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         // Yes, it's a power of 2. Generate mips.
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         // No, it's not a power of 2. Turn off mips and set
 | 
				
			||||||
 | 
					         // wrapping to clamp to edge
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = '<br>';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader +fragmentShaderDefs+ fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; ++i){
 | 
				
			||||||
 | 
					            loadTexture(gl, './'+(i+1)+'.jpg', i); //Texture loading.
 | 
				
			||||||
 | 
					            textures[i] = i;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
 | 
				
			||||||
 | 
					         setUniform('4f', 'rot', Math.cos(mousedx), Math.sin(mousedx), Math.cos(mousedy), Math.sin(mousedz));
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					            [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 0, 0);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					   (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,252 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604); 
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform int flags;
 | 
				
			||||||
 | 
					//FLAGS 0-TEX, 1-RT, 2-MOVED, 3-FLASH, 4-TEX_ROT, 5-CLOUD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform vec4 rot; //ROTATION VALUES USED TO CALCULATE TRANSFORMATION MATRIX
 | 
				
			||||||
 | 
					//rot=[cosx, sinx, cosy, siny], x, y BING ROTATED ANGLE
 | 
				
			||||||
 | 
					uniform float dFL; //DELTA on FOCAL LENGTH
 | 
				
			||||||
 | 
					uniform vec3 fDir;//Flash light direction
 | 
				
			||||||
 | 
					varying vec3 vPos;// -1 < vPos.x < +1
 | 
				
			||||||
 | 
					// -1 < vPos.y < +1
 | 
				
			||||||
 | 
					//      vPos.z == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float fl=3.;//ORIGINAL FOCAL LENGTH
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					const int n_ref=5; //<<=======***********************MAX NUMBER OF RAY TRACING RECURRSIONS. INCREASE IT IF YOUR GRAPHICS CARD CAN HANDLE.**************************** 
 | 
				
			||||||
 | 
					//const int ns=4; ns is added from .js
 | 
				
			||||||
 | 
					vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					vec3 Ambient[ns];
 | 
				
			||||||
 | 
					vec3 Diffuse[ns];
 | 
				
			||||||
 | 
					vec4 Specular[ns];
 | 
				
			||||||
 | 
					float ks[ns];
 | 
				
			||||||
 | 
					struct Sphere{ //UPDATED SPHERE STRUCTURE THAT SUPPORTS TRANSPARENCY.(UNUSED)
 | 
				
			||||||
 | 
					   vec4 Pos;
 | 
				
			||||||
 | 
					   vec3 Ambient;
 | 
				
			||||||
 | 
					   vec3 Diffuse;
 | 
				
			||||||
 | 
					   vec4 Specular;
 | 
				
			||||||
 | 
					   int textureid;
 | 
				
			||||||
 | 
					   float ks, kt;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					struct RT{ //STACK FOR RECURSIVE RAY TRACING.
 | 
				
			||||||
 | 
					   vec3 color;
 | 
				
			||||||
 | 
					   float ks;
 | 
				
			||||||
 | 
					   // vec3 colorr;
 | 
				
			||||||
 | 
					   // float kt;
 | 
				
			||||||
 | 
					   // vec3 ptr;
 | 
				
			||||||
 | 
					   // vec3 normal;
 | 
				
			||||||
 | 
					} stack[n_ref];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool getflag(int flag,int bit){
 | 
				
			||||||
 | 
					   float shifted = float(int(float(flag)/ pow(2.,float(bit))));
 | 
				
			||||||
 | 
					   return fract(shifted/2.)>0.;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					float clampv(float val,float l,float h){
 | 
				
			||||||
 | 
					   return val<l?l:val>h?h:val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   ////////////////////////////////////////////////
 | 
				
			||||||
 | 
					   //
 | 
				
			||||||
 | 
					   // HERE, FOR YOUR HOMEWORK, YOU CAN WRITE ANY
 | 
				
			||||||
 | 
					   // CODE YOU LIKDEFINE A COLOR FOR THIS FRAGMENT.
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   // LIGHT DIRECTION AND COLOR
 | 
				
			||||||
 | 
					   //* I USED LDir AS LIGHT POSITION
 | 
				
			||||||
 | 
					   //* I NORMALIZED IT AFTER GETTING THE 
 | 
				
			||||||
 | 
					   //* DIRECTION BY SUBTRACTING IT FROM THE POINT
 | 
				
			||||||
 | 
					   vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					   vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   // SPHERE
 | 
				
			||||||
 | 
					   Sph[3]=vec4(.9*sin(uTime*.4),0.,.9*cos(uTime*.4),.25);
 | 
				
			||||||
 | 
					   Sph[2]=vec4(.22*sin(uTime*1.2),0.05,.22*cos(uTime*1.2),.02);
 | 
				
			||||||
 | 
					   Sph[0]=vec4(.45*sin(uTime),0.05*cos(uTime + 1.),.45*cos(uTime),.1);
 | 
				
			||||||
 | 
					   Sph[1]=vec4(0.,0.,0.,.15);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   // SURFACE REFLECTANCE PROPERTIES, can be transferred from .js
 | 
				
			||||||
 | 
					   Ambient[3]=vec3(.1,.1,.1);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[3]=vec3(.71,.71,.71);// r,g,b
 | 
				
			||||||
 | 
					   Specular[3]=vec4(.71,.71,.71,10.);// r,g,b,power
 | 
				
			||||||
 | 
					   Ambient[2]=vec3(.1,.05,.05);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[2]=vec3(.71,.71,.71);// r,g,b
 | 
				
			||||||
 | 
					   Specular[2]=vec4(.71,.71,.71,10.);// r,g,b,power
 | 
				
			||||||
 | 
					   Ambient[1]=vec3(.1,.05,.05);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[1]=vec3(1.,.5,.5);// r,g,b
 | 
				
			||||||
 | 
					   Specular[1]=vec4(1.,.5,.5,10.);// r,g,b,power
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   Ambient[0]=vec3(.05,.05,.1);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[0]=vec3(.5,.5,1.);// r,g,b
 | 
				
			||||||
 | 
					   Specular[0]=vec4(1.,.5,.5,20.);// r,g,b,power
 | 
				
			||||||
 | 
					   ks[0] = 0.25;
 | 
				
			||||||
 | 
					   ks[1] = 0.1;
 | 
				
			||||||
 | 
					   ks[2] = 0.3;
 | 
				
			||||||
 | 
					   ks[3] = 0.05;
 | 
				
			||||||
 | 
					   // INITIALIZE TO A BACKGROUND COLOR
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   float ca=rot.x, sa = rot.y, cb=rot.z, sb=rot.w;
 | 
				
			||||||
 | 
					   mat3 transformation, invTr;//Transformation matrix for viewpoint.
 | 
				
			||||||
 | 
					   transformation[0] = vec3(ca, sb*sa, sa*cb);//because the matrices are all the same,
 | 
				
			||||||
 | 
					   transformation[1] = vec3(0, cb, -sb);//We don't need to calculate it for every pixel
 | 
				
			||||||
 | 
					   transformation[2] = vec3(-sa,ca*sb,ca*cb);//So, we get it from the CPU
 | 
				
			||||||
 | 
					   invTr[0] = vec3(ca, 0, -sa);//it's inverse, to calculate texture mapping.
 | 
				
			||||||
 | 
					   invTr[1] = vec3(sa*sb, cb, ca*sb);
 | 
				
			||||||
 | 
					   invTr[2] = vec3(cb*sa, -sb, ca*cb);
 | 
				
			||||||
 | 
					   vec3 trPos = transformation*((dFL+fl+1.)/(fl+1.))*vec3(vPos.xy, -1);
 | 
				
			||||||
 | 
					   // COMPUTE THE RAY ORIGIN AND DIRECTION
 | 
				
			||||||
 | 
					   vec3 V0=transformation*vec3(0.,0.,fl+dFL), V = V0;
 | 
				
			||||||
 | 
					   vec3 W=normalize(trPos-V);
 | 
				
			||||||
 | 
					   // RAY TRACE TO ALL OBJECTS IN THE SCENE
 | 
				
			||||||
 | 
					   bool rtxoff = getflag(flags, 1), 
 | 
				
			||||||
 | 
					   showtexture = !getflag(flags,0), 
 | 
				
			||||||
 | 
					   moved = getflag(flags,2)//,
 | 
				
			||||||
 | 
					//   flash = true;//getflag(flags, 3)
 | 
				
			||||||
 | 
					   ;//get flags.
 | 
				
			||||||
 | 
					 //  bool hit = false;
 | 
				
			||||||
 | 
					   int cnt_ref = n_ref;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      float tMin=10000.;
 | 
				
			||||||
 | 
					      int iMin = -1;
 | 
				
			||||||
 | 
					      for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					         // SHIFT COORDINATES, SO THAT SPHERE IS AT (0,0,0)
 | 
				
			||||||
 | 
					         vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					         // SOLVE FOR QUADRATIC EQUATION IN t
 | 
				
			||||||
 | 
					         float B=dot(W,Vp);
 | 
				
			||||||
 | 
					         float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					         float D=B*B-C;
 | 
				
			||||||
 | 
					         if(D>0.){
 | 
				
			||||||
 | 
					            float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					            if(t > 0. && t < tMin){
 | 
				
			||||||
 | 
					               tMin = t; //This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					               iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // IF RAY HITS SPHERE
 | 
				
			||||||
 | 
					      if(iMin >= 0){
 | 
				
			||||||
 | 
					         float t = tMin;
 | 
				
			||||||
 | 
					         vec3 S=V+t*W;
 | 
				
			||||||
 | 
					         for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					            if(i == iMin) //* Because GLSL doesn't support non-const index, 
 | 
				
			||||||
 | 
					            {             //*  we have to get Sph[iMin], uSampler[iMin], etc. this way
 | 
				
			||||||
 | 
					               //*Good old TEXTURE MAPPING from hw1
 | 
				
			||||||
 | 
					               vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					               if(moved)
 | 
				
			||||||
 | 
					                  tex_sph=invTr*tex_sph;//* transform the sphere to original place if view point moved;
 | 
				
			||||||
 | 
					                                        //* This is super expensive! plus it's in the inner loop!!
 | 
				
			||||||
 | 
					                                        //* We added a flag to disable it when the viewport is not moved!
 | 
				
			||||||
 | 
					               float R=Sph[i].w;
 | 
				
			||||||
 | 
					               float tex_x=acos(abs(tex_sph.x)/sqrt(R*R-tex_sph.y*tex_sph.y));
 | 
				
			||||||
 | 
					               if(tex_sph.x>0.)
 | 
				
			||||||
 | 
					                  tex_x=pi-tex_x;
 | 
				
			||||||
 | 
					               tex_x*=1.5708;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					               tex_x=tex_x+float(uTime);
 | 
				
			||||||
 | 
					               float quo=float(int(tex_x/_2pi));
 | 
				
			||||||
 | 
					               tex_x=tex_x/_2pi -quo;
 | 
				
			||||||
 | 
					               vec3 texture_color;
 | 
				
			||||||
 | 
					               if(showtexture)
 | 
				
			||||||
 | 
					                  texture_color=texture2D(uSampler[i],vec2(tex_x,((R-tex_sph.y)/(2.*R)))).xyz;
 | 
				
			||||||
 | 
					               else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					               vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					               //*DIRECTIONS ARE NORMALIZED TO GET THE CORRECT PHONG LIGHTING
 | 
				
			||||||
 | 
					               vec3 realLDir=normalize(LDir-S); 
 | 
				
			||||||
 | 
					               color=(
 | 
				
			||||||
 | 
					                     Ambient[i]
 | 
				
			||||||
 | 
					                     +Diffuse[i]*max(0.,dot(N,realLDir))*LCol
 | 
				
			||||||
 | 
					                  )*texture_color
 | 
				
			||||||
 | 
					               ;
 | 
				
			||||||
 | 
					               // + SPECULAR COMPONENT GOES HERE
 | 
				
			||||||
 | 
					               if(rtxoff || j == n_ref - 1) //if it's the last ray
 | 
				
			||||||
 | 
					                  color += sqrt(float(j+1)) * Specular[i].xyz*pow(max(0.,
 | 
				
			||||||
 | 
					                  dot(2.*dot(N,realLDir)*N-realLDir,-W)),Specular[i].w);
 | 
				
			||||||
 | 
					               //*Pushing current color and ks into stack.
 | 
				
			||||||
 | 
					               //*suppose ks is 0.15 for all spheres, we can 
 | 
				
			||||||
 | 
					               //*of course support different ks, kt for different object
 | 
				
			||||||
 | 
					               //*but I didn't have time to do that, just a proof of concept,
 | 
				
			||||||
 | 
					               //*I defined the new sphere structure that could be used in the future.
 | 
				
			||||||
 | 
					               stack[j] = RT(color, ks[i]);
 | 
				
			||||||
 | 
					               V = S; //*NEXT RAY SHOOTING FROM THE INTERSECTION POINT 
 | 
				
			||||||
 | 
					               // if(flash && j == 0){
 | 
				
			||||||
 | 
					               //    V0 = V - V0;
 | 
				
			||||||
 | 
					               //    hit = true;
 | 
				
			||||||
 | 
					               // }               
 | 
				
			||||||
 | 
					               W = -normalize(2. * dot(N, W) * N - W);//*W is the next direction of the next ray.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               break;// this is only the innerloop, RT is still going!
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					      // TO SIMIPIFY THINGS UP, I'LL ASSUME THAT EVERYTHING 
 | 
				
			||||||
 | 
					      // IS INSIDE THE BOUNDING BOX [(-1,-1,-1), (1,1,1)]
 | 
				
			||||||
 | 
					      // AND THERE'S A FLOOR at [y = -1] THE NORMAL IS (0,1,0)
 | 
				
			||||||
 | 
					      // Because We assumed that the light always hit sphere first,
 | 
				
			||||||
 | 
					      // It will have wirld behavior when you rotate the scene upsidedown.
 | 
				
			||||||
 | 
					         float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					         float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         if(t >= 0.&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					         {   
 | 
				
			||||||
 | 
					            vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					            vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					            color=(
 | 
				
			||||||
 | 
					                  0.5 //ambient for ground
 | 
				
			||||||
 | 
					                  +0.5*max(0.,realLDir.y)*LCol //diffusion for ground
 | 
				
			||||||
 | 
					               )*groundColor
 | 
				
			||||||
 | 
					            ;
 | 
				
			||||||
 | 
					            // + SPECULAR COMPONENT GOES HERE
 | 
				
			||||||
 | 
					            if(rtxoff || j == n_ref - 1)
 | 
				
			||||||
 | 
					               color += sqrt(float(j+1))*groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                  pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					            stack[j] = RT(color, 0.15); //ks of ground is 0.1
 | 
				
			||||||
 | 
					            V = S; //Same as above, trace again from S, dir = reflect(W, N).
 | 
				
			||||||
 | 
					            // if(flash && j == 0){
 | 
				
			||||||
 | 
					            //    V0 = W;
 | 
				
			||||||
 | 
					            //    hit = true;
 | 
				
			||||||
 | 
					            // }
 | 
				
			||||||
 | 
					            W = vec3(W.x, -W.y, W.z); 
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            if(j > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					               // If the light bounces away! The color of it is calculated by 
 | 
				
			||||||
 | 
					               stack[j] = RT(sqrt(float(j+1))*vec3(4.,4.,4)*pow(max(0.,dot(W, normalize(LDir - V))), 10.), 0.);
 | 
				
			||||||
 | 
					               cnt_ref = j + 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else //If the light hits the void in the first place, it's just black!
 | 
				
			||||||
 | 
					               cnt_ref = j;//j is always 0 in this case.
 | 
				
			||||||
 | 
					            break; //The light is shooting into the void, let's stop RT.
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }       
 | 
				
			||||||
 | 
					      // RTX off
 | 
				
			||||||
 | 
					      if(rtxoff)
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(rtxoff)
 | 
				
			||||||
 | 
					      color = stack[0].color;
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      color = vec3(0,0,0);
 | 
				
			||||||
 | 
					      float currks = 1.;
 | 
				
			||||||
 | 
					      for(int i = 0; i < n_ref; ++i)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         if(i >= cnt_ref)//same trick to use bounded non-const on indexes
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            color += currks * stack[i - 1].color; //if there're less than n_ref rays, e.g. ray go to the void.
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         color += currks *(1.-stack[i].ks) * stack[i].color;
 | 
				
			||||||
 | 
					         currks *= stack[i].ks;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if(n_ref == cnt_ref)
 | 
				
			||||||
 | 
					         color += currks * stack[n_ref - 1].color;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   // APPLY GAMMA CORRECTION AND SET THE PIXEL COLOR.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(color),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					old/
 | 
				
			||||||
 | 
					new/
 | 
				
			||||||
@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					# graphics_hw3
 | 
				
			||||||
 | 
					[link](https://billsun.dev/graphics/hw3)
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.5 KiB  | 
| 
		 After Width: | Height: | Size: 6.7 KiB  | 
| 
		 After Width: | Height: | Size: 658 KiB  | 
| 
		 After Width: | Height: | Size: 75 KiB  | 
@ -0,0 +1,341 @@
 | 
				
			|||||||
 | 
					<script src=lib3.js></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					<center>
 | 
				
			||||||
 | 
					   <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					<canvas id='canvas1' style=" overflow: hidden !important; width: 600px !important; height:600px !important;" width=600 height=600></canvas>
 | 
				
			||||||
 | 
					</center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_vertex_shader' type='x-shader/x-vertex'>
 | 
				
			||||||
 | 
					   attribute vec3 aPos;
 | 
				
			||||||
 | 
					   varying   vec3 vPos;
 | 
				
			||||||
 | 
					   void main() {
 | 
				
			||||||
 | 
					      gl_Position = vec4(aPos, 1.);
 | 
				
			||||||
 | 
					      vPos = aPos;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					<!--script src="shader.frag" id='my_fragment_shader' type='x-shader/x-fragment'> </script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- CREATE A PROPERLY DESCRIPTIVE TITLE BELOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_title' type='text/html'>
 | 
				
			||||||
 | 
					RTX Extreme 
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- HERE IS WHERE YOU CAN PROVIDE A LONGER TEXT DESCRIPTION -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script id='my_instructions' type='text/html'><font color=#909090>
 | 
				
			||||||
 | 
					<p style="font-size:30px; ">In this homework, I implemented Global illumination w/ 
 | 
				
			||||||
 | 
					   Realtime Recursive Ray Tracing! 
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					<i style="font-size:25px;">Usage: </i>
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+T: Toggle Texture.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+S: Download fragment shader.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+N: Reset ViewPoint.</li>
 | 
				
			||||||
 | 
					   <li>Ctrl+Alt/Option+P: Toggle Pause/Resume.</li>
 | 
				
			||||||
 | 
					   <li style="color:red;">Please unfocus the Editing area (click somewhere else on the page) to use hotkeys.</li>
 | 
				
			||||||
 | 
					   <li>Double Click on canvas (WITHOUT key modifiers): Toggle Pause/Resume.</li>
 | 
				
			||||||
 | 
					   <li>DRAG, SCROLL on canvas: Changing Viewing point.</li>
 | 
				
			||||||
 | 
					   <li>Please use Chromium based browser.</li>
 | 
				
			||||||
 | 
					   <li>Super Sampling(0.25x-4x): increase rendering size for better visual or decrease rendering size for better performance.</li>
 | 
				
			||||||
 | 
					   <li>Spheres(1 - 5): number of spheres, performance will suffer if adding too many spheres.</li>
 | 
				
			||||||
 | 
					</ul>
 | 
				
			||||||
 | 
					<i style="font-size:25px;">How it works:</i>
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					   <li>I added recursive ray tracing with fraction support.</li>
 | 
				
			||||||
 | 
					   <li><a style="color:red;">About the scene: </a>There're two spheres in the center, the bouncing one in the very center (the Earth) is not transparent nor is it reflective, 
 | 
				
			||||||
 | 
					      the outer one is both transparent and reflective and has the texture of the Sun(barely distinguishable). 
 | 
				
			||||||
 | 
					      The small sphere embedded running circle is reflective but not transparent. You can also add
 | 
				
			||||||
 | 
					       two additional spheres via the button above. (up to 5).
 | 
				
			||||||
 | 
					   </li>
 | 
				
			||||||
 | 
					   <li>If your scene is clipped, this is a bug from chromium, you may reset the viewport by adjust super sampling.</li>
 | 
				
			||||||
 | 
					   <li>Each hit will now spawn 2 rays, but there're serious performance issues, because 
 | 
				
			||||||
 | 
					      the number of rays increases exponentially. I resolved this issue by:
 | 
				
			||||||
 | 
					   </li>
 | 
				
			||||||
 | 
					   <ul>
 | 
				
			||||||
 | 
					      <li>Pruning: If the weight of this ray is too small, dispose it.</li>
 | 
				
			||||||
 | 
					      <li>Smarter Stack frame utilization: Now the stack frame will only store last rays and next rays. 
 | 
				
			||||||
 | 
					         By alternating 2 arrays storing last ray and next ray, I don't need to store other rays.
 | 
				
			||||||
 | 
					      </li>
 | 
				
			||||||
 | 
					      <li>By combining these methods I managed to significantly reduce RT depth and 'stack' size, 
 | 
				
			||||||
 | 
					         While supporting nested object and objects both reflection and refraction rays on the same surface. 
 | 
				
			||||||
 | 
					      </li>   
 | 
				
			||||||
 | 
					   </ul>
 | 
				
			||||||
 | 
					   <img src="./img.jpg"></img>
 | 
				
			||||||
 | 
					 </ul>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CREATE THE HTML DOCUMENT
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					let vs = my_vertex_shader.innerHTML;
 | 
				
			||||||
 | 
					    //* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					    var client = new XMLHttpRequest();
 | 
				
			||||||
 | 
					    client.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					    client.onloadend = function() {
 | 
				
			||||||
 | 
					      fs = (client.responseText);
 | 
				
			||||||
 | 
					      //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					      gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					      editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					      editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					         if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					            setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   client.send();
 | 
				
			||||||
 | 
					document.body.innerHTML = [''
 | 
				
			||||||
 | 
					   ,'<font size=7 color=#909090>' + my_title.innerHTML
 | 
				
			||||||
 | 
					   ,'<img id="rtx" style="float:right;" src="./RTXon.svg" type="image/svg+xml"'
 | 
				
			||||||
 | 
					   ,' alt="Turn Ray Tracing On/OFF" title="Turn Ray Tracing On/OFF" height=60px /img>' 
 | 
				
			||||||
 | 
					   ,'<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>' 
 | 
				
			||||||
 | 
					   ,'<TABLE cellspacing=0 cellpadding=0><TR>'
 | 
				
			||||||
 | 
					   ,'<td><font color=red size=5><div id=errorMessage></div></font></td>'
 | 
				
			||||||
 | 
					   ,'</TR><TR>'
 | 
				
			||||||
 | 
					   ,'<table cellspacing=0>'
 | 
				
			||||||
 | 
					   ,'<tr>'
 | 
				
			||||||
 | 
					   ,'<td valign=top>'
 | 
				
			||||||
 | 
					   ,'<div id="ace" style="width:800px;height:2200px;"></div>'
 | 
				
			||||||
 | 
					   ,'</td><td valign=top>' + document.body.innerHTML
 | 
				
			||||||
 | 
					   ,'<input type="number" id="ins" style="margin-left:3px;font-size:24px;width:100px;height:45px" value="3" max="5" min = "1">'
 | 
				
			||||||
 | 
					   ,'<button id="bns" style="margin-left:5px;font-size:24px;width:180px;height:45px">Set Spheres</button>'
 | 
				
			||||||
 | 
					   ,'<input type="number" id="insamp" style="margin-left:3px;font-size:24px;width:100px;height:45px" value="1" max="4" min = "0.25" step="0.2">'
 | 
				
			||||||
 | 
					   ,'<button id="bnsamp" style="margin-left:5px;font-size:24px;width:200px;height:45px">Super Sampling</button>'
 | 
				
			||||||
 | 
					   ,'<div style=\'font-size:25px\'>' + my_instructions.innerHTML + '</div>' + '</td>'
 | 
				
			||||||
 | 
					   ,'</tr></table>'
 | 
				
			||||||
 | 
					   ,'</TR></TABLE>'
 | 
				
			||||||
 | 
					   ].join('');
 | 
				
			||||||
 | 
					bns.onclick=function(e){
 | 
				
			||||||
 | 
					   if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
 | 
				
			||||||
 | 
					   {   
 | 
				
			||||||
 | 
					      cns = ins.value;
 | 
				
			||||||
 | 
					      fragmentShaderDefs = '\n const int cns = ' + cns + ';';
 | 
				
			||||||
 | 
					      if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnsamp.onclick=function(e){
 | 
				
			||||||
 | 
					   let multiplier  = insamp.value;
 | 
				
			||||||
 | 
					   let w = parseInt(canvas1.style.width)*multiplier;
 | 
				
			||||||
 | 
					   let h = parseInt(canvas1.style.height)*multiplier;
 | 
				
			||||||
 | 
					   canvas1.height = h;
 | 
				
			||||||
 | 
					   canvas1.width = w;
 | 
				
			||||||
 | 
					   gl.viewport(0, 0, w, h);
 | 
				
			||||||
 | 
					   gl.clearRect(0, 0, w, h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					delete editor.KeyBinding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let lastTime = Date.now();
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
 | 
				
			||||||
 | 
					let mousedx = 0, mousedy = 0, mousedz = 0;
 | 
				
			||||||
 | 
					let cx = 1, cy = 1, sx = 0, sy = 0;
 | 
				
			||||||
 | 
					let mouselastX, mouselastY;
 | 
				
			||||||
 | 
					let lastClick = undefined;
 | 
				
			||||||
 | 
					let pause_resume = function(){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					         lastTime = Date.now();
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					      animating = !animating;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(!(shift && alt) && lastClick&& Date.now()-lastClick<400)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   lastClick = Date.now();
 | 
				
			||||||
 | 
					   //moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseover', function(e){
 | 
				
			||||||
 | 
					   over = true;
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags |= mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousedown', function(e){
 | 
				
			||||||
 | 
					      moving = true
 | 
				
			||||||
 | 
					      mouselastX = mouselastY =  undefined;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousemove', function(e){
 | 
				
			||||||
 | 
					      if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
 | 
				
			||||||
 | 
					         mousedx -= (mouselastX - e.offsetX)/60;
 | 
				
			||||||
 | 
					         mousedy -= (mouselastY - e.offsetY)/60;
 | 
				
			||||||
 | 
					         cx = Math.cos(mousedx);
 | 
				
			||||||
 | 
					         sx = Math.sin(mousedx);
 | 
				
			||||||
 | 
					         cy = Math.cos(mousedy);
 | 
				
			||||||
 | 
					         sy = Math.sin(mousedy);
 | 
				
			||||||
 | 
					         setUniform('Matrix3fv', 'transformation', false, [cx, sy*sx, sx*cy, 0, cy, -sy, -sx, cx*sy, cx*cy]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mouselastX = e.offsetX;
 | 
				
			||||||
 | 
					      mouselastY = e.offsetY;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseup', function(e){
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseout', function(e){
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags &= !mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   over = false;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('wheel', function(e){
 | 
				
			||||||
 | 
					      mousedz += e.wheelDelta/600;
 | 
				
			||||||
 | 
					      setUniform('1f', 'dFL', mousedz);
 | 
				
			||||||
 | 
					      e.stopImmediatePropagation();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.scroll(function(e) {e.stopPropagation();});
 | 
				
			||||||
 | 
					rtx.style.cursor="pointer";
 | 
				
			||||||
 | 
					let rtswitch = function(){
 | 
				
			||||||
 | 
					   alert('Ray Tracing is always on. See hw2 where rt can be toggled on/off.')
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					rtx.addEventListener('click', rtswitch);
 | 
				
			||||||
 | 
					var requestAnimationFrame = window.requestAnimationFrame ||
 | 
				
			||||||
 | 
					 window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 | 
				
			||||||
 | 
					let fpscounter = function(time){
 | 
				
			||||||
 | 
					      if (start === undefined)
 | 
				
			||||||
 | 
					         start = time;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
 | 
				
			||||||
 | 
					      start = time;
 | 
				
			||||||
 | 
					      if(fpson)
 | 
				
			||||||
 | 
					         ;//requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         start = undefined;
 | 
				
			||||||
 | 
					         fps.innerHTML = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = true;
 | 
				
			||||||
 | 
					   else if(ctrl && alt && e.code == 'KeyT'){
 | 
				
			||||||
 | 
					      const mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)?mask:0);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (ctrl &&e.code == 'KeyS'){
 | 
				
			||||||
 | 
					      let a = document.createElement('a');
 | 
				
			||||||
 | 
					      a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
 | 
				
			||||||
 | 
					      a.download = 'shader.frag';
 | 
				
			||||||
 | 
					      a.click();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyR')
 | 
				
			||||||
 | 
					      rtswitch();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyN')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      flags = 0;
 | 
				
			||||||
 | 
					      moving = false;
 | 
				
			||||||
 | 
					      mousedx = mousedy = mousedz = 0;
 | 
				
			||||||
 | 
					      cx = Math.cos(mousedx);
 | 
				
			||||||
 | 
					      sx = Math.sin(mousedx);
 | 
				
			||||||
 | 
					      cy = Math.cos(mousedy);
 | 
				
			||||||
 | 
					      sy = Math.sin(mousedy);
 | 
				
			||||||
 | 
					      rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					      setUniform('Matrix3fv', 'transformation', false, [cx, sy*sx, sx*cy, 0, cy, -sy, -sx, cx*sy, cx*cy]);
 | 
				
			||||||
 | 
					      setUniform('1f', 'dFL', mousedz);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyP')
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyF')
 | 
				
			||||||
 | 
					      if(!fpson)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         fpson = true;
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fpson = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					let startTime = Date.now();
 | 
				
			||||||
 | 
					let lastFrameTime = 0;
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   let uTime;
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (Date.now() - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (lastTime - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   setUniform('4f', 'Sph[4]', 0.5*Math.sin(uTime*1.),0.08*Math.sin(uTime *0.9),.5*Math.cos(uTime*1.),.12);
 | 
				
			||||||
 | 
					   setUniform('4f', 'Sph[3]', .9*Math.sin(uTime*.4),0.,.9*Math.cos(uTime*.4),.25);
 | 
				
			||||||
 | 
					   setUniform('4f', 'Sph[2]', .22*Math.sin(uTime*1.2),0.05,.22*Math.cos(uTime*1.2),.05);
 | 
				
			||||||
 | 
					   setUniform('4f', 'Sph[0]', 0,0.05*Math.cos(uTime + 1.),.045*Math.cos(uTime),.15);
 | 
				
			||||||
 | 
					   setUniform('4f', 'Sph[1]', 0,0.,0,.25);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,207 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					let ns = 5, cns = 3;
 | 
				
			||||||
 | 
					fragmentShaderHeader+= 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					let fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;         // IS THIS THE FIREFOX BROWSER?
 | 
				
			||||||
 | 
					let errorMsg = '';
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Initialize a texture and load an image.
 | 
				
			||||||
 | 
					// When the image finished loading copy it into the texture.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					     bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   } 
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let texture = [], gl, program;
 | 
				
			||||||
 | 
					let textures = []; 
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   // Because images have to be downloaded over the internet
 | 
				
			||||||
 | 
					   // they might take a moment until they are ready.
 | 
				
			||||||
 | 
					   // Until then put a single pixel in the texture so we can
 | 
				
			||||||
 | 
					   // use it immediately. When the image has finished downloading
 | 
				
			||||||
 | 
					   // we'll update the texture with the contents of the image.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      // WebGL1 has different requirements for power of 2 images
 | 
				
			||||||
 | 
					      // vs non power of 2 images so check if the image is a
 | 
				
			||||||
 | 
					      // power of 2 in both dimensions.
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         // Yes, it's a power of 2. Generate mips.
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         // No, it's not a power of 2. Turn off mips and set
 | 
				
			||||||
 | 
					         // wrapping to clamp to edge
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = '<br>';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader +fragmentShaderDefs+ fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; ++i){
 | 
				
			||||||
 | 
					            loadTexture(gl, './'+(i+1)+'.jpg', i); //Texture loading.
 | 
				
			||||||
 | 
					            textures[i] = i;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
 | 
				
			||||||
 | 
					         let cx = Math.cos(mousedx), cy = Math.cos(mousedy), sx = Math.sin(mousedx), sy = Math.sin(mousedy);
 | 
				
			||||||
 | 
					         setUniform('Matrix3fv', 'transformation', false, [cx, sy*sx, sx*cy, 0, cy, -sy, -sx, cx*sy, cx*cy]);
 | 
				
			||||||
 | 
					         let attribs = [
 | 
				
			||||||
 | 
					            .05,.05,.1,  .5,.5,1.,  1.,.5,.5,20.,  0., .0, 1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  1.,.5,.5,  1.,.5,.5,10.,  .3,1.,1.3, //
 | 
				
			||||||
 | 
					            .1,.05,.05,  .71,.71,.71,  .71,.71,.71,10.,  0.3,.0,1.5,
 | 
				
			||||||
 | 
					            .1,.1,.1,  .71,.71,.71,  .71,.71,.71,10.,  0.05,0., 1.,
 | 
				
			||||||
 | 
					            .0,.0,.0,  .0,.0,.0,  .0,.0,.0,40.,  0.,.85,1.5
 | 
				
			||||||
 | 
					         ]
 | 
				
			||||||
 | 
					         var offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Ambient['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Diffuse['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('4fv', 'Specular['+i+']', attribs.slice(offset, offset += 4));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'ks['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kr['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kf['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					            [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 0, 0);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   if(gl)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					      (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 173 KiB  | 
@ -0,0 +1,264 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604); 
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform int flags;
 | 
				
			||||||
 | 
					//FLAGS 0-TEX, 1-RT, 2-MOVED, 3-FLASH, 4-TEX_ROT, 5-CLOUD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform vec4 rot; //ROTATION VALUES USED TO CALCULATE TRANSFORMATION MATRIX
 | 
				
			||||||
 | 
					//rot=[cosx, sinx, cosy, siny], x, y BING ROTATED ANGLE
 | 
				
			||||||
 | 
					uniform float dFL; //DELTA on FOCAL LENGTH
 | 
				
			||||||
 | 
					uniform vec3 fDir;//Flash light direction
 | 
				
			||||||
 | 
					varying vec3 vPos;// -1 < vPos.x < +1
 | 
				
			||||||
 | 
					// -1 < vPos.y < +1
 | 
				
			||||||
 | 
					//      vPos.z == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float fl=3.;//ORIGINAL FOCAL LENGTH
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					const int n_ref=9; //2^(hits) + 1 because each hit now spawn 2 rays.
 | 
				
			||||||
 | 
					//const int ns=4; ns is added from .js
 | 
				
			||||||
 | 
					vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					vec3 Ambient[ns];
 | 
				
			||||||
 | 
					vec3 Diffuse[ns];
 | 
				
			||||||
 | 
					vec4 Specular[ns];
 | 
				
			||||||
 | 
					float ks[ns];
 | 
				
			||||||
 | 
					float kr[ns];
 | 
				
			||||||
 | 
					float kf[ns], kf_air = 1.000293;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int type[ns];//Nested objects
 | 
				
			||||||
 | 
					// 1-sphere, 2-compost sphere, 3-
 | 
				
			||||||
 | 
					struct Object{ //UPDATED SPHERE STRUCTURE THAT SUPPORTS TRANSPARENCY.(UNUSED)
 | 
				
			||||||
 | 
					   vec4 Pos;
 | 
				
			||||||
 | 
					   vec3 Ambient;
 | 
				
			||||||
 | 
					   vec3 Diffuse;
 | 
				
			||||||
 | 
					   vec4 Specular;
 | 
				
			||||||
 | 
					   int textureid;
 | 
				
			||||||
 | 
					   float ks, kt, kr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					struct RT{ //STACK FOR RECURSIVE RAY TRACING.
 | 
				
			||||||
 | 
					   vec3 color;
 | 
				
			||||||
 | 
					   float ks;
 | 
				
			||||||
 | 
					} ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 scolor = vec3(0,0,0); //Actually 2^n_ref
 | 
				
			||||||
 | 
					struct Ray{
 | 
				
			||||||
 | 
					   vec3 V;
 | 
				
			||||||
 | 
					   vec3 W;
 | 
				
			||||||
 | 
					   float kf, cumulativeK;
 | 
				
			||||||
 | 
					} lastRay[n_ref/2];
 | 
				
			||||||
 | 
					bool modulo2(int n){
 | 
				
			||||||
 | 
					   return n-2*(n/2) == 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool getflag(int flag,int bit){
 | 
				
			||||||
 | 
					   int shifted = flag / int(pow(2.,float(bit)));
 | 
				
			||||||
 | 
					   return modulo2(shifted);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					float clampv(float val,float l,float h){
 | 
				
			||||||
 | 
					   return val<l?l:val>h?h:val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					   vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   // SPHERE
 | 
				
			||||||
 | 
					   Sph[3]=vec4(.9*sin(uTime*.4),0.,.9*cos(uTime*.4),.25);
 | 
				
			||||||
 | 
					   Sph[2]=vec4(.22*sin(uTime*1.2),0.05,.22*cos(uTime*1.2),.02);
 | 
				
			||||||
 | 
					   Sph[0]=vec4(.45*sin(uTime),0.05*cos(uTime + 1.),.45*cos(uTime),.1);
 | 
				
			||||||
 | 
					   Sph[1]=vec4(0.,0.,0.,.15);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   // SURFACE REFLECTANCE PROPERTIES, can be transferred from .js
 | 
				
			||||||
 | 
					   Ambient[3]=vec3(.1,.1,.1);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[3]=vec3(.71,.71,.71);// r,g,b
 | 
				
			||||||
 | 
					   Specular[3]=vec4(.71,.71,.71,10.);// r,g,b,power
 | 
				
			||||||
 | 
					   Ambient[2]=vec3(.1,.05,.05);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[2]=vec3(.71,.71,.71);// r,g,b
 | 
				
			||||||
 | 
					   Specular[2]=vec4(.71,.71,.71,10.);// r,g,b,power
 | 
				
			||||||
 | 
					   Ambient[1]=vec3(.1,.05,.05);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[1]=vec3(1.,.5,.5);// r,g,b
 | 
				
			||||||
 | 
					   Specular[1]=vec4(1.,.5,.5,10.);// r,g,b,power
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   Ambient[0]=vec3(.05,.05,.1);// r,g,b
 | 
				
			||||||
 | 
					   Diffuse[0]=vec3(.5,.5,1.);// r,g,b
 | 
				
			||||||
 | 
					   Specular[0]=vec4(1.,.5,.5,20.);// r,g,b,power
 | 
				
			||||||
 | 
					   ks[0] = 0.25;
 | 
				
			||||||
 | 
					   ks[1] = 0.1;
 | 
				
			||||||
 | 
					   ks[2] = 0.3;
 | 
				
			||||||
 | 
					   ks[3] = 0.05;
 | 
				
			||||||
 | 
					   kr[0] = 0.25;
 | 
				
			||||||
 | 
					   kr[1] = 0.1;
 | 
				
			||||||
 | 
					   kr[2] = 0.3;
 | 
				
			||||||
 | 
					   kr[3] = 0.05;
 | 
				
			||||||
 | 
					   kf[0] = 1.3;
 | 
				
			||||||
 | 
					   kf[1] = 1.3; //Water
 | 
				
			||||||
 | 
					   kf[2] = 1.5; //Glass
 | 
				
			||||||
 | 
					   kf[3] = 1.; //Vacuum
 | 
				
			||||||
 | 
					   float currKf = kf_air;
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   float ca=rot.x, sa = rot.y, cb=rot.z, sb=rot.w;
 | 
				
			||||||
 | 
					   mat3 transformation, invTr;//Transformation matrix for viewpoint.
 | 
				
			||||||
 | 
					   transformation[0] = vec3(ca, sb*sa, sa*cb);//because the matrices are all the same,
 | 
				
			||||||
 | 
					   transformation[1] = vec3(0, cb, -sb);//We don't need to calculate it for every pixel
 | 
				
			||||||
 | 
					   transformation[2] = vec3(-sa,ca*sb,ca*cb);//So, we get it from the CPU
 | 
				
			||||||
 | 
					   invTr[0] = vec3(ca, 0, -sa);//it's inverse, to calculate texture mapping.
 | 
				
			||||||
 | 
					   invTr[1] = vec3(sa*sb, cb, ca*sb);
 | 
				
			||||||
 | 
					   invTr[2] = vec3(cb*sa, -sb, ca*cb);
 | 
				
			||||||
 | 
					   vec3 trPos = transformation*((dFL+fl+1.)/(fl+1.))*vec3(vPos.xy, -1);
 | 
				
			||||||
 | 
					   vec3 V0=transformation*vec3(0.,0.,fl+dFL), V = V0;
 | 
				
			||||||
 | 
					   vec3 W=normalize(trPos-V);
 | 
				
			||||||
 | 
					   bool rtxoff = getflag(flags, 1), 
 | 
				
			||||||
 | 
					   showtexture = !getflag(flags,0), 
 | 
				
			||||||
 | 
					   moved = getflag(flags,2);
 | 
				
			||||||
 | 
					   int cnt_ref = n_ref;
 | 
				
			||||||
 | 
					   float currentK = 1.;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      if(j > 0){
 | 
				
			||||||
 | 
					         Ray currR = lastRay[(j-1)/2];
 | 
				
			||||||
 | 
					         currKf = currR.kf;
 | 
				
			||||||
 | 
					         currentK = currR.cumulativeK;
 | 
				
			||||||
 | 
					         if(currKf <= 0.0000001 || currentK <= 0.0000001)
 | 
				
			||||||
 | 
					            continue; // We make it terminate w/ kf=0
 | 
				
			||||||
 | 
					         V = currR.V;
 | 
				
			||||||
 | 
					         W = currR.W;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      float tMin=10000.;
 | 
				
			||||||
 | 
					      int iMin = -1;
 | 
				
			||||||
 | 
					      for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					         // SHIFT COORDINATES, SO THAT SPHERE IS AT (0,0,0)
 | 
				
			||||||
 | 
					         vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					         // SOLVE FOR QUADRATIC EQUATION IN t
 | 
				
			||||||
 | 
					         float B=dot(W,Vp);
 | 
				
			||||||
 | 
					         float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					         float D=B*B-C;
 | 
				
			||||||
 | 
					         if(D>0.){
 | 
				
			||||||
 | 
					            float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					            if(t >= 0.00001 && t < tMin){
 | 
				
			||||||
 | 
					               tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					               iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (t >= -0.00001){
 | 
				
			||||||
 | 
					               t = -(t + 2.*B);
 | 
				
			||||||
 | 
					               if(t < tMin){
 | 
				
			||||||
 | 
					                  tMin = t;
 | 
				
			||||||
 | 
					                  iMin = i;
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // IF RAY HITS SPHERE
 | 
				
			||||||
 | 
					      if(iMin >= 0){
 | 
				
			||||||
 | 
					         float t = tMin;
 | 
				
			||||||
 | 
					         vec3 S=V+t*W;
 | 
				
			||||||
 | 
					         for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					            if(i == iMin) 
 | 
				
			||||||
 | 
					            {             
 | 
				
			||||||
 | 
					               vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					               if(moved)
 | 
				
			||||||
 | 
					                  tex_sph=invTr*tex_sph;
 | 
				
			||||||
 | 
					               float R=Sph[i].w;
 | 
				
			||||||
 | 
					               float tex_x=acos(abs(tex_sph.x)/sqrt(R*R-tex_sph.y*tex_sph.y));
 | 
				
			||||||
 | 
					               if(tex_sph.x>0.)
 | 
				
			||||||
 | 
					                  tex_x=pi-tex_x;
 | 
				
			||||||
 | 
					               tex_x*=1.5708;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					               tex_x=tex_x+float(uTime);
 | 
				
			||||||
 | 
					               float quo=float(int(tex_x/_2pi));
 | 
				
			||||||
 | 
					               tex_x=tex_x/_2pi - quo;
 | 
				
			||||||
 | 
					               vec3 texture_color;
 | 
				
			||||||
 | 
					               if(showtexture)
 | 
				
			||||||
 | 
					                  texture_color=texture2D(uSampler[i],vec2(tex_x,((R-tex_sph.y)/(2.*R)))).xyz;
 | 
				
			||||||
 | 
					               else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					               vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					               vec3 realLDir=normalize(LDir-S); 
 | 
				
			||||||
 | 
					               color=(
 | 
				
			||||||
 | 
					                     Ambient[i]
 | 
				
			||||||
 | 
					                     +Diffuse[i]*max(0.,dot(N,realLDir))*LCol
 | 
				
			||||||
 | 
					                  )*texture_color
 | 
				
			||||||
 | 
					               ;
 | 
				
			||||||
 | 
					               if(rtxoff || j >= n_ref/2) //if it's the last hit
 | 
				
			||||||
 | 
					               {
 | 
				
			||||||
 | 
					                  color += sqrt(float(j+1)) * Specular[i].xyz*pow(max(0.,
 | 
				
			||||||
 | 
					                     dot(2.*dot(N,realLDir)*N-realLDir,-W)),Specular[i].w);
 | 
				
			||||||
 | 
					                  scolor += color * currentK;
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               else{
 | 
				
			||||||
 | 
					                  lastRay[2 * j + 1] = Ray(S, (-(2. * dot(N, W) * N - W)), currKf, currentK * ks[i]); //reflection
 | 
				
			||||||
 | 
					                  float ita = currKf/kf[i];
 | 
				
			||||||
 | 
					                  float c1 = dot(N, W);
 | 
				
			||||||
 | 
					                  float c2 = sqrt(1.-ita*ita*(1.-c1*c1));
 | 
				
			||||||
 | 
					                  lastRay[2 * j + 2] = Ray(S, normalize(ita*W + (ita*c1 - c2)*N), kf[i], currentK * kr[i]); //refraction
 | 
				
			||||||
 | 
					                  scolor += currentK*(1. - ks[i] - kr[i]) * color;//stack[j] = RT(color, currentK*(1. - ks[i] - kr[i]) * color;
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					         float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					         float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					         if(t >= 0.&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					         {   
 | 
				
			||||||
 | 
					            vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					            vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					            color=(
 | 
				
			||||||
 | 
					                  0.5 //ambient for ground
 | 
				
			||||||
 | 
					                  +0.5*max(0.,realLDir.y)*LCol //diffusion for ground
 | 
				
			||||||
 | 
					               )*groundColor
 | 
				
			||||||
 | 
					            ;
 | 
				
			||||||
 | 
					            // + SPECULAR COMPONENT GOES HERE
 | 
				
			||||||
 | 
					            if(rtxoff || j == n_ref - 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					               color += sqrt(float(j+1))*groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                  pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					               //stack[j] = RT(color, currentK); //ks of ground is 0.15
 | 
				
			||||||
 | 
					               scolor += currentK * color;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					               lastRay[2 * j + 1] = Ray(S, vec3(W.x, -W.y, W.z), currKf, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					               //stack[j] = RT(color, currentK * (1.-0.15)); //ks of ground is 0.15
 | 
				
			||||||
 | 
					               scolor += (currentK*.85)*color;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            //lastRay[2 * j + 2] = Ray(S, vec3(0,0,0), 0.); //refraction
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            if(j > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					               // If the light bounces away! The color of it is calculated by 
 | 
				
			||||||
 | 
					               //stack[j] = RT(sqrt(float(j+1))*vec3(4.,4.,4)*pow(max(0.,dot(W, normalize(LDir - V))), 10.), currentK);
 | 
				
			||||||
 | 
					               scolor += currentK * sqrt(float(j+1)*pow(max(0.,dot(W, normalize(LDir - V))), 10.)) * vec3(4.,4.,4);
 | 
				
			||||||
 | 
					               //cnt_ref = j + 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            //else //If the light hits the void in the first place, it's just black!
 | 
				
			||||||
 | 
					               //cnt_ref = j;//j is always 0 in this case.
 | 
				
			||||||
 | 
					            break; //The light is shooting into the void, let's stop RT.
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }       
 | 
				
			||||||
 | 
					      if(rtxoff)
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(!rtxoff)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      color = scolor;
 | 
				
			||||||
 | 
					      // color = vec3(0,0,0);
 | 
				
			||||||
 | 
					      // //float currks = 1.;
 | 
				
			||||||
 | 
					      // for(int i = 0; i < n_ref; ++i)
 | 
				
			||||||
 | 
					      // {
 | 
				
			||||||
 | 
					      //    //if(i >= cnt_ref)//same trick to use bounded non-const on indexes
 | 
				
			||||||
 | 
					      //    // {
 | 
				
			||||||
 | 
					      //    //    color += currks * stack[i - 1].color; //if there're less than n_ref rays, e.g. ray go to the void.
 | 
				
			||||||
 | 
					      //    //    break;
 | 
				
			||||||
 | 
					      //    // }
 | 
				
			||||||
 | 
					      //    if(stack[i].ks <0.0000001)
 | 
				
			||||||
 | 
					      //       continue;
 | 
				
			||||||
 | 
					      //    color += stack[i].ks * stack[i].color;//currks *(1.-stack[i].ks) * stack[i].color;
 | 
				
			||||||
 | 
					      //    //currks *= stack[i].ks;
 | 
				
			||||||
 | 
					      // }
 | 
				
			||||||
 | 
					      // // if(n_ref == cnt_ref)
 | 
				
			||||||
 | 
					      // //    color += currks * stack[n_ref - 1].color;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(color),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
@ -0,0 +1,268 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform int f_tex, f_rt, f_moved;
 | 
				
			||||||
 | 
					uniform vec4 rot; //ROTATION VALUES USED TO CALCULATE TRANSFORMATION MATRIX
 | 
				
			||||||
 | 
					uniform float dFL; //DELTA on FOCAL LENGTH
 | 
				
			||||||
 | 
					uniform mat3 transformation, invTr;
 | 
				
			||||||
 | 
					uniform vec3 Ambient[ns], Diffuse[ns];
 | 
				
			||||||
 | 
					uniform vec4 Specular[ns];
 | 
				
			||||||
 | 
					uniform float ks[ns], kr[ns], kf[ns];
 | 
				
			||||||
 | 
					uniform vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const float kf_air = 1.000293;
 | 
				
			||||||
 | 
					varying vec3 vPos;
 | 
				
			||||||
 | 
					float fl=3.;//ORIGINAL FOCAL LENGTH
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					const int n_ref=15; //2^(hits) - 1 because each hit now spawn 2 rays.
 | 
				
			||||||
 | 
					const int max_stack = (n_ref+1)/4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 scolor = vec3(0,0,0); //Actually 2^n_ref
 | 
				
			||||||
 | 
					struct Ray{
 | 
				
			||||||
 | 
					   vec3 V;
 | 
				
			||||||
 | 
					   vec3 W;
 | 
				
			||||||
 | 
					   float kf, cumulativeK;
 | 
				
			||||||
 | 
					} stack1[max_stack], stack2[max_stack];
 | 
				
			||||||
 | 
					bool modulo2(int n){
 | 
				
			||||||
 | 
					   return n-2*(n/2) == 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					vec3 getRefraction(vec3 N, vec3 W, float nextkr, float eta, float c1){
 | 
				
			||||||
 | 
					   float c2 = (1.-eta*eta*(1.-c1*c1));
 | 
				
			||||||
 | 
					   c2 = sqrt(abs(c2));
 | 
				
			||||||
 | 
					   return normalize(eta*W + (eta*c1 - c2)*N);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					   vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   float currKf = kf_air;
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   vec3 trPos = transformation*((dFL+fl+1.)/(fl+1.))*vec3(vPos.xy, -1);
 | 
				
			||||||
 | 
					   vec3 V0=transformation*vec3(0.,0.,fl+dFL), V = V0;
 | 
				
			||||||
 | 
					   vec3 W=(trPos-V);
 | 
				
			||||||
 | 
					   bool rtxoff = false, showtexture = true, moved = false;
 | 
				
			||||||
 | 
					   float currentK = 1.;
 | 
				
			||||||
 | 
					   int curr_ptr = 0, curr_top = 0, next_top = 0;
 | 
				
			||||||
 | 
					   bool final = false, stackswap = false;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      for(int curr = 0; curr < max_stack; ++curr){
 | 
				
			||||||
 | 
					         if(curr == curr_ptr){
 | 
				
			||||||
 | 
					            bool outward = false;
 | 
				
			||||||
 | 
					            bool skip = false;
 | 
				
			||||||
 | 
					            if(j > 0){
 | 
				
			||||||
 | 
					               Ray currR;
 | 
				
			||||||
 | 
					               if(stackswap)
 | 
				
			||||||
 | 
					                  currR = stack1[curr];
 | 
				
			||||||
 | 
					               else
 | 
				
			||||||
 | 
					                  currR = stack2[curr];
 | 
				
			||||||
 | 
					               currKf = currR.kf;
 | 
				
			||||||
 | 
					               currentK = currR.cumulativeK;
 | 
				
			||||||
 | 
					               if(currKf <= 0.001 || currentK <= 0.001)
 | 
				
			||||||
 | 
					                  skip = true; 
 | 
				
			||||||
 | 
					               V = currR.V;
 | 
				
			||||||
 | 
					               W = currR.W;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else 
 | 
				
			||||||
 | 
					               W = normalize(W);
 | 
				
			||||||
 | 
					            if(!skip){
 | 
				
			||||||
 | 
					               float tMin=10000.;
 | 
				
			||||||
 | 
					               int iMin = -1;
 | 
				
			||||||
 | 
					               for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					                  vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					                  float B=dot(W,Vp);
 | 
				
			||||||
 | 
					                  float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					                  float D=B*B-C;
 | 
				
			||||||
 | 
					                  if(D>0.){
 | 
				
			||||||
 | 
					                     float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					                     if(t >= 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                        tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					                        iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					                        outward = false;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else if (t >= -0.01 && t <0.01){
 | 
				
			||||||
 | 
					                        t = -(t + 2.*B);
 | 
				
			||||||
 | 
					                        if(t > 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                           tMin = t;
 | 
				
			||||||
 | 
					                           iMin = i;
 | 
				
			||||||
 | 
					                           outward = true;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               if(iMin >= 0){
 | 
				
			||||||
 | 
					                  float t = tMin;
 | 
				
			||||||
 | 
					                  vec3 S=V+t*W;
 | 
				
			||||||
 | 
					                  for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					                     if(i == iMin)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        vec3 texture_color;
 | 
				
			||||||
 | 
					                        if(showtexture)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                           vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                           if(moved)
 | 
				
			||||||
 | 
					                              ;//tex_sph=invTr*tex_sph;
 | 
				
			||||||
 | 
					                           float R=Sph[i].w;
 | 
				
			||||||
 | 
					                           float tex_x=acos(abs(tex_sph.x)/sqrt(R*R-tex_sph.y*tex_sph.y));
 | 
				
			||||||
 | 
					                           if(tex_sph.x>0.)
 | 
				
			||||||
 | 
					                              tex_x=pi-tex_x;
 | 
				
			||||||
 | 
					                           tex_x*=1.5708;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					                           tex_x=tex_x+float(uTime);
 | 
				
			||||||
 | 
					                           float quo=float(int(tex_x/_2pi));
 | 
				
			||||||
 | 
					                           tex_x=tex_x/_2pi - quo;
 | 
				
			||||||
 | 
					                           texture_color=texture2D(uSampler[i],vec2(tex_x,((R-tex_sph.y)/(2.*R)))).xyz;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                        vec3 realLDir=normalize(LDir-S);
 | 
				
			||||||
 | 
					                        if(outward){
 | 
				
			||||||
 | 
					                           float c1 = dot(N, W);
 | 
				
			||||||
 | 
					                           if(c1 > 0.)
 | 
				
			||||||
 | 
					                           {  
 | 
				
			||||||
 | 
					                              c1 = -c1;
 | 
				
			||||||
 | 
					                              N = -N;
 | 
				
			||||||
 | 
					                              outward = true;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                           else outward = false;
 | 
				
			||||||
 | 
					                           color=(Ambient[i]+Diffuse[i]*max(0.,dot(N,realLDir))*LCol)*texture_color;
 | 
				
			||||||
 | 
					                           if(rtxoff || final) //if it's the last hit
 | 
				
			||||||
 | 
					                           {
 | 
				
			||||||
 | 
					                              color +=  Specular[i].xyz*pow(max(0.,dot(-2.*c1*N-realLDir,realLDir)),Specular[i].w);
 | 
				
			||||||
 | 
					                              scolor += color * currentK;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                           else{
 | 
				
			||||||
 | 
					                              float eta =kf[i]/currKf;
 | 
				
			||||||
 | 
					                              if(outward) eta = 1./eta;
 | 
				
			||||||
 | 
					                              float nextks = currentK * ks[i], nextkr = currentK * kr[i];
 | 
				
			||||||
 | 
					                              bool refl = nextks > 0.001, refr = nextkr > 0.001;
 | 
				
			||||||
 | 
					                              if(refl || refr)
 | 
				
			||||||
 | 
					                                 for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                                    if(k == next_top){
 | 
				
			||||||
 | 
					                                       if(stackswap){
 | 
				
			||||||
 | 
					                                          if(refl)
 | 
				
			||||||
 | 
					                                          {
 | 
				
			||||||
 | 
					                                             stack2[k] = Ray(S, getRefraction(N, W, nextkr, eta, c1), currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                             currentK -= nextks;
 | 
				
			||||||
 | 
					                                             next_top ++;
 | 
				
			||||||
 | 
					                                          }
 | 
				
			||||||
 | 
					                                          if(refr)
 | 
				
			||||||
 | 
					                                          {
 | 
				
			||||||
 | 
					                                             if(refl)
 | 
				
			||||||
 | 
					                                                stack2[k+1] = Ray(S, getRefraction(N, W, nextkr, eta, c1), kf[i], nextkr); //refraction
 | 
				
			||||||
 | 
					                                             else
 | 
				
			||||||
 | 
					                                                stack2[k] = Ray(S, getRefraction(N, W, nextkr, eta, c1), kf[i], nextkr); //refraction
 | 
				
			||||||
 | 
					                                             currentK -= nextkr;
 | 
				
			||||||
 | 
					                                             next_top ++;
 | 
				
			||||||
 | 
					                                          }
 | 
				
			||||||
 | 
					                                       }else{
 | 
				
			||||||
 | 
					                                          if(refl)
 | 
				
			||||||
 | 
					                                          {
 | 
				
			||||||
 | 
					                                             stack1[k] = Ray(S, (-(2. * c1 * N - W)), currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                             currentK -= nextks;
 | 
				
			||||||
 | 
					                                             next_top ++;
 | 
				
			||||||
 | 
					                                          }
 | 
				
			||||||
 | 
					                                          if(refr)
 | 
				
			||||||
 | 
					                                          {
 | 
				
			||||||
 | 
					                                             if(refl)
 | 
				
			||||||
 | 
					                                                stack1[k+1] = Ray(S, getRefraction(N, W, nextkr, eta, c1), kf[i], nextkr); //refraction
 | 
				
			||||||
 | 
					                                             else
 | 
				
			||||||
 | 
					                                                stack1[k] = Ray(S, getRefraction(N, W, nextkr, eta, c1), kf[i], nextkr); //refraction
 | 
				
			||||||
 | 
					                                             currentK -= nextkr;
 | 
				
			||||||
 | 
					                                             next_top ++;
 | 
				
			||||||
 | 
					                                          }
 | 
				
			||||||
 | 
					                                       }
 | 
				
			||||||
 | 
					                                       break;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                              scolor += currentK * color;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else{
 | 
				
			||||||
 | 
					                              float c1 = (dot(N, W));
 | 
				
			||||||
 | 
					                              float ita = kf_air/currKf;
 | 
				
			||||||
 | 
					                              if(c1<0.)
 | 
				
			||||||
 | 
					                              {   
 | 
				
			||||||
 | 
					                                 c1 = -c1;
 | 
				
			||||||
 | 
					                                 N = - N;
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                              float c2 = (1.-ita*ita*(1.-c1*c1));
 | 
				
			||||||
 | 
					                              if(c2 >= 0.)
 | 
				
			||||||
 | 
					                                 c2 = sqrt(c2);
 | 
				
			||||||
 | 
					                              else c2 = -sqrt(-c2);
 | 
				
			||||||
 | 
					                              for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                                 if(k == next_top){
 | 
				
			||||||
 | 
					                                    if(stackswap)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       //stack2[k] = Ray(S, ((2. * c1 * N - W)), currKf, currentK*ks[i]); //reflection
 | 
				
			||||||
 | 
					                                       //if(c2>=0.)
 | 
				
			||||||
 | 
					                                       {
 | 
				
			||||||
 | 
					                                          stack2[k] = Ray(S, normalize(ita*W + (ita*c1 - c2)*N), kf_air, currentK*kr[i]); //refraction
 | 
				
			||||||
 | 
					                                          next_top ++;
 | 
				
			||||||
 | 
					                                       }
 | 
				
			||||||
 | 
					                                    }else{
 | 
				
			||||||
 | 
					                                       //stack1[k] = Ray(S, ((2. * c1 * N - W)), currKf, currentK*ks[i]); //reflection
 | 
				
			||||||
 | 
					                                       //if(c2 >= 0.)
 | 
				
			||||||
 | 
					                                       {
 | 
				
			||||||
 | 
					                                          stack1[k] = Ray(S, normalize(ita*W + (ita*c1 - c2)*N), kf_air, currentK*kr[i]); //refraction
 | 
				
			||||||
 | 
					                                          next_top ++;
 | 
				
			||||||
 | 
					                                       }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                   // next_top ++;
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                 }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               else {
 | 
				
			||||||
 | 
					                  float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					                  float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  if(t >= 0. && abs(sx) < 1.5 && abs(sz) < 3.)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                     vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					                     vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					                     color=(0.5+0.5*max(0.,realLDir.y)*LCol)*texture2D(uSampler[4],vec2((sx+2.)/3., (sz+1.)/6.)).xyz;
 | 
				
			||||||
 | 
					                     if(rtxoff || final&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        color += groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                           pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					                        scolor += currentK * color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                           if(k == next_top){
 | 
				
			||||||
 | 
					                              if(stackswap)
 | 
				
			||||||
 | 
					                                 stack2[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              else
 | 
				
			||||||
 | 
					                                 stack1[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              next_top ++;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        scolor += (currentK*.85)*color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  else{
 | 
				
			||||||
 | 
					                     if(j > 0)
 | 
				
			||||||
 | 
					                        scolor += currentK * pow(max(0.,dot(W, normalize(LDir - V))), 10.) * vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(++curr_ptr >= curr_top){
 | 
				
			||||||
 | 
					               curr_top = next_top;
 | 
				
			||||||
 | 
					               curr_ptr = 0;
 | 
				
			||||||
 | 
					               if(next_top * 2 > max_stack)
 | 
				
			||||||
 | 
					                  final = true;
 | 
				
			||||||
 | 
					               stackswap = !stackswap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(scolor),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,237 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#define _DEBUG_BREAK {gl_FragColor=vec4(1,0,0,1); return;}
 | 
				
			||||||
 | 
					#define REFRACTION normalize(c2 >= 0.? (eta*W + (eta*c1 - sqrt(c2))*N) : ((W + c1*N)/sqrt(1.-c1*c1)))
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform int f_tex, f_rt, f_moved;
 | 
				
			||||||
 | 
					uniform float dFL; //DELTA on FOCAL LENGTH
 | 
				
			||||||
 | 
					uniform mat3 transformation, invTr;
 | 
				
			||||||
 | 
					uniform vec3 Ambient[ns], Diffuse[ns];
 | 
				
			||||||
 | 
					uniform vec4 Specular[ns];
 | 
				
			||||||
 | 
					uniform float ks[ns], kr[ns], kf[ns];
 | 
				
			||||||
 | 
					uniform vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const float kf_air = 1.000293;
 | 
				
			||||||
 | 
					varying vec3 vPos;
 | 
				
			||||||
 | 
					float fl=3.;//ORIGINAL FOCAL LENGTH
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********PLEASE DO INCREASE n_ref(RT DEPTH) FOR BETTER RESULTS************/
 | 
				
			||||||
 | 
					/*---->*/const int n_ref=31; //2^n-1 because each hit now spawn at most 2 rays.
 | 
				
			||||||
 | 
					/**BUT BE CAUTIOUS IF YOU DON'T HAVE A DECENT GRAPHICS CARD (below GTX 950M)**/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int max_stack = (n_ref+1)/4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 scolor = vec3(0,0,0); //Actually 2^n_ref
 | 
				
			||||||
 | 
					struct Ray{
 | 
				
			||||||
 | 
					   vec3 V;
 | 
				
			||||||
 | 
					   vec3 W;
 | 
				
			||||||
 | 
					   float kf, cumulativeK;
 | 
				
			||||||
 | 
					} stack1[max_stack], stack2[max_stack];
 | 
				
			||||||
 | 
					bool modulo2(int n){
 | 
				
			||||||
 | 
					   return n-2*(n/2) == 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					vec2 getTextCoord(vec3 tex_sph, float R){
 | 
				
			||||||
 | 
					   float tex_x=atan(tex_sph.x,tex_sph.z)/_2pi + 0.5;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					   tex_x=fract(tex_x+uTime/20.);
 | 
				
			||||||
 | 
					   return vec2(tex_x,-asin(tex_sph.y/R)/pi + 0.5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					   vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   float currKf = kf_air;
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   vec3 trPos = transformation*((dFL+fl+1.)/(fl+1.))*vec3(vPos.xy, -1);
 | 
				
			||||||
 | 
					   vec3 V0=transformation*vec3(0.,0.,fl+dFL), V = V0;
 | 
				
			||||||
 | 
					   vec3 W=(trPos-V);
 | 
				
			||||||
 | 
					   bool rtxoff = false, showtexture = true, moved = false;
 | 
				
			||||||
 | 
					   float currentK = 1.;
 | 
				
			||||||
 | 
					   int curr_ptr = 0, curr_top = 0, next_top = 0;
 | 
				
			||||||
 | 
					   bool final = false, stackswap = false, stop = false;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      for(int curr = 0; curr < max_stack; ++curr){
 | 
				
			||||||
 | 
					         if(curr == curr_ptr){
 | 
				
			||||||
 | 
					            bool skip = false;
 | 
				
			||||||
 | 
					            if(j > 0){
 | 
				
			||||||
 | 
					               Ray currR;
 | 
				
			||||||
 | 
					               if(stackswap)
 | 
				
			||||||
 | 
					                  currR = stack1[curr];
 | 
				
			||||||
 | 
					               else
 | 
				
			||||||
 | 
					                  currR = stack2[curr];
 | 
				
			||||||
 | 
					               currKf = currR.kf;
 | 
				
			||||||
 | 
					               currentK = currR.cumulativeK;
 | 
				
			||||||
 | 
					               if(currKf <= 0.001 || currentK <= 0.001)
 | 
				
			||||||
 | 
					                  skip = true; 
 | 
				
			||||||
 | 
					               V = currR.V;
 | 
				
			||||||
 | 
					               W = currR.W;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else 
 | 
				
			||||||
 | 
					               W = normalize(W);
 | 
				
			||||||
 | 
					            if(!skip){
 | 
				
			||||||
 | 
					               float tMin=10000.;
 | 
				
			||||||
 | 
					               int iMin = -1;
 | 
				
			||||||
 | 
					               for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					                  vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					                  float B=dot(W,Vp);
 | 
				
			||||||
 | 
					                  float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					                  float D=B*B-C;
 | 
				
			||||||
 | 
					                  if(D>0.){
 | 
				
			||||||
 | 
					                     float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					                     if(t >= 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                        tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					                        iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else if (t >= -0.01 && t <0.01){
 | 
				
			||||||
 | 
					                        t = -(t + 2.*B);
 | 
				
			||||||
 | 
					                        if(t > 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                           tMin = t;
 | 
				
			||||||
 | 
					                           iMin = i;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               if(iMin >= 0){
 | 
				
			||||||
 | 
					                  float t = tMin;
 | 
				
			||||||
 | 
					                  vec3 S=V+t*W;
 | 
				
			||||||
 | 
					                  for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					                     if(i == iMin)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        vec3 texture_color;
 | 
				
			||||||
 | 
					                        if(showtexture)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                           vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                           texture_color=texture2D(uSampler[i],getTextCoord(tex_sph, Sph[i].w)).xyz;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                        vec3 realLDir=normalize(LDir-S);
 | 
				
			||||||
 | 
					                        float c1 =dot(N, W);
 | 
				
			||||||
 | 
					                        float eta, nextkf;
 | 
				
			||||||
 | 
					                        if(c1<0.){
 | 
				
			||||||
 | 
					                           color=(Ambient[i]+Diffuse[i]*max(0.,dot(N,realLDir))*LCol)*texture_color;
 | 
				
			||||||
 | 
					                           if(rtxoff || final) //if it's the last hit
 | 
				
			||||||
 | 
					                           {
 | 
				
			||||||
 | 
					                              color +=  Specular[i].xyz*pow(max(0.,
 | 
				
			||||||
 | 
					                                 dot(-2.*c1*N-realLDir,realLDir)),Specular[i].w);
 | 
				
			||||||
 | 
					                              scolor += color * currentK;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                           else{
 | 
				
			||||||
 | 
					                              c1 = -c1;
 | 
				
			||||||
 | 
					                              eta = currKf/kf[i];
 | 
				
			||||||
 | 
					                              nextkf = kf[i];
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else{
 | 
				
			||||||
 | 
					                           N = -N;
 | 
				
			||||||
 | 
					                           eta = currKf/kf_air;
 | 
				
			||||||
 | 
					                           nextkf = kf_air;
 | 
				
			||||||
 | 
					                           color = Ambient[i];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        float c2 = (1.-eta*eta*(1.-c1*c1));
 | 
				
			||||||
 | 
					                        float nextks = currentK * ks[i], nextkr = currentK * kr[i];
 | 
				
			||||||
 | 
					                        bool refl = nextks > 0.01, refr = nextkr > 0.01;
 | 
				
			||||||
 | 
					                        if(refl || refr)
 | 
				
			||||||
 | 
					                           for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                              if(k == next_top){
 | 
				
			||||||
 | 
					                                 if(stackswap){
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       stack2[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack2[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack2[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }else{
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    { //remember, c1 = -NW now
 | 
				
			||||||
 | 
					                                       stack1[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack1[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack1[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }
 | 
				
			||||||
 | 
					                                 break;
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                        scolor += color * currentK;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               else {
 | 
				
			||||||
 | 
					                  float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					                  float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  if(t >= 0. && abs(sx) < 1.5 && abs(sz) < 3.)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                     vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					                     vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					                     color=(0.5+0.5*max(0.,realLDir.y)*LCol)*texture2D(uSampler[4],vec2((sx+1.4)/3., (sz+1.5)/4.)).xyz;
 | 
				
			||||||
 | 
					                     if(rtxoff || final&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        color += groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                           pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					                        scolor += currentK * color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                           if(k == next_top){
 | 
				
			||||||
 | 
					                              if(stackswap)
 | 
				
			||||||
 | 
					                                 stack2[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              else
 | 
				
			||||||
 | 
					                                 stack1[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              next_top ++;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        scolor += (currentK*.85)*color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  else{
 | 
				
			||||||
 | 
					                     if(j > 0)
 | 
				
			||||||
 | 
					                        scolor += currentK * (pow(max(0.,dot(W, normalize(LDir - V))), 10.) * vec3(3.,3.,3.) + foregroundColor*0.1);
 | 
				
			||||||
 | 
					                     else scolor = foregroundColor*0.6;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(++curr_ptr >= curr_top){
 | 
				
			||||||
 | 
					               if(next_top <= 0)
 | 
				
			||||||
 | 
					                  stop = true;
 | 
				
			||||||
 | 
					               if(next_top * 2 > max_stack)
 | 
				
			||||||
 | 
					                  final = true;
 | 
				
			||||||
 | 
					               curr_top = next_top;
 | 
				
			||||||
 | 
					               next_top = 0;
 | 
				
			||||||
 | 
					               curr_ptr = 0;
 | 
				
			||||||
 | 
					               
 | 
				
			||||||
 | 
					               stackswap = !stackswap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if(stop)
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(scolor),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.7 KiB  | 
@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src=lib4.header.js></script>
 | 
				
			||||||
 | 
					<script src=lib4.js></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<font size=7 color=#909090>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   StarCraft RTX 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img id="rtx" style="float:right;" src="./RTXon.svg" type="image/svg+xml"
 | 
				
			||||||
 | 
					   alt="Turn Ray Tracing On/OFF" title="Turn Ray Tracing On/OFF" height=60px /img>
 | 
				
			||||||
 | 
					<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>
 | 
				
			||||||
 | 
					<TABLE cellspacing=0 cellpadding=0><TR>
 | 
				
			||||||
 | 
					<td><font color=red size=5><div id=errorMessage></div></font></td>
 | 
				
			||||||
 | 
					</TR><TR>
 | 
				
			||||||
 | 
					<table cellspacing=0>
 | 
				
			||||||
 | 
					<tr>
 | 
				
			||||||
 | 
					<td valign=top>
 | 
				
			||||||
 | 
					<div id="ace" style="width:800px;height:2200px;"></div>
 | 
				
			||||||
 | 
					</td><td valign=top>
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					   <center>
 | 
				
			||||||
 | 
					      <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					   <canvas id='canvas1' style=" overflow: hidden !important; width: 600px !important; height:600px !important;" width=599 height=599></canvas>
 | 
				
			||||||
 | 
					   </center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					<div id="controls">
 | 
				
			||||||
 | 
					<input type="number" id="ins" style="margin-left:0px;font-size:24px;width:35px;height:45px" value="5" max="5" min = "1">
 | 
				
			||||||
 | 
					<button id="bns" style="margin-left:0px;font-size:24px;width:105px;height:45px">Spheres</button>
 | 
				
			||||||
 | 
					<input type="number" id="insamp" style="margin-left:2px;font-size:24px;width:60px;height:45px" value="1" max="4" min = "0.25" step="0.2">
 | 
				
			||||||
 | 
					<button id="bnsamp" style="margin-left:0px;font-size:24px;width:190px;height:45px">Super Sampling</button>
 | 
				
			||||||
 | 
					<button id="bnfs" style="margin-left:2px;font-size:24px;width:180px;height:45px">Fullscreen</button>
 | 
				
			||||||
 | 
					<button id="clrsel" style="margin-left:0px;font-size:24px;width:180px;height:45px">Clear Selection</button>
 | 
				
			||||||
 | 
					<button id="reset" style="margin-left:0px;font-size:24px;width:100px;height:45px">Reset</button>
 | 
				
			||||||
 | 
					<div style=\'font-size:25px\'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <font color=#909090>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					   <i style="font-size:25px;">What's new: </i>
 | 
				
			||||||
 | 
					   <p style="font-size:20px;"> 
 | 
				
			||||||
 | 
					       As before, drag on the canvas to rotate the scene, scroll on it to change focal point (perspective projection). 
 | 
				
			||||||
 | 
					   Double click it to pause/resume.<br>
 | 
				
			||||||
 | 
					   I now added Fullscreen mode so that we can scroll on the canvas without scrolling the whole page and use single-key 
 | 
				
			||||||
 | 
					   hotkeys without worrying about conflicts with the editor. <br>
 | 
				
			||||||
 | 
					       <a style="color:red;">Now, you can select a sphere by clicking on it (literally, click the sphere on the canvas!). And drag it around 
 | 
				
			||||||
 | 
					   to move it.</a><br>
 | 
				
			||||||
 | 
					       When a sphere is selected, you can also scroll whe mouse wheel to change its radius, and <strong>in fullscreen mode</strong>, press B and F key to send 
 | 
				
			||||||
 | 
					   it backward or forward <strong>according to your view point!</strong><br>
 | 
				
			||||||
 | 
					       I also optimized the code a little bit, so that the transformation matrix is completely computed in CPU, 
 | 
				
			||||||
 | 
					   and applied (multiplied) inside the <a href="./shader.vert">vertex shader</a>.<br>
 | 
				
			||||||
 | 
					       I suggest moving spheres when pausing the scene by double clicking the canvas, otherwise the spheres are already moving.<br>
 | 
				
			||||||
 | 
					       <strong>If you found the scene somehow clipped, it seems to be a bug of chromium, please simply click on 'Super Sampling' button
 | 
				
			||||||
 | 
					    or refresh the page. Otherwise the interactions won't work because the coordinates are wrong.</strong>
 | 
				
			||||||
 | 
					   </p>
 | 
				
			||||||
 | 
					   <div id="howitworks">
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					   <p style="font-size:20px;"> 
 | 
				
			||||||
 | 
					      <i style="font-size:25px;">How it works:</i><br>
 | 
				
			||||||
 | 
					      I used similar method in raytracing to find the sphere it hits.<br>
 | 
				
			||||||
 | 
					      The transformation methods are implemented in <a href="./lib4.header.js">lib4.header.js</a><br>
 | 
				
			||||||
 | 
					      Interaction parts are in <a href="./lib4.ext.js">lib4.ext.js</a><br>
 | 
				
			||||||
 | 
					      <a href="./lib4.js">lib4.js</a> most contains initialization methods for the renderer.<br>
 | 
				
			||||||
 | 
					      <a href="./index.html">index.html</a> is almost pure html.<br>
 | 
				
			||||||
 | 
					   </p>
 | 
				
			||||||
 | 
					   </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <p>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div></td>
 | 
				
			||||||
 | 
					</tr></table>
 | 
				
			||||||
 | 
					</TR></TABLE>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script src="lib4.ext.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					   setInterval(() => {
 | 
				
			||||||
 | 
					      if(window.vs != null && window.fs != null&& canvas1.setShaders === undefined)
 | 
				
			||||||
 | 
					         gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					   }, 200);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -0,0 +1,359 @@
 | 
				
			|||||||
 | 
					let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
 | 
				
			||||||
 | 
					let lastClick = undefined;
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					var startTime = Date.now();
 | 
				
			||||||
 | 
					let lastTime = Date.now();
 | 
				
			||||||
 | 
					var lastFrameTime = 0;
 | 
				
			||||||
 | 
					let oldDocument;
 | 
				
			||||||
 | 
					let fullscreen = false;
 | 
				
			||||||
 | 
					let oldparents = {};
 | 
				
			||||||
 | 
					var tr, div;
 | 
				
			||||||
 | 
					let canvas_originalsize;
 | 
				
			||||||
 | 
					let Sph = [];
 | 
				
			||||||
 | 
					let SphTr = [];
 | 
				
			||||||
 | 
					let SphDletaR = []
 | 
				
			||||||
 | 
					let selected = false, selection = -1, dragging = false;
 | 
				
			||||||
 | 
					for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					   SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function toggleFullscreen(element){
 | 
				
			||||||
 | 
					   if(fullscreen)
 | 
				
			||||||
 | 
					   { 
 | 
				
			||||||
 | 
					      if (document.exitFullscreen) 
 | 
				
			||||||
 | 
					         document.exitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.webkitExitFullscreen) 
 | 
				
			||||||
 | 
					         document.webkitExitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.mozCancelFullScreen) 
 | 
				
			||||||
 | 
					         document.mozCancelFullScreen();
 | 
				
			||||||
 | 
					      else if (document.msExitFullscreen) 
 | 
				
			||||||
 | 
					         document.msExitFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = false;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      if(element.requestFullscreen)
 | 
				
			||||||
 | 
					         element.requestFullscreen();
 | 
				
			||||||
 | 
					      else if (element.webkitRequestFullscreen)
 | 
				
			||||||
 | 
					         element.webkitRequestFullscreen();
 | 
				
			||||||
 | 
					      else if(element.msRequestFullscreen)
 | 
				
			||||||
 | 
					         element.msRequestFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = true;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Exit Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnfs.onclick = function(_){
 | 
				
			||||||
 | 
					   if(fullscreen){
 | 
				
			||||||
 | 
					      oldparents[controls].appendChild(controls);
 | 
				
			||||||
 | 
					      oldparents[canvas1].appendChild(canvas1);
 | 
				
			||||||
 | 
					      canvas1.style.width = canvas_originalsize[0];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas_originalsize[1];
 | 
				
			||||||
 | 
					      howitworks.hidden = false;
 | 
				
			||||||
 | 
					   }else{
 | 
				
			||||||
 | 
					      div = document.createElement("div");
 | 
				
			||||||
 | 
					      tr = document.createElement("table").insertRow();
 | 
				
			||||||
 | 
					      tr.style.backgroundColor="white";
 | 
				
			||||||
 | 
					      let size = Math.min(screen.availHeight, screen.availWidth);
 | 
				
			||||||
 | 
					      canvas_originalsize = [canvas1.style.width, canvas1.style.height, canvas1.width, canvas1.height];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas1.style.width = size;
 | 
				
			||||||
 | 
					      howitworks.hidden=true;
 | 
				
			||||||
 | 
					      oldparents[controls] = controls.parentNode;
 | 
				
			||||||
 | 
					      oldparents[canvas1] = canvas1.parentNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let td1 = tr.insertCell();
 | 
				
			||||||
 | 
					      td1.appendChild(canvas1);
 | 
				
			||||||
 | 
					      let td2;
 | 
				
			||||||
 | 
					      td2 = tr.insertCell();
 | 
				
			||||||
 | 
					      td2.style.verticalAlign="top";
 | 
				
			||||||
 | 
					      td2.appendChild(controls);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      div.appendChild(tr);
 | 
				
			||||||
 | 
					      document.body.appendChild(div);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   toggleFullscreen(div);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					clrsel.onclick=function(_){
 | 
				
			||||||
 | 
					   setUniform("1i", "sel", -1);
 | 
				
			||||||
 | 
					   selected = false;
 | 
				
			||||||
 | 
					   selection = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					reset.onclick = function(_){
 | 
				
			||||||
 | 
					   clrsel.onclick();
 | 
				
			||||||
 | 
					   if(!animating)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   flags = 0;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   mousedx = mousedy = mousedz = 0;
 | 
				
			||||||
 | 
					   positionsupdated = true;
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					      SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bns.onclick=function(e){
 | 
				
			||||||
 | 
					   if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
 | 
				
			||||||
 | 
					   {   
 | 
				
			||||||
 | 
					      cns = ins.value;
 | 
				
			||||||
 | 
					      fragmentShaderDefs = '\n const int cns = ' + cns + ';';
 | 
				
			||||||
 | 
					      if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnsamp.onclick=function(e){
 | 
				
			||||||
 | 
					   let multiplier  = insamp.value;
 | 
				
			||||||
 | 
					   let w = parseInt(canvas1.style.width)*multiplier;
 | 
				
			||||||
 | 
					   let h = parseInt(canvas1.style.height)*multiplier;
 | 
				
			||||||
 | 
					   canvas1.height = h;
 | 
				
			||||||
 | 
					   canvas1.width = w;
 | 
				
			||||||
 | 
					   gl.viewport(0, 0, w, h);
 | 
				
			||||||
 | 
					   //gl.clearRect(0, 0, w, h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					if(fs != undefined)
 | 
				
			||||||
 | 
					    editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					   if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					delete editor.KeyBinding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let pause_resume = function(){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      lastTime = Date.now();
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					   animating = !animating;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(!(shift && alt) && lastClick&& Date.now()-lastClick<400)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   lastClick = Date.now();
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseover', function(e){
 | 
				
			||||||
 | 
					   over = true;
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags |= mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousedown', function(e){
 | 
				
			||||||
 | 
					      moving = true
 | 
				
			||||||
 | 
					      mouselastX = mouselastY =  undefined;
 | 
				
			||||||
 | 
					      let i = hitTest([2*e.offsetX/ parseInt(canvas1.style.width)-1, 
 | 
				
			||||||
 | 
					         1-2*e.offsetY/ parseInt(canvas1.style.height), -1]);
 | 
				
			||||||
 | 
					      if(i >= 0)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         dragging = true;
 | 
				
			||||||
 | 
					         selected = true;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else if(selected = true){
 | 
				
			||||||
 | 
					         dragging = false;
 | 
				
			||||||
 | 
					         selected = false;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousemove', function(e){
 | 
				
			||||||
 | 
					      if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
 | 
				
			||||||
 | 
					         let dx = (mouselastX - e.offsetX), 
 | 
				
			||||||
 | 
					             dy = (mouselastY - e.offsetY);
 | 
				
			||||||
 | 
					         if(!selected)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            mousedx -= dx/60;
 | 
				
			||||||
 | 
					            mousedy -= dy/60;
 | 
				
			||||||
 | 
					            positionsupdated = true;
 | 
				
			||||||
 | 
					         }else if(dragging){
 | 
				
			||||||
 | 
					            let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					            m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					            let dv = matrix_multiply(m, [2*-dx/ parseInt(canvas1.style.width), 
 | 
				
			||||||
 | 
					               2*dy/ parseInt(canvas1.style.height), 0, 1]).slice(0,3);
 | 
				
			||||||
 | 
					            SphTr[selection] = matrix_multiply(SphTr[selection], matrix_translate(dv[0], dv[1], dv[2]));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mouselastX = e.offsetX;
 | 
				
			||||||
 | 
					      mouselastY = e.offsetY;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseup', function(e){
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   dragging = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseout', function(e){
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags &= !mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   over = false;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('wheel', function(e){
 | 
				
			||||||
 | 
					   if(!selected){
 | 
				
			||||||
 | 
					      mousedz += e.wheelDelta/600;
 | 
				
			||||||
 | 
					      positionsupdated = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      SphDletaR[selection] += e.wheelDelta / 800;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.scroll(function(e) {e.stopPropagation();});
 | 
				
			||||||
 | 
					rtx.style.cursor="pointer";
 | 
				
			||||||
 | 
					let rtswitch = function(){
 | 
				
			||||||
 | 
					   alert('Ray Tracing is always on. See hw2 where rt can be toggled on/off.')
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					rtx.addEventListener('click', rtswitch);
 | 
				
			||||||
 | 
					var requestAnimationFrame = window.requestAnimationFrame ||
 | 
				
			||||||
 | 
					 window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 | 
				
			||||||
 | 
					let fpscounter = function(time){
 | 
				
			||||||
 | 
					      if (start === undefined)
 | 
				
			||||||
 | 
					         start = time;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
 | 
				
			||||||
 | 
					      start = time;
 | 
				
			||||||
 | 
					      if(fpson)
 | 
				
			||||||
 | 
					         ;//requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         start = undefined;
 | 
				
			||||||
 | 
					         fps.innerHTML = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = true;
 | 
				
			||||||
 | 
					   else if(ctrl && alt && e.code == 'KeyT'){
 | 
				
			||||||
 | 
					      const mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)?mask:0);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (ctrl &&e.code == 'KeyS'){
 | 
				
			||||||
 | 
					      let a = document.createElement('a');
 | 
				
			||||||
 | 
					      a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
 | 
				
			||||||
 | 
					      a.download = 'shader.frag';
 | 
				
			||||||
 | 
					      a.click();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyR')
 | 
				
			||||||
 | 
					      rtswitch();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyN')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      reset.onclick();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyP')
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyF')
 | 
				
			||||||
 | 
					      if(!fpson)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         fpson = true;
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fpson = false;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   if(fullscreen && selected ){
 | 
				
			||||||
 | 
					      if(/*e.code == 'ArrowUp' || e.code == 'ArrowDown' || e.code =='ArrowLeft'
 | 
				
			||||||
 | 
					         ||e.code == 'ArrowRight' || e.code =='KeyW'||e.code =='KeyS'||*/e.code =='KeyF'||e.code =='KeyB'){
 | 
				
			||||||
 | 
					            let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					            m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					            m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch(e.code){
 | 
				
			||||||
 | 
					               // case 'ArrowUp':
 | 
				
			||||||
 | 
					               //    m = matrix_multiply(m, matrix_rotateX(0.1));
 | 
				
			||||||
 | 
					               //    break;
 | 
				
			||||||
 | 
					               // case 'ArrowDown':
 | 
				
			||||||
 | 
					               //    m = matrix_multiply(m, matrix_rotateX(-0.1));
 | 
				
			||||||
 | 
					               //    break;
 | 
				
			||||||
 | 
					               // case 'ArrowLeft':
 | 
				
			||||||
 | 
					               //    m = matrix_multiply(m, matrix_rotateY(-0.1));
 | 
				
			||||||
 | 
					               //    break;
 | 
				
			||||||
 | 
					               // case 'ArrowRight':
 | 
				
			||||||
 | 
					               //    m = matrix_multiply(m, matrix_rotateY(0.1));
 | 
				
			||||||
 | 
					               //    break;
 | 
				
			||||||
 | 
					               // case 'KeyW':
 | 
				
			||||||
 | 
					               //    m = matrix_multiply(m, matrix_rotateZ(0.1));
 | 
				
			||||||
 | 
					               //    break;
 | 
				
			||||||
 | 
					               // case 'KeyS':
 | 
				
			||||||
 | 
					               //    m = matrix_multiply(m, matrix_rotateZ(-0.1));
 | 
				
			||||||
 | 
					               //    break;     
 | 
				
			||||||
 | 
					               case 'KeyB':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, -0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					               case 'KeyF':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, 0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;                
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            SphTr[selection] = matrix_multiply(SphTr[selection], m);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   let uTime;
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (Date.now() - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (lastTime - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   Sph[0] = [0,0.05*Math.cos(uTime + 1.),.045*Math.cos(uTime), 1,.15];
 | 
				
			||||||
 | 
					   Sph[1] = [0,0,0,1,.25];
 | 
				
			||||||
 | 
					   Sph[2] = [.22*Math.sin(uTime*1.2),0.05,.22*Math.cos(uTime*1.2),1,.05];
 | 
				
			||||||
 | 
					   Sph[3] = [.9*Math.sin(uTime*.4),0.,.9*Math.cos(uTime*.4),1,.25];
 | 
				
			||||||
 | 
					   Sph[4] = [0.5*Math.sin(uTime*1.),0.08*Math.sin(uTime *0.9),.5*Math.cos(uTime*1.),1,.12];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++ i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let trsph = matrix_multiply(SphTr[i], Sph[i]);
 | 
				
			||||||
 | 
					      trsph[3] = Sph[i][4];
 | 
				
			||||||
 | 
					      setUniform('4fv', 'Sph['+ i + ']', trsph);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   if(positionsupdated)
 | 
				
			||||||
 | 
					      updatePositions();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					requestAnimationFrame(fpscounter);
 | 
				
			||||||
@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					//Header file, contains global variable definitions, 
 | 
				
			||||||
 | 
					// asynchronized shader loading and utility functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let mousedx = 0, mousedy = 0, mousedz = 0;
 | 
				
			||||||
 | 
					let seldx = 0, seldy = 0, seldz = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var cx = 1, cy = 1, sx = 0, sy = 0;
 | 
				
			||||||
 | 
					let mouselastX, mouselastY;
 | 
				
			||||||
 | 
					const fl = 3;
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					var vs, fs;
 | 
				
			||||||
 | 
					var vsfetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					var editor = undefined
 | 
				
			||||||
 | 
					let cos = Math.cos, sin = Math.sin, tan = Math.tan,
 | 
				
			||||||
 | 
					    acos = Math.acos, asin = Math.asin, atan = Math.atan,
 | 
				
			||||||
 | 
					    sqrt = Math.sqrt;
 | 
				
			||||||
 | 
					let positionsupdated = true;
 | 
				
			||||||
 | 
					vsfetch.open('GET', './shader.vert');
 | 
				
			||||||
 | 
					vsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    vs = vsfetch.responseText;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					vsfetch.send();
 | 
				
			||||||
 | 
					//* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					var client = new XMLHttpRequest();
 | 
				
			||||||
 | 
					client.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					client.onloadend = function () {
 | 
				
			||||||
 | 
					    fs = (client.responseText);
 | 
				
			||||||
 | 
					    //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					    if (editor != undefined)
 | 
				
			||||||
 | 
					        editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					client.send();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// I HAVE IMPLEMENTED THESE FUNCTIONS FOR YOU
 | 
				
			||||||
 | 
					let matrix_identity = () => {
 | 
				
			||||||
 | 
					    return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_translate = (x, y, z) => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[12] = x;
 | 
				
			||||||
 | 
					    m[13] = y;
 | 
				
			||||||
 | 
					    m[14] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// YOU NEED TO PROPERLY IMPLEMENT THE FOLLOWING FIVE FUNCTIONS:
 | 
				
			||||||
 | 
					let matrix_rotateX = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    m[6] = sin(theta);
 | 
				
			||||||
 | 
					    m[9] = -sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let matrix_rotateY = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[2] = -sin(theta);
 | 
				
			||||||
 | 
					    m[8] = sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_rotateZ= theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[1] = sin(theta);
 | 
				
			||||||
 | 
					    m[4] = -sin(theta);
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_scale = (x, y, z) => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = x;
 | 
				
			||||||
 | 
					    m[5] = y;
 | 
				
			||||||
 | 
					    m[10] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_multiply = (a, b, m = 4, n = 4) => { //dim=mn*nm=mm
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    if (b.length < m*n) { //mat-vec multiply (i did this for my convenience)
 | 
				
			||||||
 | 
					        for (let i = 0; i < m; ++i) {
 | 
				
			||||||
 | 
					            res[i] = 0;
 | 
				
			||||||
 | 
					            for (let j = 0; j < n; ++j)
 | 
				
			||||||
 | 
					                res[i] += b[j] * a[m * j + i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    } //otherwise mm multiply
 | 
				
			||||||
 | 
					    for (let i = 0; i < m; ++i)
 | 
				
			||||||
 | 
					        for (let j = 0; j < m; ++j) {
 | 
				
			||||||
 | 
					            var t = 0;
 | 
				
			||||||
 | 
					            for (let k = 0; k < n; ++k)
 | 
				
			||||||
 | 
					                t += a[k * m + j] * b[i * n + k];
 | 
				
			||||||
 | 
					            res.push(t);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let const_multiply = (c, a) => {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++ i)
 | 
				
			||||||
 | 
					        m[i] = a[i] * c;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function dot(a, b){
 | 
				
			||||||
 | 
					    let m = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m += a[i] * b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function plus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] + b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function minus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] - b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function normalize(v){
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    sum = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        sum += v[i] * v[i];
 | 
				
			||||||
 | 
					    sum = sqrt(sum);
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        res[i] = v[i] / sum;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function updatePositions() {
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    setUniform('3f', 'V0', m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz));
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    setUniform('Matrix3fv', 'transformation', false, [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]);
 | 
				
			||||||
 | 
					    positionsupdated = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest(pos){
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    let V = [m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz)];
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    let trPos = matrix_multiply([m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]], pos, 3,3);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    let W=normalize(minus(trPos, V));
 | 
				
			||||||
 | 
					    let tMin=10000.;
 | 
				
			||||||
 | 
					    let iMin = -1;
 | 
				
			||||||
 | 
					    for(let i=0;i<cns;i++){
 | 
				
			||||||
 | 
					    let Vp=minus(V, matrix_multiply(SphTr[i], Sph[i]));
 | 
				
			||||||
 | 
					    let B=dot(W,Vp);
 | 
				
			||||||
 | 
					    let C=dot(Vp,Vp)-Sph[i][4]*Sph[i][4];
 | 
				
			||||||
 | 
					    let D=B*B-C;
 | 
				
			||||||
 | 
					    if(D>0.){
 | 
				
			||||||
 | 
					       let t=-B-sqrt(D);
 | 
				
			||||||
 | 
					       if(t > 0.0 && t < tMin){
 | 
				
			||||||
 | 
					          tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					          iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return iMin;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
@ -0,0 +1,189 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					let ns = 5, cns = 5;
 | 
				
			||||||
 | 
					fragmentShaderHeader+= 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					let fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;   
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					     bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   } 
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let texture = [], gl, program;
 | 
				
			||||||
 | 
					let textures = []; 
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					   console.log('glstart');
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = 'Build Your Own Universe!';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader +fragmentShaderDefs+ fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; ++i){
 | 
				
			||||||
 | 
					            loadTexture(gl, './'+(i+1)+'.jpg', i); //Texture loading.
 | 
				
			||||||
 | 
					            textures[i] = i;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
 | 
				
			||||||
 | 
					         positionsupdated = true;
 | 
				
			||||||
 | 
					         let attribs = [
 | 
				
			||||||
 | 
					            .05,.05,.1,  .5,.5,1.,  1.,.5,.5,20.,  0., .0, 1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  1.,.5,.5,  1.,.5,.5,10.,  .3,1.,1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  .71,.71,.71,  .71,.71,.71,10.,  0.3,.0,1.5,
 | 
				
			||||||
 | 
					            .1,.1,.1,  .71,.71,.71,  .71,.71,.71,10.,  0.05,0., 1.,
 | 
				
			||||||
 | 
					            .0,.0,.0,  .0,.0,.0,  .0,.0,.0,40.,  0.,.85,1.5
 | 
				
			||||||
 | 
					         ]
 | 
				
			||||||
 | 
					         var offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Ambient['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Diffuse['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('4fv', 'Specular['+i+']', attribs.slice(offset, offset += 4));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'ks['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kr['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kf['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					            [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 0, 0);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   if(gl)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					      (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,235 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#define _DEBUG_BREAK {gl_FragColor=vec4(1,0,0,1); return;}
 | 
				
			||||||
 | 
					#define REFRACTION (c2 >= 0.? (eta*W + (eta*c1 - sqrt(c2))*N) : ((W + c1*N)/sqrt(1.-c1*c1)))
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform vec3 Ambient[ns], Diffuse[ns];
 | 
				
			||||||
 | 
					uniform vec4 Specular[ns];
 | 
				
			||||||
 | 
					uniform float ks[ns], kr[ns], kf[ns];
 | 
				
			||||||
 | 
					uniform vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					uniform vec3 V0;
 | 
				
			||||||
 | 
					uniform int sel;
 | 
				
			||||||
 | 
					const float kf_air = 1.000293;
 | 
				
			||||||
 | 
					varying vec3 trPos;
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********PLEASE DO INCREASE n_ref(RT DEPTH) FOR BETTER RESULTS************/
 | 
				
			||||||
 | 
					/*---->*/const int n_ref=31; //2^n-1 because each hit now spawn at most 2 rays.
 | 
				
			||||||
 | 
					/**BUT BE CAUTIOUS IF YOU DON'T HAVE A DECENT GRAPHICS CARD (below GTX 950M)**/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int max_stack = (n_ref+1)/4;
 | 
				
			||||||
 | 
					vec3 scolor = vec3(0,0,0); 
 | 
				
			||||||
 | 
					struct Ray{
 | 
				
			||||||
 | 
					   vec3 V;
 | 
				
			||||||
 | 
					   vec3 W;
 | 
				
			||||||
 | 
					   float kf, cumulativeK;
 | 
				
			||||||
 | 
					} stack1[max_stack], stack2[max_stack];
 | 
				
			||||||
 | 
					bool modulo2(int n){
 | 
				
			||||||
 | 
					   return n-2*(n/2) == 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					vec2 getTextCoord(vec3 tex_sph, float R){
 | 
				
			||||||
 | 
					   float tex_x=atan(tex_sph.z,tex_sph.x)/_2pi + 0.5;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					   tex_x=fract(tex_x+uTime/20.);
 | 
				
			||||||
 | 
					   return vec2(tex_x,-asin(tex_sph.y/R)/pi + 0.5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					   vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   float currKf = kf_air;
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=(trPos-V);
 | 
				
			||||||
 | 
					   bool rtxoff = false, showtexture = true, selected = false;
 | 
				
			||||||
 | 
					   float currentK = 1.;
 | 
				
			||||||
 | 
					   int curr_ptr = 0, curr_top = 0, next_top = 0;
 | 
				
			||||||
 | 
					   bool final = false, stackswap = false, stop = false;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      for(int curr = 0; curr < max_stack; ++curr){
 | 
				
			||||||
 | 
					         if(curr == curr_ptr){
 | 
				
			||||||
 | 
					            bool skip = false;
 | 
				
			||||||
 | 
					            if(j > 0){
 | 
				
			||||||
 | 
					               Ray currR;
 | 
				
			||||||
 | 
					               if(stackswap)
 | 
				
			||||||
 | 
					                  currR = stack1[curr];
 | 
				
			||||||
 | 
					               else
 | 
				
			||||||
 | 
					                  currR = stack2[curr];
 | 
				
			||||||
 | 
					               currKf = currR.kf;
 | 
				
			||||||
 | 
					               currentK = currR.cumulativeK;
 | 
				
			||||||
 | 
					               if(currKf <= 0.001 || currentK <= 0.001)
 | 
				
			||||||
 | 
					                  skip = true; 
 | 
				
			||||||
 | 
					               V = currR.V;
 | 
				
			||||||
 | 
					               W = currR.W;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else 
 | 
				
			||||||
 | 
					               W = normalize(W);
 | 
				
			||||||
 | 
					            if(!skip){
 | 
				
			||||||
 | 
					               float tMin=10000.;
 | 
				
			||||||
 | 
					               int iMin = -1;
 | 
				
			||||||
 | 
					               for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					                  vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					                  float B=dot(W,Vp);
 | 
				
			||||||
 | 
					                  float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					                  float D=B*B-C;
 | 
				
			||||||
 | 
					                  if(D>0.){
 | 
				
			||||||
 | 
					                     float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					                     if(t >= 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                        tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					                        iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else if (t >= -0.01 && t <0.01){
 | 
				
			||||||
 | 
					                        t = -(t + 2.*B);
 | 
				
			||||||
 | 
					                        if(t > 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                           tMin = t;
 | 
				
			||||||
 | 
					                           iMin = i;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               if(iMin >= 0){
 | 
				
			||||||
 | 
					                  if(j == 0 && iMin == sel)
 | 
				
			||||||
 | 
					                     selected = true;
 | 
				
			||||||
 | 
					                  float t = tMin;
 | 
				
			||||||
 | 
					                  vec3 S=V+t*W;
 | 
				
			||||||
 | 
					                  for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					                     if(i == iMin)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        vec3 texture_color;
 | 
				
			||||||
 | 
					                        if(showtexture)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                           vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                           texture_color=texture2D(uSampler[i],getTextCoord(tex_sph, Sph[i].w)).xyz;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                        vec3 realLDir=normalize(LDir-S);
 | 
				
			||||||
 | 
					                        float c1 =dot(N, W);
 | 
				
			||||||
 | 
					                        float eta, nextkf;
 | 
				
			||||||
 | 
					                        if(c1<0.){
 | 
				
			||||||
 | 
					                           color=(Ambient[i]+Diffuse[i]*max(0.,dot(N,realLDir))*LCol)*texture_color;
 | 
				
			||||||
 | 
					                           if(rtxoff || final) //if it's the last hit
 | 
				
			||||||
 | 
					                           {
 | 
				
			||||||
 | 
					                              color +=  Specular[i].xyz*pow(max(0.,
 | 
				
			||||||
 | 
					                                 dot(-2.*c1*N-realLDir,realLDir)),Specular[i].w);
 | 
				
			||||||
 | 
					                              scolor += color * currentK;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                           else{
 | 
				
			||||||
 | 
					                              c1 = -c1;
 | 
				
			||||||
 | 
					                              eta = currKf/kf[i];
 | 
				
			||||||
 | 
					                              nextkf = kf[i];
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else{
 | 
				
			||||||
 | 
					                           N = -N;
 | 
				
			||||||
 | 
					                           eta = currKf/kf_air;
 | 
				
			||||||
 | 
					                           nextkf = kf_air;
 | 
				
			||||||
 | 
					                           color = Ambient[i];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        float c2 = (1.-eta*eta*(1.-c1*c1));
 | 
				
			||||||
 | 
					                        float nextks = currentK * ks[i], nextkr = currentK * kr[i];
 | 
				
			||||||
 | 
					                        bool refl = nextks > 0.01, refr = nextkr > 0.01;
 | 
				
			||||||
 | 
					                        if(refl || refr)
 | 
				
			||||||
 | 
					                           for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                              if(k == next_top){
 | 
				
			||||||
 | 
					                                 if(stackswap){
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       stack2[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack2[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack2[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }else{
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    { //remember, c1 = -NW now
 | 
				
			||||||
 | 
					                                       stack1[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack1[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack1[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }
 | 
				
			||||||
 | 
					                                 break;
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                        scolor += color * currentK;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               else {
 | 
				
			||||||
 | 
					                  float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					                  float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  if(t >= 0. && abs(sx) < 1.5 && abs(sz) < 3.)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                     vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					                     vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					                     color=(0.5+0.5*max(0.,realLDir.y)*LCol)*texture2D(uSampler[4],vec2((sx+1.4)/3., (sz+1.5)/4.)).xyz;
 | 
				
			||||||
 | 
					                     if(rtxoff || final&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        color += groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                           pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					                        scolor += currentK * color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                           if(k == next_top){
 | 
				
			||||||
 | 
					                              if(stackswap)
 | 
				
			||||||
 | 
					                                 stack2[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              else
 | 
				
			||||||
 | 
					                                 stack1[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              next_top ++;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        scolor += (currentK*.85)*color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  else{
 | 
				
			||||||
 | 
					                     if(j > 0)
 | 
				
			||||||
 | 
					                        scolor += currentK * (pow(max(0.,dot(W, normalize(LDir - V))), 10.) * vec3(3.,3.,3.) + foregroundColor*0.1);
 | 
				
			||||||
 | 
					                     else scolor = foregroundColor*0.6;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(++curr_ptr >= curr_top){
 | 
				
			||||||
 | 
					               if(next_top <= 0)
 | 
				
			||||||
 | 
					                  stop = true;
 | 
				
			||||||
 | 
					               if(next_top * 2 > max_stack)
 | 
				
			||||||
 | 
					                  final = true;
 | 
				
			||||||
 | 
					               curr_top = next_top;
 | 
				
			||||||
 | 
					               next_top = 0;
 | 
				
			||||||
 | 
					               curr_ptr = 0;
 | 
				
			||||||
 | 
					               stackswap = !stackswap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if(stop)
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(selected)
 | 
				
			||||||
 | 
					      scolor.x += 0.5;
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(scolor),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					attribute vec3 aPos;
 | 
				
			||||||
 | 
					varying   vec3 trPos;
 | 
				
			||||||
 | 
					uniform mat3 transformation; 
 | 
				
			||||||
 | 
					//I used mat3 instead of the augmented mat4 matrix because we 
 | 
				
			||||||
 | 
					//are not doing complex projections yet. I implemented simple 
 | 
				
			||||||
 | 
					//perspective projection back in hw2 by changing focal length 
 | 
				
			||||||
 | 
					//and adjusting the size of the projected surface accrodingly.
 | 
				
			||||||
 | 
					//New surface = distance(surface, old viewpoint)/ distance(surface, new viewpoint) * old surface
 | 
				
			||||||
 | 
					//            = (deltaFl + fl + 1)/(fl + 1) * old surface
 | 
				
			||||||
 | 
					//This is implemented by vPos = (dFl + fl + 1)/(fl + 1) * vPos;
 | 
				
			||||||
 | 
					//Because we will multiply the resulting vPos by the transformation matrix 
 | 
				
			||||||
 | 
					//anyway, I smashed the ratio into the matrix into avoid doing this in shaders.
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    gl_Position = vec4(aPos, 1.);
 | 
				
			||||||
 | 
					    trPos = transformation *vec3(aPos.xy, -1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,235 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#define _DEBUG_BREAK {gl_FragColor=vec4(1,0,0,1); return;}
 | 
				
			||||||
 | 
					#define REFRACTION (c2 >= 0.? (eta*W + (eta*c1 - sqrt(c2))*N) : ((W + c1*N)/sqrt(1.-c1*c1)))
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform vec3 Ambient[ns], Diffuse[ns];
 | 
				
			||||||
 | 
					uniform vec4 Specular[ns];
 | 
				
			||||||
 | 
					uniform float ks[ns], kr[ns], kf[ns];
 | 
				
			||||||
 | 
					uniform vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					uniform vec3 V0;
 | 
				
			||||||
 | 
					uniform int sel;
 | 
				
			||||||
 | 
					const float kf_air = 1.000293;
 | 
				
			||||||
 | 
					varying vec3 trPos;
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********PLEASE DO INCREASE n_ref(RT DEPTH) FOR BETTER RESULTS************/
 | 
				
			||||||
 | 
					/*---->*/const int n_ref=7; //2^n-1 because each hit now spawn at most 2 rays.
 | 
				
			||||||
 | 
					/**BUT BE CAUTIOUS IF YOU DON'T HAVE A DECENT GRAPHICS CARD (below GTX 950M)**/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int max_stack = (n_ref+1)/4;
 | 
				
			||||||
 | 
					vec3 scolor = vec3(0,0,0); 
 | 
				
			||||||
 | 
					struct Ray{
 | 
				
			||||||
 | 
					   vec3 V;
 | 
				
			||||||
 | 
					   vec3 W;
 | 
				
			||||||
 | 
					   float kf, cumulativeK;
 | 
				
			||||||
 | 
					} stack1[max_stack], stack2[max_stack];
 | 
				
			||||||
 | 
					bool modulo2(int n){
 | 
				
			||||||
 | 
					   return n-2*(n/2) == 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					vec2 getTextCoord(vec3 tex_sph, float R){
 | 
				
			||||||
 | 
					   float tex_x=atan(tex_sph.z,tex_sph.x)/_2pi + 0.5;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					   tex_x=fract(tex_x+uTime/20.);
 | 
				
			||||||
 | 
					   return vec2(tex_x,-asin(tex_sph.y/R)/pi + 0.5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					   vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					   float currKf = kf_air;
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=(trPos-V);
 | 
				
			||||||
 | 
					   bool rtxoff = false, showtexture = true, selected = false;
 | 
				
			||||||
 | 
					   float currentK = 1.;
 | 
				
			||||||
 | 
					   int curr_ptr = 0, curr_top = 0, next_top = 0;
 | 
				
			||||||
 | 
					   bool final = false, stackswap = false, stop = false;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      for(int curr = 0; curr < max_stack; ++curr){
 | 
				
			||||||
 | 
					         if(curr == curr_ptr){
 | 
				
			||||||
 | 
					            bool skip = false;
 | 
				
			||||||
 | 
					            if(j > 0){
 | 
				
			||||||
 | 
					               Ray currR;
 | 
				
			||||||
 | 
					               if(stackswap)
 | 
				
			||||||
 | 
					                  currR = stack1[curr];
 | 
				
			||||||
 | 
					               else
 | 
				
			||||||
 | 
					                  currR = stack2[curr];
 | 
				
			||||||
 | 
					               currKf = currR.kf;
 | 
				
			||||||
 | 
					               currentK = currR.cumulativeK;
 | 
				
			||||||
 | 
					               if(currKf <= 0.001 || currentK <= 0.001)
 | 
				
			||||||
 | 
					                  skip = true; 
 | 
				
			||||||
 | 
					               V = currR.V;
 | 
				
			||||||
 | 
					               W = currR.W;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else 
 | 
				
			||||||
 | 
					               W = normalize(W);
 | 
				
			||||||
 | 
					            if(!skip){
 | 
				
			||||||
 | 
					               float tMin=10000.;
 | 
				
			||||||
 | 
					               int iMin = -1;
 | 
				
			||||||
 | 
					               for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					                  vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					                  float B=dot(W,Vp);
 | 
				
			||||||
 | 
					                  float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					                  float D=B*B-C;
 | 
				
			||||||
 | 
					                  if(D>0.){
 | 
				
			||||||
 | 
					                     float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					                     if(t >= 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                        tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					                        iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else if (t >= -0.01 && t <0.01){
 | 
				
			||||||
 | 
					                        t = -(t + 2.*B);
 | 
				
			||||||
 | 
					                        if(t > 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                           tMin = t;
 | 
				
			||||||
 | 
					                           iMin = i;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               if(iMin >= 0){
 | 
				
			||||||
 | 
					                  if(j == 0 && iMin == sel)
 | 
				
			||||||
 | 
					                     selected = true;
 | 
				
			||||||
 | 
					                  float t = tMin;
 | 
				
			||||||
 | 
					                  vec3 S=V+t*W;
 | 
				
			||||||
 | 
					                  for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					                     if(i == iMin)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        vec3 texture_color;
 | 
				
			||||||
 | 
					                        if(showtexture)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                           vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                           texture_color=texture2D(uSampler[i],getTextCoord(tex_sph, Sph[i].w)).xyz;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                        vec3 realLDir=normalize(LDir-S);
 | 
				
			||||||
 | 
					                        float c1 =dot(N, W);
 | 
				
			||||||
 | 
					                        float eta, nextkf;
 | 
				
			||||||
 | 
					                        if(c1<0.){
 | 
				
			||||||
 | 
					                           color=(Ambient[i]+Diffuse[i]*max(0.,dot(N,realLDir))*LCol)*texture_color;
 | 
				
			||||||
 | 
					                           if(rtxoff || final) //if it's the last hit
 | 
				
			||||||
 | 
					                           {
 | 
				
			||||||
 | 
					                              color +=  Specular[i].xyz*pow(max(0.,
 | 
				
			||||||
 | 
					                                 dot(-2.*c1*N-realLDir,realLDir)),Specular[i].w);
 | 
				
			||||||
 | 
					                              scolor += color * currentK;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                           else{
 | 
				
			||||||
 | 
					                              c1 = -c1;
 | 
				
			||||||
 | 
					                              eta = currKf/kf[i];
 | 
				
			||||||
 | 
					                              nextkf = kf[i];
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else{
 | 
				
			||||||
 | 
					                           N = -N;
 | 
				
			||||||
 | 
					                           eta = currKf/kf_air;
 | 
				
			||||||
 | 
					                           nextkf = kf_air;
 | 
				
			||||||
 | 
					                           color = Ambient[i];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        float c2 = (1.-eta*eta*(1.-c1*c1));
 | 
				
			||||||
 | 
					                        float nextks = currentK * ks[i], nextkr = currentK * kr[i];
 | 
				
			||||||
 | 
					                        bool refl = nextks > 0.01, refr = nextkr > 0.01;
 | 
				
			||||||
 | 
					                        if(refl || refr)
 | 
				
			||||||
 | 
					                           for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                              if(k == next_top){
 | 
				
			||||||
 | 
					                                 if(stackswap){
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       stack2[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack2[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack2[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }else{
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    { //remember, c1 = -NW now
 | 
				
			||||||
 | 
					                                       stack1[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack1[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack1[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }
 | 
				
			||||||
 | 
					                                 break;
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                        scolor += color * currentK;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               else {
 | 
				
			||||||
 | 
					                  float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					                  float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  if(t >= 0. && abs(sx) < 1.5 && abs(sz) < 3.)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                     vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					                     vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					                     color=(0.5+0.5*max(0.,realLDir.y)*LCol)*texture2D(uSampler[4],vec2((sx+1.4)/3., (sz+1.5)/4.)).xyz;
 | 
				
			||||||
 | 
					                     if(rtxoff || final&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        color += groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                           pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					                        scolor += currentK * color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                           if(k == next_top){
 | 
				
			||||||
 | 
					                              if(stackswap)
 | 
				
			||||||
 | 
					                                 stack2[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              else
 | 
				
			||||||
 | 
					                                 stack1[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              next_top ++;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        scolor += (currentK*.85)*color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  else{
 | 
				
			||||||
 | 
					                     if(j > 0)
 | 
				
			||||||
 | 
					                        scolor += currentK * (pow(max(0.,dot(W, normalize(LDir - V))), 10.) * vec3(3.,3.,3.) + foregroundColor*0.1);
 | 
				
			||||||
 | 
					                     else scolor = foregroundColor*0.6;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(++curr_ptr >= curr_top){
 | 
				
			||||||
 | 
					               if(next_top <= 0)
 | 
				
			||||||
 | 
					                  stop = true;
 | 
				
			||||||
 | 
					               if(next_top * 2 > max_stack)
 | 
				
			||||||
 | 
					                  final = true;
 | 
				
			||||||
 | 
					               curr_top = next_top;
 | 
				
			||||||
 | 
					               next_top = 0;
 | 
				
			||||||
 | 
					               curr_ptr = 0;
 | 
				
			||||||
 | 
					               stackswap = !stackswap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if(stop)
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(selected)
 | 
				
			||||||
 | 
					      scolor.x += 0.5;
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(scolor),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					attribute vec3 aPos;
 | 
				
			||||||
 | 
					varying   vec3 trPos;
 | 
				
			||||||
 | 
					uniform mat3 transformation; 
 | 
				
			||||||
 | 
					//I used mat3 instead of the augmented mat4 matrix because we 
 | 
				
			||||||
 | 
					//are not doing complex projections yet. I implemented simple 
 | 
				
			||||||
 | 
					//perspective projection back in hw2 by changing focal length 
 | 
				
			||||||
 | 
					//and adjusting the size of the projected surface accrodingly.
 | 
				
			||||||
 | 
					//New surface = distance(surface, old viewpoint)/ distance(surface, new viewpoint) * old surface
 | 
				
			||||||
 | 
					//            = (deltaFl + fl + 1)/(fl + 1) * old surface
 | 
				
			||||||
 | 
					//This is implemented by vPos = (dFl + fl + 1)/(fl + 1) * vPos;
 | 
				
			||||||
 | 
					//Because we will multiply the resulting vPos by the transformation matrix 
 | 
				
			||||||
 | 
					//anyway, I smashed the ratio into the matrix into avoid doing this in shaders.
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    gl_Position = vec4(aPos, 1.);
 | 
				
			||||||
 | 
					    trPos = transformation *vec3(aPos.xy, -1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.7 KiB  | 
@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					<!--<video src="pjsk.mp4" id="pjsk" muted="muted" loop="true" style="position:fixed; left:0; top:0;max-width:100%;min-width:100%;min-height: 100%;z-index: -100;"></video>!-->
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src=lib4.header.js></script>
 | 
				
			||||||
 | 
					<script src=lib4.js></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<font size=7 color=#909090>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Space Walk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img id="rtx" style="float:right;" src="./RTXon.svg" type="image/svg+xml"
 | 
				
			||||||
 | 
					   alt="Turn Ray Tracing On/OFF" title="Turn Ray Tracing On/OFF" height=60px /img>
 | 
				
			||||||
 | 
					<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>
 | 
				
			||||||
 | 
					<TABLE cellspacing=0 cellpadding=0><TR>
 | 
				
			||||||
 | 
					<td><font color=red size=5><div id=errorMessage></div></font></td>
 | 
				
			||||||
 | 
					</TR><TR>
 | 
				
			||||||
 | 
					<table cellspacing=0>
 | 
				
			||||||
 | 
					<tr>
 | 
				
			||||||
 | 
					<td valign=top>
 | 
				
			||||||
 | 
					<div id="ace" style="opacity:90%;width:800px;height:2200px;"></div>
 | 
				
			||||||
 | 
					</td><td valign=top style="background-color:azure;opacity: 95%;">
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					   <center>
 | 
				
			||||||
 | 
					      <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					   <canvas id='canvas1' style=" overflow: hidden !important; width: 600px !important; height:600px !important;" width=599 height=599></canvas>
 | 
				
			||||||
 | 
					   </center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					<div id="controls">
 | 
				
			||||||
 | 
					<input type="number" id="ins" style="margin-left:0px;font-size:24px;width:35px;height:45px" value="5" max="5" min = "1">
 | 
				
			||||||
 | 
					<button id="bns" style="margin-left:0px;font-size:24px;width:105px;height:45px">Spheres</button>
 | 
				
			||||||
 | 
					<input type="number" id="insamp" style="margin-left:2px;font-size:24px;width:60px;height:45px" value="1" max="4" min = "0.25" step="0.2">
 | 
				
			||||||
 | 
					<button id="bnsamp" style="margin-left:0px;font-size:24px;width:190px;height:45px">Super Sampling</button>
 | 
				
			||||||
 | 
					<button id="bnfs" style="margin-left:2px;font-size:24px;width:180px;height:45px">Fullscreen</button>
 | 
				
			||||||
 | 
					<button id="clrsel" style="margin-left:0px;font-size:24px;width:180px;height:45px">Clear Selection</button>
 | 
				
			||||||
 | 
					<button id="reset" style="margin-left:0px;font-size:24px;width:100px;height:45px">Reset</button>
 | 
				
			||||||
 | 
					<button id="mov" style="margin-left:0px;font-size:24px;width:280px;height:45px">Move Lighting & Texture</button>
 | 
				
			||||||
 | 
					<div style='font-size:25px;'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <font color=#909090>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					   <i style="font-size:25px;">What's new: </i>
 | 
				
			||||||
 | 
					   <p style="font-size:20px;"> 
 | 
				
			||||||
 | 
					       I created a little figure that can walk. First, press "Fullscreen" button. In fullscreen mode, <a style="font-size:25px;color:red;"><strong>the figure is able to walk 
 | 
				
			||||||
 | 
					   in four directions when pressing corresponding arrow keys.</strong></a><br>
 | 
				
			||||||
 | 
					        I added normal calculation to every shape I created and then I added phong shading to the scene. <br>
 | 
				
			||||||
 | 
					        As before, you can rotate the scene by dragging on the canvas.<br>
 | 
				
			||||||
 | 
					       I added new shapes such as torus and cubes.</strong><br>
 | 
				
			||||||
 | 
					       <strong>If you found the scene somehow clipped, it seems to be a bug of chromium, please simply click on 'Super Sampling' button
 | 
				
			||||||
 | 
					    or refresh the page. .</strong>
 | 
				
			||||||
 | 
					   </p>
 | 
				
			||||||
 | 
					   <div id="howitworks">
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      <i style="font-size:25px;">How it works:</i><br>
 | 
				
			||||||
 | 
					   <p style="font-size:20px;"> 
 | 
				
			||||||
 | 
					      I used the matrix stack to push and pop transformations to create the figure and move it around. The entire scene is then transformed to apply movements and global rotations.<br>
 | 
				
			||||||
 | 
					      The mesh creation functions and transformation methods are implemented in <a href="./lib4.header.js">lib4.header.js</a><br>
 | 
				
			||||||
 | 
					      Animating function and  are in <a href="./lib4.ext.js">lib4.ext.js</a><br>
 | 
				
			||||||
 | 
					      <a href="./shader.vert">shader.vert</a> is the vertex shader.<br>
 | 
				
			||||||
 | 
					      <a href="./lib4.js">lib4.js</a> most contains initialization methods for the renderer. You can also see how I passes more attributes like surface normal and 
 | 
				
			||||||
 | 
					      object id to the shaders.<br>
 | 
				
			||||||
 | 
					      <a href="./index.html">index.html</a> is almost pure html.<br>
 | 
				
			||||||
 | 
					   </p>
 | 
				
			||||||
 | 
					   </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <p>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div></td>
 | 
				
			||||||
 | 
					</tr></table>
 | 
				
			||||||
 | 
					</TR></TABLE>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script src="lib4.ext.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					   setInterval(() => {
 | 
				
			||||||
 | 
					      if(window.vs != null && window.fs != null&& canvas1.setShaders === undefined)
 | 
				
			||||||
 | 
					         gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					   }, 200);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -0,0 +1,593 @@
 | 
				
			|||||||
 | 
					let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
 | 
				
			||||||
 | 
					let lastClick = undefined;
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					var startTime = Date.now();
 | 
				
			||||||
 | 
					let lastTime = Date.now();
 | 
				
			||||||
 | 
					var lastFrameTime = 0;
 | 
				
			||||||
 | 
					let oldDocument;
 | 
				
			||||||
 | 
					let fullscreen = false, btntoggled = false;
 | 
				
			||||||
 | 
					let movescene = true;
 | 
				
			||||||
 | 
					let oldparents = {};
 | 
				
			||||||
 | 
					var tr, div;
 | 
				
			||||||
 | 
					let canvas_originalsize;
 | 
				
			||||||
 | 
					let Sph = [];
 | 
				
			||||||
 | 
					let SphTr = [];
 | 
				
			||||||
 | 
					let SphDletaR = []
 | 
				
			||||||
 | 
					let selected = false, selection = -1, dragging = false;
 | 
				
			||||||
 | 
					let overall_trans = matrix_identity();
 | 
				
			||||||
 | 
					let rebuild = true, presentation = true, sRotation = matrix_identity();
 | 
				
			||||||
 | 
					let facing = 1, running = 0;
 | 
				
			||||||
 | 
					for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					   SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function toggleFullscreen(element){
 | 
				
			||||||
 | 
					   if(fullscreen)
 | 
				
			||||||
 | 
					   { 
 | 
				
			||||||
 | 
					      if (document.exitFullscreen) 
 | 
				
			||||||
 | 
					         document.exitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.webkitExitFullscreen) 
 | 
				
			||||||
 | 
					         document.webkitExitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.mozCancelFullScreen) 
 | 
				
			||||||
 | 
					         document.mozCancelFullScreen();
 | 
				
			||||||
 | 
					      else if (document.msExitFullscreen) 
 | 
				
			||||||
 | 
					         document.msExitFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = false;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      if(element.requestFullscreen)
 | 
				
			||||||
 | 
					         element.requestFullscreen();
 | 
				
			||||||
 | 
					      else if (element.webkitRequestFullscreen)
 | 
				
			||||||
 | 
					         element.webkitRequestFullscreen();
 | 
				
			||||||
 | 
					      else if(element.msRequestFullscreen)
 | 
				
			||||||
 | 
					         element.msRequestFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = true;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Exit Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnfs.onclick = function(e){
 | 
				
			||||||
 | 
					   if(e === "no")
 | 
				
			||||||
 | 
					      ;
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      btntoggled = true;
 | 
				
			||||||
 | 
					   if(fullscreen){
 | 
				
			||||||
 | 
					      oldparents[controls].appendChild(controls);
 | 
				
			||||||
 | 
					      oldparents[canvas1].appendChild(canvas1);
 | 
				
			||||||
 | 
					      canvas1.style.width = canvas_originalsize[0];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas_originalsize[1];
 | 
				
			||||||
 | 
					      howitworks.hidden = false;
 | 
				
			||||||
 | 
					   }else{
 | 
				
			||||||
 | 
					      div = document.createElement("div");
 | 
				
			||||||
 | 
					      tr = document.createElement("table").insertRow();
 | 
				
			||||||
 | 
					      tr.style.backgroundColor="white";
 | 
				
			||||||
 | 
					      let size = Math.min(screen.availHeight, screen.availWidth);
 | 
				
			||||||
 | 
					      canvas_originalsize = [canvas1.style.width, canvas1.style.height, canvas1.width, canvas1.height];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas1.style.width = size;
 | 
				
			||||||
 | 
					      howitworks.hidden=true;
 | 
				
			||||||
 | 
					      oldparents[controls] = controls.parentNode;
 | 
				
			||||||
 | 
					      oldparents[canvas1] = canvas1.parentNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let td1 = tr.insertCell();
 | 
				
			||||||
 | 
					      td1.appendChild(canvas1);
 | 
				
			||||||
 | 
					      let td2;
 | 
				
			||||||
 | 
					      td2 = tr.insertCell();
 | 
				
			||||||
 | 
					      td2.style.verticalAlign="top";
 | 
				
			||||||
 | 
					      td2.appendChild(controls);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      div.appendChild(tr);
 | 
				
			||||||
 | 
					      document.body.appendChild(div);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   toggleFullscreen(div);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					mov.onclick=function(_){
 | 
				
			||||||
 | 
					   movescene = !movescene;
 | 
				
			||||||
 | 
					   if(!movescene)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mov.innerText= "Move Scene";
 | 
				
			||||||
 | 
					      mov.style.width = "170px";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mov.innerText = "Move Lighting&Texture";
 | 
				
			||||||
 | 
					      mov.style.width = "280px";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					document.addEventListener("webkitfullscreenchange", ()=>{if(!btntoggled && fullscreen)bnfs.onclick("no");btntoggled = false;});
 | 
				
			||||||
 | 
					document.addEventListener("fullscreenchange", ()=>{if(!btntoggled && fullscreen)bnfs.onclick("no");btntoggled = false;});
 | 
				
			||||||
 | 
					clrsel.onclick=function(_){
 | 
				
			||||||
 | 
					   setUniform("1i", "sel", -1);
 | 
				
			||||||
 | 
					   selected = false;
 | 
				
			||||||
 | 
					   selection = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					reset.onclick = function(_){
 | 
				
			||||||
 | 
					   clrsel.onclick();
 | 
				
			||||||
 | 
					   if(!animating)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   flags = 0;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   mousedx = mousedy = mousedz = 0;
 | 
				
			||||||
 | 
					   positionsupdated = true;
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					      SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bns.onclick=function(e){
 | 
				
			||||||
 | 
					   if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
 | 
				
			||||||
 | 
					   {   
 | 
				
			||||||
 | 
					      cns = ins.value;
 | 
				
			||||||
 | 
					      fragmentShaderDefs = '\n const int cns = ' + cns + ';';
 | 
				
			||||||
 | 
					      if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnsamp.onclick=function(e){
 | 
				
			||||||
 | 
					   let multiplier  = insamp.value;
 | 
				
			||||||
 | 
					   let w = parseInt(canvas1.style.width)*multiplier;
 | 
				
			||||||
 | 
					   let h = parseInt(canvas1.style.height)*multiplier;
 | 
				
			||||||
 | 
					   canvas1.height = h;
 | 
				
			||||||
 | 
					   canvas1.width = w;
 | 
				
			||||||
 | 
					   gl.viewport(0, 0, w, h);
 | 
				
			||||||
 | 
					   //gl.clearRect(0, 0, w, h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					if(fs != undefined)
 | 
				
			||||||
 | 
					    editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					   if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					delete editor.KeyBinding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let pause_resume = function(){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      lastTime = Date.now();
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					   animating = !animating;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(!(shift && alt) && lastClick&& Date.now()-lastClick<400)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   lastClick = Date.now();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseover', function(e){
 | 
				
			||||||
 | 
					   over = true;
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags |= mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousedown', function(e){
 | 
				
			||||||
 | 
					      moving = true
 | 
				
			||||||
 | 
					      mouselastX = mouselastY =  undefined;
 | 
				
			||||||
 | 
					      let i = hitTest([2*e.offsetX/ parseInt(canvas1.style.width)-1, 
 | 
				
			||||||
 | 
					         1-2*e.offsetY/ parseInt(canvas1.style.height), -1]);
 | 
				
			||||||
 | 
					      if(i >= 0)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         dragging = true;
 | 
				
			||||||
 | 
					         selected = true;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else if(selected = true){
 | 
				
			||||||
 | 
					         dragging = false;
 | 
				
			||||||
 | 
					         selected = false;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousemove', function(e){
 | 
				
			||||||
 | 
					      if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
 | 
				
			||||||
 | 
					         let dx = (mouselastX - e.offsetX), 
 | 
				
			||||||
 | 
					             dy = (mouselastY - e.offsetY);
 | 
				
			||||||
 | 
					         if(movescene){
 | 
				
			||||||
 | 
					            sRotation = matrix_multiply(sRotation, matrix_rotateY(-dy/60));
 | 
				
			||||||
 | 
					            sRotation = matrix_multiply(sRotation, matrix_rotateX(-dx/60)); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         } 
 | 
				
			||||||
 | 
					         else if(!selected)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					               mousedx -= dx/60;
 | 
				
			||||||
 | 
					               mousedy -= dy/60;
 | 
				
			||||||
 | 
					               positionsupdated = true;
 | 
				
			||||||
 | 
					         }else if(dragging){
 | 
				
			||||||
 | 
					               let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					               m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					               let dv = matrix_multiply(m, [2*-dx/ parseInt(canvas1.style.width), 
 | 
				
			||||||
 | 
					                  2*dy/ parseInt(canvas1.style.height), 0, 1]).slice(0,3);
 | 
				
			||||||
 | 
					               SphTr[selection] = matrix_multiply(SphTr[selection], matrix_translate(dv[0], dv[1], dv[2]));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mouselastX = e.offsetX;
 | 
				
			||||||
 | 
					      mouselastY = e.offsetY;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseup', function(e){
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   dragging = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseout', function(e){
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags &= !mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   over = false;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('wheel', function(e){
 | 
				
			||||||
 | 
					   if(!selected){
 | 
				
			||||||
 | 
					      mousedz += e.wheelDelta/600;
 | 
				
			||||||
 | 
					      positionsupdated = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      SphDletaR[selection] += e.wheelDelta / 800;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.scroll(function(e) {e.stopPropagation();});
 | 
				
			||||||
 | 
					rtx.style.cursor="pointer";
 | 
				
			||||||
 | 
					let rtswitch = function(){
 | 
				
			||||||
 | 
					   alert('Ray Tracing is always on. See hw2 where rt can be toggled on/off.')
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					rtx.addEventListener('click', rtswitch);
 | 
				
			||||||
 | 
					var requestAnimationFrame = window.requestAnimationFrame ||
 | 
				
			||||||
 | 
					 window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 | 
				
			||||||
 | 
					let fpscounter = function(time){
 | 
				
			||||||
 | 
					      if (start === undefined)
 | 
				
			||||||
 | 
					         start = time;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
 | 
				
			||||||
 | 
					      start = time;
 | 
				
			||||||
 | 
					      if(fpson)
 | 
				
			||||||
 | 
					         ;//requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         start = undefined;
 | 
				
			||||||
 | 
					         fps.innerHTML = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = true;
 | 
				
			||||||
 | 
					   else if(ctrl && alt && e.code == 'KeyT'){
 | 
				
			||||||
 | 
					      const mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)?mask:0);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (ctrl &&e.code == 'KeyS'){
 | 
				
			||||||
 | 
					      let a = document.createElement('a');
 | 
				
			||||||
 | 
					      a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
 | 
				
			||||||
 | 
					      a.download = 'shader.frag';
 | 
				
			||||||
 | 
					      a.click();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyR')
 | 
				
			||||||
 | 
					      rtswitch();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyN')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      reset.onclick();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyP')
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyF')
 | 
				
			||||||
 | 
					      if(!fpson)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         fpson = true;
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fpson = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(e.code == 'ArrowUp' || e.code == 'ArrowDown' || e.code =='ArrowLeft'
 | 
				
			||||||
 | 
					      ||e.code == 'ArrowRight' || e.code =='KeyW'||e.code =='KeyS')
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         switch(e.code){
 | 
				
			||||||
 | 
					         case 'ArrowUp':
 | 
				
			||||||
 | 
					            facing = -2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowDown':
 | 
				
			||||||
 | 
					            facing = 2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowLeft':
 | 
				
			||||||
 | 
					            facing = -1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowRight':
 | 
				
			||||||
 | 
					            facing = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'KeyW':
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'KeyS':
 | 
				
			||||||
 | 
					            break;  
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      running = 20;
 | 
				
			||||||
 | 
					      rebuild = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(fullscreen && selected ){
 | 
				
			||||||
 | 
					      if(e.code =='KeyF'||e.code =='KeyB'){
 | 
				
			||||||
 | 
					            let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					            m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					            m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch(e.code){   
 | 
				
			||||||
 | 
					               case 'KeyB':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, -0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					               case 'KeyF':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, 0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;                
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            SphTr[selection] = matrix_multiply(SphTr[selection], m);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					let squareMesh = new Float32Array([ -1,-1,1,0,0,0,0,0,-1, 1,1,0,0,0,0,0,-1, -1,-1,0,0,0,0,0, -1,1,-1,0 ,0,0,0,0]);
 | 
				
			||||||
 | 
					let sphereMesh   = createMesh(32, 32, uvToSphere);
 | 
				
			||||||
 | 
					let tubeMesh     = createMesh(32, 2, uvToTube,0,1);
 | 
				
			||||||
 | 
					let diskMesh     = createMesh(32, 2, uvToDisk,0,1);
 | 
				
			||||||
 | 
					let tubeMesh2     = createMesh(32, 2, uvToTube,0,2);
 | 
				
			||||||
 | 
					let diskNMesh2    = createMesh(32, 2, uvToDisk, -1,2);
 | 
				
			||||||
 | 
					let diskPMesh2    = createMesh(32, 2, uvToDisk,  1,2);
 | 
				
			||||||
 | 
					let tubeMesh3     = createMesh(32, 2, uvToTube,0,3);
 | 
				
			||||||
 | 
					let diskNMesh3    = createMesh(32, 2, uvToDisk, -1,3);
 | 
				
			||||||
 | 
					let diskPMesh3    = createMesh(32, 2, uvToDisk,  1,3);
 | 
				
			||||||
 | 
					let diskNMesh    = createMesh(32, 2, uvToDisk, -1,1);
 | 
				
			||||||
 | 
					let diskPMesh    = createMesh(32, 2, uvToDisk,  1,1);
 | 
				
			||||||
 | 
					let cylinderMesh = glueMeshes(glueMeshes(tubeMesh, diskPMesh), diskNMesh);
 | 
				
			||||||
 | 
					let cylinderMesh2 = glueMeshes(glueMeshes(tubeMesh2, diskPMesh2), diskNMesh2);
 | 
				
			||||||
 | 
					let cylinderMesh3 = glueMeshes(glueMeshes(tubeMesh3, diskPMesh3), diskNMesh3);
 | 
				
			||||||
 | 
					let torusMash    = createMesh(32, 32, uvToTorus, 1, 5);
 | 
				
			||||||
 | 
					let head = createCube(1.5,1,1, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let objects = [];
 | 
				
			||||||
 | 
					let addObject = (obj, mat) => {
 | 
				
			||||||
 | 
					   objects.push([obj, mat]);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					let clearObject = () => {delete objects; objects = [];};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let delta_height = 0, delta_l = [0,0];
 | 
				
			||||||
 | 
					class State{
 | 
				
			||||||
 | 
					   constructor() {
 | 
				
			||||||
 | 
					      this.leg = true;
 | 
				
			||||||
 | 
					      this.progress = 0;
 | 
				
			||||||
 | 
					      this.rh = this.lh = .5*pi;
 | 
				
			||||||
 | 
					      this.lf = this.rf = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   initialize(){
 | 
				
			||||||
 | 
					      this.leg = true;
 | 
				
			||||||
 | 
					      this.progress = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   next(){
 | 
				
			||||||
 | 
					      //return this.presentation();
 | 
				
			||||||
 | 
					      if(running <= 0)
 | 
				
			||||||
 | 
					         return {rh:.5*pi, lh:.5*pi, rf:0, lf:0, dh:0,dl:0}
 | 
				
			||||||
 | 
					      running --;
 | 
				
			||||||
 | 
					      const steps = 100;
 | 
				
			||||||
 | 
					      let dl = 0;
 | 
				
			||||||
 | 
					      if(this.progress >= steps/2)
 | 
				
			||||||
 | 
					      { 
 | 
				
			||||||
 | 
					         this.progress = 0;
 | 
				
			||||||
 | 
					         this.leg = !this.leg;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let delta = [-pi/5, 0.5*pi, 0.44*pi, 0.55*pi];
 | 
				
			||||||
 | 
					      for (let i = 0; i < 4; ++i) delta[i] /= steps;
 | 
				
			||||||
 | 
					      if(this.leg)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         if(this.progress < steps/4)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            this.lh += delta[0];
 | 
				
			||||||
 | 
					            this.rh += delta[3];
 | 
				
			||||||
 | 
					            this.lf += delta[1];
 | 
				
			||||||
 | 
					            this.rf += delta[2];
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            this.lh -= delta[0];
 | 
				
			||||||
 | 
					            this.rh -= delta[3];
 | 
				
			||||||
 | 
					            this.lf -= delta[1];
 | 
				
			||||||
 | 
					            this.rf-= delta[2];  
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         if(this.progress < steps/4)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            this.lh += delta[3];
 | 
				
			||||||
 | 
					            this.rh += delta[0];
 | 
				
			||||||
 | 
					            this.lf += delta[2];
 | 
				
			||||||
 | 
					            this.rf += delta[1];
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            this.lh -= delta[3];
 | 
				
			||||||
 | 
					            this.rh -= delta[0];
 | 
				
			||||||
 | 
					            this.lf -= delta[2];
 | 
				
			||||||
 | 
					            this.rf-= delta[1];  
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let delta_h = Math.max((1-cos(abs(this.lh - pi/2)))*.5+(1-cos(abs(this.lf)))*.6,(1-cos(abs(this.rh - pi/2)))*.5+(1-cos(abs(this.rf)))*.6);
 | 
				
			||||||
 | 
					      this.progress++;  
 | 
				
			||||||
 | 
					      return  {lh:this.lh, lf:this.lf, rh:this.rh,rf:this.rf, dh:delta_h, dl:1.8522/steps};
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   // presentation(){
 | 
				
			||||||
 | 
					   //    return {lh:.4*pi, lf:pi/6,rh:.7*pi, rf:pi/8, dh:0};
 | 
				
			||||||
 | 
					   // }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					let build_objects = (state)=>{
 | 
				
			||||||
 | 
					   if(running === 0)
 | 
				
			||||||
 | 
					      rebuild = false;
 | 
				
			||||||
 | 
					   let {lh, lf, rh, rf, dh, dl} = state.next();
 | 
				
			||||||
 | 
					   delta_l[abs(facing)-1] += 0.3* Math.sign(facing) * dl;
 | 
				
			||||||
 | 
					   delta_height = dh;
 | 
				
			||||||
 | 
					   clearObject();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.rotateX(pi/2);
 | 
				
			||||||
 | 
					         M.scale(0.5, 0.5, 1);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0,1,0);
 | 
				
			||||||
 | 
					         addObject(head, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0.5, 0.2, 0.3);
 | 
				
			||||||
 | 
					         M.rotateX(pi/4);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.4);
 | 
				
			||||||
 | 
					            M.rotateX(-0.53*pi);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.4);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-0.5, 0.2, 0.3);
 | 
				
			||||||
 | 
					         M.rotateX(pi/4);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.4);
 | 
				
			||||||
 | 
					            M.rotateX(-0.55*pi);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.4);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					      M.restore();      
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0.3, -1, 0.);
 | 
				
			||||||
 | 
					         M.rotateX(lh);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.45);
 | 
				
			||||||
 | 
					            M.rotateX(lf);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.6);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-0.3, -1, 0.);
 | 
				
			||||||
 | 
					         M.rotateX(rh);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.45);
 | 
				
			||||||
 | 
					            M.rotateX(rf);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.6);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   //rebuild = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					let state = new State();
 | 
				
			||||||
 | 
					var M = new Matrix();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   let uTime;
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (Date.now() - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (lastTime - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   Sph[0] = [0,0.05*Math.cos(uTime + 1.),.045*Math.cos(uTime), 1,.15];
 | 
				
			||||||
 | 
					   Sph[1] = [0,0,0,1,.25];
 | 
				
			||||||
 | 
					   Sph[2] = [.22*Math.sin(uTime*1.2),0.05,.22*Math.cos(uTime*1.2),1,.05];
 | 
				
			||||||
 | 
					   Sph[3] = [.9*Math.sin(uTime*.4),0.,.9*Math.cos(uTime*.4),1,.25];
 | 
				
			||||||
 | 
					   Sph[4] = [0.5*Math.sin(uTime*1.),0.08*Math.sin(uTime *0.9),.5*Math.cos(uTime*1.),1,.12];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++ i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let trsph = matrix_multiply(SphTr[i], Sph[i]);
 | 
				
			||||||
 | 
					      trsph[3] = Sph[i][4];
 | 
				
			||||||
 | 
					      setUniform('4fv', 'Sph['+ i + ']', trsph);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(presentation){
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.scale(0.3);
 | 
				
			||||||
 | 
					         M.rotateY(uTime/5);
 | 
				
			||||||
 | 
					         M.rotateX(1);
 | 
				
			||||||
 | 
					         M.translate(delta_l[0], -delta_height, delta_l[1]);
 | 
				
			||||||
 | 
					         if(facing !=2)
 | 
				
			||||||
 | 
					            M.rotateY(pi*(facing/2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         //M.translate(0, -delta_height, 0);
 | 
				
			||||||
 | 
					         overall_trans = M.value();
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   }else{
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					        // M.rotateY(2);
 | 
				
			||||||
 | 
					         M.rotateX(1);
 | 
				
			||||||
 | 
					         M.scale(0.3);
 | 
				
			||||||
 | 
					         M.translate(delta_l[0], -delta_height, delta_l[1]);
 | 
				
			||||||
 | 
					         overall_trans = M.value();
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(rebuild)
 | 
				
			||||||
 | 
					      build_objects(state);
 | 
				
			||||||
 | 
					   for(const [obj, mat] of objects){
 | 
				
			||||||
 | 
					      drawMesh(obj, matrix_multiply(sRotation,matrix_multiply(overall_trans, mat)));
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					      M.scale(0.1);
 | 
				
			||||||
 | 
					      M.translate(6,0,1);
 | 
				
			||||||
 | 
					      M.rotateX(1);
 | 
				
			||||||
 | 
					      M.rotateY(uTime/4);
 | 
				
			||||||
 | 
					      drawMesh(torusMash, M.value());
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   if(positionsupdated)
 | 
				
			||||||
 | 
					      updatePositions();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					//pjsk.play();
 | 
				
			||||||
@ -0,0 +1,332 @@
 | 
				
			|||||||
 | 
					//Header file, contains global variable definitions, 
 | 
				
			||||||
 | 
					// asynchronized shader loading and utility functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mousedx = 0, mousedy = 0, mousedz = 0;
 | 
				
			||||||
 | 
					let seldx = 0, seldy = 0, seldz = 0;
 | 
				
			||||||
 | 
					var enableSelection = false;
 | 
				
			||||||
 | 
					var cx = 1, cy = 1, sx = 0, sy = 0;
 | 
				
			||||||
 | 
					var mouselastX, mouselastY;
 | 
				
			||||||
 | 
					const fl = 3;
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					var vs, fs;
 | 
				
			||||||
 | 
					var vsfetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					var editor = undefined
 | 
				
			||||||
 | 
					var cos = Math.cos, sin = Math.sin, tan = Math.tan,
 | 
				
			||||||
 | 
					    acos = Math.acos, asin = Math.asin, atan = Math.atan,
 | 
				
			||||||
 | 
					    sqrt = Math.sqrt, pi = Math.PI, abs = Math.abs;
 | 
				
			||||||
 | 
					var positionsupdated = true;
 | 
				
			||||||
 | 
					vsfetch.open('GET', './shader.vert');
 | 
				
			||||||
 | 
					vsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    vs = vsfetch.responseText;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					vsfetch.send();
 | 
				
			||||||
 | 
					//* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					var client = new XMLHttpRequest();
 | 
				
			||||||
 | 
					client.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					client.onloadend = function () {
 | 
				
			||||||
 | 
					    fs = (client.responseText);
 | 
				
			||||||
 | 
					    //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					    if (editor != undefined)
 | 
				
			||||||
 | 
					        editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					client.send();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// I HAVE IMPLEMENTED THESE FUNCTIONS FOR YOU
 | 
				
			||||||
 | 
					let matrix_identity = () => {
 | 
				
			||||||
 | 
					    return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_translate = (x, y, z) => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[12] = x;
 | 
				
			||||||
 | 
					    m[13] = y;
 | 
				
			||||||
 | 
					    m[14] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// YOU NEED TO PROPERLY IMPLEMENT THE FOLLOWING FIVE FUNCTIONS:
 | 
				
			||||||
 | 
					let matrix_rotateX = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    m[6] = sin(theta);
 | 
				
			||||||
 | 
					    m[9] = -sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let matrix_rotateY = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[2] = -sin(theta);
 | 
				
			||||||
 | 
					    m[8] = sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_rotateZ= theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[1] = sin(theta);
 | 
				
			||||||
 | 
					    m[4] = -sin(theta);
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_scale = (x, y, z) => {
 | 
				
			||||||
 | 
					    if (y === undefined)
 | 
				
			||||||
 | 
					        y = z = x;
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = x;
 | 
				
			||||||
 | 
					    m[5] = y;
 | 
				
			||||||
 | 
					    m[10] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_multiply = (a, b, m = 4, n = 4) => { //dim=mn*nm=mm
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    if (b.length < m*n) { //mat-vec multiply (i did this for my convenience)
 | 
				
			||||||
 | 
					        for (let i = 0; i < m; ++i) {
 | 
				
			||||||
 | 
					            res[i] = 0;
 | 
				
			||||||
 | 
					            for (let j = 0; j < n; ++j)
 | 
				
			||||||
 | 
					                res[i] += b[j] * a[m * j + i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    } //otherwise mm multiply
 | 
				
			||||||
 | 
					    for (let i = 0; i < m; ++i)
 | 
				
			||||||
 | 
					        for (let j = 0; j < m; ++j) {
 | 
				
			||||||
 | 
					            var t = 0;
 | 
				
			||||||
 | 
					            for (let k = 0; k < n; ++k)
 | 
				
			||||||
 | 
					                t += a[k * m + j] * b[i * n + k];
 | 
				
			||||||
 | 
					            res.push(t);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let const_multiply = (c, a) => {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++ i)
 | 
				
			||||||
 | 
					        m[i] = a[i] * c;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function dot(a, b){
 | 
				
			||||||
 | 
					    let m = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m += a[i] * b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function plus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] + b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function minus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] - b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function normalize(v){
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    sum = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        sum += v[i] * v[i];
 | 
				
			||||||
 | 
					    sum = sqrt(sum);
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        res[i] = v[i] / sum;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let Matrix = function() {
 | 
				
			||||||
 | 
					    let top = 0, m = [ matrix_identity() ];
 | 
				
			||||||
 | 
					    this.identity = () => m[top] = matrix_identity();
 | 
				
			||||||
 | 
					    this.translate = (x,y,z) => m[top] = matrix_multiply(m[top], matrix_translate(x,y,z));
 | 
				
			||||||
 | 
					    this.rotateX = theta     => m[top] = matrix_multiply(m[top], matrix_rotateX(theta));
 | 
				
			||||||
 | 
					    this.rotateY = theta     => m[top] = matrix_multiply(m[top], matrix_rotateY(theta));
 | 
				
			||||||
 | 
					    this.rotateZ = theta     => m[top] = matrix_multiply(m[top], matrix_rotateZ(theta));
 | 
				
			||||||
 | 
					    this.scale   = (x,y,z)   => m[top] = matrix_multiply(m[top], matrix_scale(x,y,z));
 | 
				
			||||||
 | 
					    this.value   = ()        => m[top];
 | 
				
			||||||
 | 
					    this.save    = ()        => { m[top+1] = m[top].slice(); top++; }
 | 
				
			||||||
 | 
					    this.restore = ()        => --top;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 //------ CREATING MESH SHAPES
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 // CREATE A MESH FROM A PARAMETRIC FUNCTION
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let createMesh = (nu, nv, f, data, oid = 0) => {
 | 
				
			||||||
 | 
					    let tmp = [];
 | 
				
			||||||
 | 
					    for (let v = 0 ; v < 1 ; v += 1/nv) {
 | 
				
			||||||
 | 
					       for (let u = 0 ; u <= 1 ; u += 1/nu) {
 | 
				
			||||||
 | 
					          tmp = tmp.concat(f(u,v,oid,data));
 | 
				
			||||||
 | 
					          tmp = tmp.concat(f(u,v+1/nv,oid,data));
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       tmp = tmp.concat(f(1,v,oid,data));
 | 
				
			||||||
 | 
					       tmp = tmp.concat(f(0,v+1/nv,oid,data));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new Float32Array(tmp);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 // GLUE TWO MESHES TOGETHER INTO A SINGLE MESH
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let glueMeshes = (a, b) => {
 | 
				
			||||||
 | 
					    let c = [];
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < a.length ; i++)
 | 
				
			||||||
 | 
					       c.push(a[i]);                           // a
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					       c.push(a[a.length - VERTEX_SIZE + i]);  // + last vertex of a
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					       c.push(b[i]);                           // + first vertex of b
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < b.length ; i++)
 | 
				
			||||||
 | 
					       c.push(b[i]);                           // + b
 | 
				
			||||||
 | 
					    return new Float32Array(c);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToSphere = (u,v, i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let phi   = Math.PI * (v - .5);
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let z = Math.sin(phi);
 | 
				
			||||||
 | 
					    return [i, x,y,z].concat(normalize([x, y, z]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToTube = (u,v,i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta);
 | 
				
			||||||
 | 
					    let z = 2 * v - 1;
 | 
				
			||||||
 | 
					    return [i,x,y,z].concat(normalize([x,y,0]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToDisk = (u,v,i,dz) => {
 | 
				
			||||||
 | 
					    if (dz === undefined)
 | 
				
			||||||
 | 
					       dz = 0;
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * v;
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * v;
 | 
				
			||||||
 | 
					    let z = dz;
 | 
				
			||||||
 | 
					    return [i,x,y,z].concat([0,0,Math.sign(z)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 let uvToTorus = (u,v,i,r) => {
 | 
				
			||||||
 | 
					    let theta = 2 * pi;
 | 
				
			||||||
 | 
					    let phi = theta * v;
 | 
				
			||||||
 | 
					    theta *= u;
 | 
				
			||||||
 | 
					    let x = 1 + r * cos(phi);
 | 
				
			||||||
 | 
					    let y = sin(theta)*x;
 | 
				
			||||||
 | 
					    x *=cos(theta);
 | 
				
			||||||
 | 
					    let z = r * sin(phi);
 | 
				
			||||||
 | 
					    let tx = -sin(theta), ty = cos(theta),tsx = sin(phi), tsy = tsx*tx, tsz = cos(phi);
 | 
				
			||||||
 | 
					    tsx*=-ty;
 | 
				
			||||||
 | 
					    return [i,x, y, z].concat(normalize([ty*tsz*0.5, -tx*tsz, tx*tsy-ty*tsx]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createCube = (w, h, l,id) => {
 | 
				
			||||||
 | 
					    let mesh = [];
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,0,1,0]);
 | 
				
			||||||
 | 
					    return new Float32Array(mesh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let verts = [];
 | 
				
			||||||
 | 
					    // for(let i = -w/2; i < w; i += w)
 | 
				
			||||||
 | 
					    //     for(let j = -h/2; j < h; j += h)
 | 
				
			||||||
 | 
					    //         for (let k = -l/2; k < l; k += l)
 | 
				
			||||||
 | 
					    //             verts.push([id, i, j, k]);
 | 
				
			||||||
 | 
					    // let mesh = [];
 | 
				
			||||||
 | 
					    // let n = 0;
 | 
				
			||||||
 | 
					    // for(let j = 0; j < 4; ++ j)
 | 
				
			||||||
 | 
					    //     mesh = mesh.concat(verts[j]);
 | 
				
			||||||
 | 
					    // for(let i = 0; i < 2; ++ i)
 | 
				
			||||||
 | 
					    //     for(let j = 0; j < 2; ++ j)
 | 
				
			||||||
 | 
					    //         mesh = mesh.concat(verts[6 - i*2 + j]);
 | 
				
			||||||
 | 
					    // for(let j = 0; j < 2; ++ j)
 | 
				
			||||||
 | 
					    //     mesh = mesh.concat(verts[j]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[5]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[3]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[7]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[7]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[6]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[6]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[4]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[2]);
 | 
				
			||||||
 | 
					    // mesh = mesh.concat(verts[0]);
 | 
				
			||||||
 | 
					    // return new Float32Array(mesh); 
 | 
				
			||||||
 | 
					    //CREATING CUBES THIS WAY REDUCES VERTICES BUT MAKES IT HARDER TO DO LIGHTING
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					function updatePositions() {
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    setUniform('3f', 'V0', m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz));
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    setUniform('Matrix3fv', 'transformation', false, [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]);
 | 
				
			||||||
 | 
					    positionsupdated = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest(pos){
 | 
				
			||||||
 | 
					    if(!enableSelection)
 | 
				
			||||||
 | 
					        return -1; 
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    let V = [m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz)];
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    let trPos = matrix_multiply([m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]], pos, 3,3);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    let W=normalize(minus(trPos, V));
 | 
				
			||||||
 | 
					    let tMin=10000.;
 | 
				
			||||||
 | 
					    let iMin = -1;
 | 
				
			||||||
 | 
					    for(let i=0;i<cns;i++){
 | 
				
			||||||
 | 
					    let Vp=minus(V, matrix_multiply(SphTr[i], Sph[i]));
 | 
				
			||||||
 | 
					    let B=dot(W,Vp);
 | 
				
			||||||
 | 
					    let C=dot(Vp,Vp)-Sph[i][4]*Sph[i][4];
 | 
				
			||||||
 | 
					    let D=B*B-C;
 | 
				
			||||||
 | 
					    if(D>0.){
 | 
				
			||||||
 | 
					       let t=-B-sqrt(D);
 | 
				
			||||||
 | 
					       if(t > 0.0 && t < tMin){
 | 
				
			||||||
 | 
					          tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					          iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return iMin;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
@ -0,0 +1,211 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					var ns = 5, cns = 5;
 | 
				
			||||||
 | 
					fragmentShaderHeader+= 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					var fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;   
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					     bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   } 
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let texture = [], gl, program;
 | 
				
			||||||
 | 
					let textures = []; 
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					   console.log('glstart');
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = 'Build Your Own Universe!';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader +fragmentShaderDefs+ fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; ++i){
 | 
				
			||||||
 | 
					            loadTexture(gl, './'+(i+1)+'.jpg', i); //Texture loading.
 | 
				
			||||||
 | 
					            textures[i] = i;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
 | 
				
			||||||
 | 
					         positionsupdated = true;
 | 
				
			||||||
 | 
					         let attribs = [
 | 
				
			||||||
 | 
					            .05,.05,.1,  .5,.5,1.,  1.,.5,.5,20.,  0., .0, 1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  1.,.5,.5,  1.,.5,.5,10.,  .3,1.,1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  .71,.71,.71,  .71,.71,.71,10.,  0.3,.0,1.5,
 | 
				
			||||||
 | 
					            .1,.1,.1,  .71,.71,.71,  .71,.71,.71,10.,  0.05,0., 1.,
 | 
				
			||||||
 | 
					            .0,.0,.0,  .0,.0,.0,  .0,.0,.0,40.,  0.,.85,1.5
 | 
				
			||||||
 | 
					         ]
 | 
				
			||||||
 | 
					         var offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Ambient['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Diffuse['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('4fv', 'Specular['+i+']', attribs.slice(offset, offset += 4));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'ks['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kr['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kf['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         // gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					         //    [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					         gl.enable(gl.DEPTH_TEST);
 | 
				
			||||||
 | 
					         gl.depthFunc(gl.LEQUAL);
 | 
				
			||||||
 | 
					         gl.clearDepth(-1);
 | 
				
			||||||
 | 
					         let oid = gl.getAttribLocation(program, 'oid');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(oid);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(oid, 1, gl.FLOAT, false, 4*7, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 4*7, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let normal = gl.getAttribLocation(program, 'normal');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(normal);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(normal, 3, gl.FLOAT, false, 4*7, 4*4);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         //gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   if(gl)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					      (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//let VERTEX_SIZE = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let VERTEX_SIZE = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let drawMesh = (mesh, m) => {
 | 
				
			||||||
 | 
					   setUniform('Matrix4fv', 'uMatrix', false, m);
 | 
				
			||||||
 | 
					   gl.bufferData(gl.ARRAY_BUFFER, mesh, gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					   gl.drawArrays(gl.TRIANGLE_STRIP, 0, mesh.length / VERTEX_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,253 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#define _DEBUG_BREAK {gl_FragColor=vec4(1,0,0,1); return;}
 | 
				
			||||||
 | 
					#define REFRACTION (c2 >= 0.? (eta*W + (eta*c1 - sqrt(c2))*N) : ((W + c1*N)/sqrt(1.-c1*c1)))
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					vec3 groundColor = vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 | 
				
			||||||
 | 
					uniform float uTime;// TIME, IN SECONDS
 | 
				
			||||||
 | 
					uniform vec3 Ambient[ns], Diffuse[ns];
 | 
				
			||||||
 | 
					uniform vec4 Specular[ns];
 | 
				
			||||||
 | 
					uniform float ks[ns], kr[ns], kf[ns];
 | 
				
			||||||
 | 
					uniform vec4 Sph[ns];
 | 
				
			||||||
 | 
					uniform sampler2D uSampler[ns];
 | 
				
			||||||
 | 
					uniform vec3 V0;
 | 
				
			||||||
 | 
					uniform int sel;
 | 
				
			||||||
 | 
					const float kf_air = 1.000293;
 | 
				
			||||||
 | 
					varying vec3 trPos;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					varying vec3 apos;
 | 
				
			||||||
 | 
					const float pi=3.14159265359;
 | 
				
			||||||
 | 
					const float _2pi=2.*pi;
 | 
				
			||||||
 | 
					vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					vec3 LCol=vec3(1.,1.,1.);
 | 
				
			||||||
 | 
					/***********PLEASE DO INCREASE n_ref(RT DEPTH) FOR BETTER RESULTS************/
 | 
				
			||||||
 | 
					/*---->*/const int n_ref=15; //2^n-1 because each hit now spawn at most 2 rays.
 | 
				
			||||||
 | 
					/**BUT BE CAUTIOUS IF YOU DON'T HAVE A DECENT GRAPHICS CARD (below GTX 950M)**/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int max_stack = (n_ref+1)/4;
 | 
				
			||||||
 | 
					vec3 scolor = vec3(0,0,0); 
 | 
				
			||||||
 | 
					struct Ray{
 | 
				
			||||||
 | 
					   vec3 V;
 | 
				
			||||||
 | 
					   vec3 W;
 | 
				
			||||||
 | 
					   float kf, cumulativeK;
 | 
				
			||||||
 | 
					} stack1[max_stack], stack2[max_stack];
 | 
				
			||||||
 | 
					bool modulo2(int n){
 | 
				
			||||||
 | 
					   return n-2*(n/2) == 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					vec2 getTextCoord(vec3 tex_sph, float R){
 | 
				
			||||||
 | 
					   float tex_x=atan(tex_sph.z,tex_sph.x)/_2pi + 0.5;//*Correct aspect ratio of texture 2:1 -> 2pir:2r
 | 
				
			||||||
 | 
					   tex_x=fract(tex_x+uTime/20.);
 | 
				
			||||||
 | 
					   return vec2(tex_x,-asin(tex_sph.y/R)/pi + 0.5);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void rtx(){   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   float currKf = kf_air;
 | 
				
			||||||
 | 
					   vec3 color=vec3(.2, .3, .5);
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=(trPos-V);
 | 
				
			||||||
 | 
					   bool rtxoff = false, showtexture = true, selected = false;
 | 
				
			||||||
 | 
					   float currentK = 1.;
 | 
				
			||||||
 | 
					   int curr_ptr = 0, curr_top = 0, next_top = 0;
 | 
				
			||||||
 | 
					   bool final = false, stackswap = false, stop = false;
 | 
				
			||||||
 | 
					   for(int j=0;j<n_ref;j++)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      for(int curr = 0; curr < max_stack; ++curr){
 | 
				
			||||||
 | 
					         if(curr == curr_ptr){
 | 
				
			||||||
 | 
					            bool skip = false;
 | 
				
			||||||
 | 
					            if(j > 0){
 | 
				
			||||||
 | 
					               Ray currR;
 | 
				
			||||||
 | 
					               if(stackswap)
 | 
				
			||||||
 | 
					                  currR = stack1[curr];
 | 
				
			||||||
 | 
					               else
 | 
				
			||||||
 | 
					                  currR = stack2[curr];
 | 
				
			||||||
 | 
					               currKf = currR.kf;
 | 
				
			||||||
 | 
					               currentK = currR.cumulativeK;
 | 
				
			||||||
 | 
					               if(currKf <= 0.001 || currentK <= 0.001)
 | 
				
			||||||
 | 
					                  skip = true; 
 | 
				
			||||||
 | 
					               V = currR.V;
 | 
				
			||||||
 | 
					               W = currR.W;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else 
 | 
				
			||||||
 | 
					               W = normalize(W);
 | 
				
			||||||
 | 
					            if(!skip){
 | 
				
			||||||
 | 
					               float tMin=10000.;
 | 
				
			||||||
 | 
					               int iMin = -1;
 | 
				
			||||||
 | 
					               for(int i=0;i<cns;i++){
 | 
				
			||||||
 | 
					                  vec3 Vp=V-Sph[i].xyz;
 | 
				
			||||||
 | 
					                  float B=dot(W,Vp);
 | 
				
			||||||
 | 
					                  float C=dot(Vp,Vp)-Sph[i].w*Sph[i].w;
 | 
				
			||||||
 | 
					                  float D=B*B-C;
 | 
				
			||||||
 | 
					                  if(D>0.){
 | 
				
			||||||
 | 
					                     float t=-B-sqrt(D);
 | 
				
			||||||
 | 
					                     if(t >= 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                        tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					                        iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else if (t >= -0.01 && t <0.01){
 | 
				
			||||||
 | 
					                        t = -(t + 2.*B);
 | 
				
			||||||
 | 
					                        if(t > 0.01 && t < tMin){
 | 
				
			||||||
 | 
					                           tMin = t;
 | 
				
			||||||
 | 
					                           iMin = i;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               if(iMin >= 0){
 | 
				
			||||||
 | 
					                  if(j == 0 && iMin == sel)
 | 
				
			||||||
 | 
					                     selected = true;
 | 
				
			||||||
 | 
					                  float t = tMin;
 | 
				
			||||||
 | 
					                  vec3 S=V+t*W;
 | 
				
			||||||
 | 
					                  for(int i = 0; i < cns; ++ i)
 | 
				
			||||||
 | 
					                     if(i == iMin)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        vec3 texture_color;
 | 
				
			||||||
 | 
					                        if(showtexture)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                           vec3 tex_sph = (S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                           texture_color=texture2D(uSampler[i],getTextCoord(tex_sph, Sph[i].w)).xyz;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else texture_color = foregroundColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        vec3 N=normalize(S-Sph[i].xyz);
 | 
				
			||||||
 | 
					                        vec3 realLDir=normalize(LDir-S);
 | 
				
			||||||
 | 
					                        float c1 =dot(N, W);
 | 
				
			||||||
 | 
					                        float eta, nextkf;
 | 
				
			||||||
 | 
					                        if(c1<0.){
 | 
				
			||||||
 | 
					                           color=(Ambient[i]+Diffuse[i]*max(0.,dot(N,realLDir))*LCol)*texture_color;
 | 
				
			||||||
 | 
					                           if(rtxoff || final) //if it's the last hit
 | 
				
			||||||
 | 
					                           {
 | 
				
			||||||
 | 
					                              color +=  Specular[i].xyz*pow(max(0.,
 | 
				
			||||||
 | 
					                                 dot(-2.*c1*N-realLDir,realLDir)),Specular[i].w);
 | 
				
			||||||
 | 
					                              scolor += color * currentK;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                           else{
 | 
				
			||||||
 | 
					                              c1 = -c1;
 | 
				
			||||||
 | 
					                              eta = currKf/kf[i];
 | 
				
			||||||
 | 
					                              nextkf = kf[i];
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else{
 | 
				
			||||||
 | 
					                           N = -N;
 | 
				
			||||||
 | 
					                           eta = currKf/kf_air;
 | 
				
			||||||
 | 
					                           nextkf = kf_air;
 | 
				
			||||||
 | 
					                           color = Ambient[i];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        float c2 = (1.-eta*eta*(1.-c1*c1));
 | 
				
			||||||
 | 
					                        float nextks = currentK * ks[i], nextkr = currentK * kr[i];
 | 
				
			||||||
 | 
					                        bool refl = nextks > 0.01, refr = nextkr > 0.01;
 | 
				
			||||||
 | 
					                        if(refl || refr)
 | 
				
			||||||
 | 
					                           for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                              if(k == next_top){
 | 
				
			||||||
 | 
					                                 if(stackswap){
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       stack2[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack2[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack2[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }else{
 | 
				
			||||||
 | 
					                                    if(refl)
 | 
				
			||||||
 | 
					                                    { //remember, c1 = -NW now
 | 
				
			||||||
 | 
					                                       stack1[k] = Ray(S, 2. * c1 * N + W, currKf, nextks); //reflection
 | 
				
			||||||
 | 
					                                       currentK -= nextks;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if(refr)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                       if(refl)
 | 
				
			||||||
 | 
					                                          stack1[k+1] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       else
 | 
				
			||||||
 | 
					                                          stack1[k] = Ray(S, REFRACTION, nextkf, nextkr); //refraction
 | 
				
			||||||
 | 
					                                       currentK -= nextkr;
 | 
				
			||||||
 | 
					                                       next_top ++;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                 }
 | 
				
			||||||
 | 
					                                 break;
 | 
				
			||||||
 | 
					                              }
 | 
				
			||||||
 | 
					                        scolor += color * currentK;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               else {
 | 
				
			||||||
 | 
					                  float t = -(.2+V.y)/W.y;
 | 
				
			||||||
 | 
					                  float sx = V.x + t* W.x, sz = V.z + t * W.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  if(t >= 0. && abs(sx) < 1.5 && abs(sz) < 3.)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                     vec3 S = vec3(sx, -.2, sz);
 | 
				
			||||||
 | 
					                     vec3 realLDir=normalize(LDir - S);
 | 
				
			||||||
 | 
					                     color=(0.5+0.5*max(0.,realLDir.y)*LCol)*texture2D(uSampler[4],vec2((sx+1.4)/3., (sz+1.5)/4.)).xyz;
 | 
				
			||||||
 | 
					                     if(rtxoff || final&&abs(sx)<1.5 && abs(sz+.6)<3.)
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        color += groundSpecular.xyz* //specular for ground.
 | 
				
			||||||
 | 
					                           pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
 | 
				
			||||||
 | 
					                        scolor += currentK * color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                     else
 | 
				
			||||||
 | 
					                     {
 | 
				
			||||||
 | 
					                        for(int k = 0; k < max_stack; ++k)
 | 
				
			||||||
 | 
					                           if(k == next_top){
 | 
				
			||||||
 | 
					                              if(stackswap)
 | 
				
			||||||
 | 
					                                 stack2[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              else
 | 
				
			||||||
 | 
					                                 stack1[k] = Ray(S, vec3(W.x, -W.y, W.z), kf_air, currentK * 0.15); //reflection
 | 
				
			||||||
 | 
					                              next_top ++;
 | 
				
			||||||
 | 
					                              break;
 | 
				
			||||||
 | 
					                           }
 | 
				
			||||||
 | 
					                        scolor += (currentK*.85)*color;
 | 
				
			||||||
 | 
					                     }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  else{
 | 
				
			||||||
 | 
					                     if(j > 0)
 | 
				
			||||||
 | 
					                        scolor += currentK * (pow(max(0.,dot(W, normalize(LDir - V))), 10.) * vec3(3.,3.,3.) + foregroundColor*0.1);
 | 
				
			||||||
 | 
					                     else scolor = foregroundColor*0.6;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(++curr_ptr >= curr_top){
 | 
				
			||||||
 | 
					               if(next_top <= 0)
 | 
				
			||||||
 | 
					                  stop = true;
 | 
				
			||||||
 | 
					               if(next_top * 2 > max_stack)
 | 
				
			||||||
 | 
					                  final = true;
 | 
				
			||||||
 | 
					               curr_top = next_top;
 | 
				
			||||||
 | 
					               next_top = 0;
 | 
				
			||||||
 | 
					               curr_ptr = 0;
 | 
				
			||||||
 | 
					               stackswap = !stackswap;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if(stop)
 | 
				
			||||||
 | 
					         break;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(selected)
 | 
				
			||||||
 | 
					      scolor.x += 0.5;
 | 
				
			||||||
 | 
					   gl_FragColor=vec4((scolor),1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 color =foregroundColor.xyz;
 | 
				
			||||||
 | 
					   float sp = 0.4, df = 0.4, amb = 0.4;
 | 
				
			||||||
 | 
					   if(id == 4.) {rtx();color = gl_FragColor.xyz;}
 | 
				
			||||||
 | 
					   else if (id == 1.) color = vec3(1.,.4,.6);
 | 
				
			||||||
 | 
					   else if (id == 5.) {color = vec3(1, .9375,.7329);sp = .5; df=.8; amb = .05;}
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=normalize(glpos-V);
 | 
				
			||||||
 | 
					   vec3 realLDir=normalize(LDir - glpos);
 | 
				
			||||||
 | 
					   color = color*(amb+ df*max(0.,dot(norm,realLDir)))//specular for ground.
 | 
				
			||||||
 | 
					                        + sp*pow(max(0., dot(2.*dot(norm, realLDir)*norm-realLDir, -W)),5.)*vec3(1,1,1);
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(color), 1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					uniform mat4 uMatrix;
 | 
				
			||||||
 | 
					uniform mat3 transformation;
 | 
				
			||||||
 | 
					attribute float oid;
 | 
				
			||||||
 | 
					attribute vec3 aPos;
 | 
				
			||||||
 | 
					attribute vec3 normal;
 | 
				
			||||||
 | 
					varying vec3 trPos;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					varying vec3 apos;
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    vec4 pos = uMatrix * vec4(aPos, 1.);
 | 
				
			||||||
 | 
					    gl_Position = pos * vec4(1., 1., -1., 1.);
 | 
				
			||||||
 | 
					    id = oid;
 | 
				
			||||||
 | 
					    norm = normalize((uMatrix*vec4(normal,0.)).xyz);
 | 
				
			||||||
 | 
					    trPos = transformation *vec3(pos.xy, -1);
 | 
				
			||||||
 | 
					    apos = aPos;
 | 
				
			||||||
 | 
					    glpos = gl_Position.xyz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.5 KiB  | 
@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					<!--<video src="pjsk.mp4" id="pjsk" muted="muted" loop="true" style="position:fixed; left:0; top:0;max-width:100%;min-width:100%;min-height: 100%;z-index: -100;"></video>-->
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src=lib6.header.js></script>
 | 
				
			||||||
 | 
					<script src=lib6.js></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<font size=7 color=#909090>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Spring Break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img id="rtx" style="float:right;" src="./RTXon.svg" type="image/svg+xml"
 | 
				
			||||||
 | 
					   alt="Turn Ray Tracing On/OFF" title="Turn Ray Tracing On/OFF" height=60px /img>
 | 
				
			||||||
 | 
					<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>
 | 
				
			||||||
 | 
					<TABLE cellspacing=0 cellpadding=0><TR>
 | 
				
			||||||
 | 
					<td><font color=red size=5><div id=errorMessage></div></font></td>
 | 
				
			||||||
 | 
					</TR><TR>
 | 
				
			||||||
 | 
					<table cellspacing=0>
 | 
				
			||||||
 | 
					<tr>
 | 
				
			||||||
 | 
					<td valign=top>
 | 
				
			||||||
 | 
					<div id="ace" style="opacity:90%;width:800px;height:2200px;"></div>
 | 
				
			||||||
 | 
					</td><td valign=top style="background-color:azure;opacity: 100%;">
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					   <center>
 | 
				
			||||||
 | 
					      <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					   <canvas id='canvas1' style=" background-color:#FFF7F8;opacity: 100%;overflow: hidden !important; width: 600px !important; height:600px !important;" width=1199 height=1199></canvas>
 | 
				
			||||||
 | 
					   </center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					<div id="controls">
 | 
				
			||||||
 | 
					<input type="number" id="ins" style="display:none;margin-left:0px;font-size:24px;width:35px;height:45px" value="5" max="5" min = "1">
 | 
				
			||||||
 | 
					<button id="bns" style="display:none;margin-left:0px;font-size:24px;width:105px;height:45px">Spheres</button>
 | 
				
			||||||
 | 
					<input type="number" id="insamp" style="margin-left:2px;font-size:24px;width:60px;height:45px" value="2" max="10" min = "0.1" step="0.2">
 | 
				
			||||||
 | 
					<button id="bnsamp" style="margin-left:0px;font-size:24px;width:190px;height:45px">Super Sampling</button>
 | 
				
			||||||
 | 
					<button id="bnfs" style="margin-left:2px;font-size:24px;width:180px;height:45px">Fullscreen</button>
 | 
				
			||||||
 | 
					<button id="clrsel" style="display:none;margin-left:0px;font-size:24px;width:180px;height:45px">Clear Selection</button>
 | 
				
			||||||
 | 
					<button id="reset" style="margin-left:0px;font-size:24px;width:100px;height:45px">Reset</button>
 | 
				
			||||||
 | 
					<button id="mov" style="margin-left:0px;font-size:24px;width:180px;height:45px">Move Lighting</button>
 | 
				
			||||||
 | 
					<button id="pause" style="margin-left:0px;font-size:24px;width:100px;height:45px">Pause</button>
 | 
				
			||||||
 | 
					<div style='font-size:25px;'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <font color=#909090>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					   <i style="font-size:25px;">What's new: </i>
 | 
				
			||||||
 | 
					   <p style="font-size:20px;"> 
 | 
				
			||||||
 | 
					        I corrected the Phong lighting, added perspective and implemented both splines.<br>
 | 
				
			||||||
 | 
					        Since we're learning splines. I figured it would be interesting to 
 | 
				
			||||||
 | 
					   do vector graphics.<br>
 | 
				
			||||||
 | 
					        It seems that most paths in a svg file (see <a href="./paths.txt">path.txt</a>) 
 | 
				
			||||||
 | 
					   are a combination multiple of end-to-end Bezier Splines.<br>
 | 
				
			||||||
 | 
					        I created these shapes in Adobe Illustrator and output them to svg.<br>
 | 
				
			||||||
 | 
					       I processed the path data in (see <a href="./lib6.header.js">lib6.header.js</a>) and 
 | 
				
			||||||
 | 
					   transformed them into multiple Bezier functions and then interpolated them in <a href="./lib6.ext.js">lib6.ext.js</a>
 | 
				
			||||||
 | 
					   so that they appears to be smooth shapes.
 | 
				
			||||||
 | 
					   <br>
 | 
				
			||||||
 | 
					        I also made animations with Hermite Splines.<br>
 | 
				
			||||||
 | 
					        As before, you can 'walk' by pressing arrow keys, it's now looked more like it because 
 | 
				
			||||||
 | 
					   I added a ground and the scene is now perspective. Again, better used in Fullscreen mode.<br>
 | 
				
			||||||
 | 
					   </p>
 | 
				
			||||||
 | 
					   <div id="howitworks">
 | 
				
			||||||
 | 
					   <br>
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <p>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div></td>
 | 
				
			||||||
 | 
					</tr></table>
 | 
				
			||||||
 | 
					</TR></TABLE>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script src="lib6.ext.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					   setInterval(() => {
 | 
				
			||||||
 | 
					      if(window.vs != null && window.fs != null&& canvas1.setShaders === undefined)
 | 
				
			||||||
 | 
					         gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					   }, 200);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -0,0 +1,795 @@
 | 
				
			|||||||
 | 
					let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
 | 
				
			||||||
 | 
					let lastClick = undefined;
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					var startTime = Date.now();
 | 
				
			||||||
 | 
					let lastTime = Date.now();
 | 
				
			||||||
 | 
					var lastFrameTime = 0;
 | 
				
			||||||
 | 
					let oldDocument;
 | 
				
			||||||
 | 
					let fullscreen = false, btntoggled = false;
 | 
				
			||||||
 | 
					let movescene = true;
 | 
				
			||||||
 | 
					let oldparents = {};
 | 
				
			||||||
 | 
					var tr, div;
 | 
				
			||||||
 | 
					let canvas_originalsize;
 | 
				
			||||||
 | 
					let Sph = [];
 | 
				
			||||||
 | 
					let SphTr = [];
 | 
				
			||||||
 | 
					let SphDletaR = []
 | 
				
			||||||
 | 
					let selected = false, selection = -1, dragging = false;
 | 
				
			||||||
 | 
					let overall_trans = matrix_identity(), overall_ground;
 | 
				
			||||||
 | 
					let rebuild = true, buildsplines = true, presentation = false, sRotation = matrix_identity();
 | 
				
			||||||
 | 
					let facing = 1, running = 0;
 | 
				
			||||||
 | 
					for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					   SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function ev_supersample(e){
 | 
				
			||||||
 | 
					   let multiplier  = insamp.value;
 | 
				
			||||||
 | 
					   let w = parseInt(canvas1.style.width)*multiplier;
 | 
				
			||||||
 | 
					   let h = parseInt(canvas1.style.height)*multiplier;
 | 
				
			||||||
 | 
					   canvas1.height = h;
 | 
				
			||||||
 | 
					   canvas1.width = w;
 | 
				
			||||||
 | 
					   gl.viewport(0, 0, w, h);
 | 
				
			||||||
 | 
					   //gl.clearRect(0, 0, w, h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function toggleFullscreen(element){
 | 
				
			||||||
 | 
					   if(fullscreen)
 | 
				
			||||||
 | 
					   { 
 | 
				
			||||||
 | 
					      if (document.exitFullscreen) 
 | 
				
			||||||
 | 
					         document.exitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.webkitExitFullscreen) 
 | 
				
			||||||
 | 
					         document.webkitExitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.mozCancelFullScreen) 
 | 
				
			||||||
 | 
					         document.mozCancelFullScreen();
 | 
				
			||||||
 | 
					      else if (document.msExitFullscreen) 
 | 
				
			||||||
 | 
					         document.msExitFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = false;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      if(element.requestFullscreen)
 | 
				
			||||||
 | 
					         element.requestFullscreen();
 | 
				
			||||||
 | 
					      else if (element.webkitRequestFullscreen)
 | 
				
			||||||
 | 
					         element.webkitRequestFullscreen();
 | 
				
			||||||
 | 
					      else if(element.msRequestFullscreen)
 | 
				
			||||||
 | 
					         element.msRequestFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = true;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Exit Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnfs.onclick = function(e){
 | 
				
			||||||
 | 
					   if(e === "no")
 | 
				
			||||||
 | 
					      ;
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      btntoggled = true;
 | 
				
			||||||
 | 
					   if(fullscreen){
 | 
				
			||||||
 | 
					      oldparents[controls].appendChild(controls);
 | 
				
			||||||
 | 
					      oldparents[canvas1].appendChild(canvas1);
 | 
				
			||||||
 | 
					      canvas1.style.width = canvas_originalsize[0];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas_originalsize[1];
 | 
				
			||||||
 | 
					      howitworks.hidden = false;
 | 
				
			||||||
 | 
					   }else{
 | 
				
			||||||
 | 
					      div = document.createElement("div");
 | 
				
			||||||
 | 
					      tr = document.createElement("table").insertRow();
 | 
				
			||||||
 | 
					      tr.style.backgroundColor="white";
 | 
				
			||||||
 | 
					      let size = Math.min(screen.availHeight, screen.availWidth);
 | 
				
			||||||
 | 
					      canvas_originalsize = [canvas1.style.width, canvas1.style.height, canvas1.width, canvas1.height];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas1.style.width = size;
 | 
				
			||||||
 | 
					      howitworks.hidden=true;
 | 
				
			||||||
 | 
					      oldparents[controls] = controls.parentNode;
 | 
				
			||||||
 | 
					      oldparents[canvas1] = canvas1.parentNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let td1 = tr.insertCell();
 | 
				
			||||||
 | 
					      td1.appendChild(canvas1);
 | 
				
			||||||
 | 
					      let td2;
 | 
				
			||||||
 | 
					      td2 = tr.insertCell();
 | 
				
			||||||
 | 
					      td2.style.verticalAlign="top";
 | 
				
			||||||
 | 
					      td2.appendChild(controls);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      div.appendChild(tr);
 | 
				
			||||||
 | 
					      document.body.appendChild(div);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   toggleFullscreen(div);
 | 
				
			||||||
 | 
					   ev_supersample();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					mov.onclick=function(_){
 | 
				
			||||||
 | 
					   movescene = !movescene;
 | 
				
			||||||
 | 
					   if(!movescene)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mov.innerText= "Move Scene";
 | 
				
			||||||
 | 
					      mov.style.width = "170px";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mov.innerText = "Move Lighting";
 | 
				
			||||||
 | 
					      mov.style.width = "180px";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					document.addEventListener("webkitfullscreenchange", ()=>{if(!btntoggled && fullscreen)bnfs.onclick("no");btntoggled = false;});
 | 
				
			||||||
 | 
					document.addEventListener("fullscreenchange", ()=>{if(!btntoggled && fullscreen)bnfs.onclick("no");btntoggled = false;});
 | 
				
			||||||
 | 
					clrsel.onclick=function(_){
 | 
				
			||||||
 | 
					   setUniform("1i", "sel", -1);
 | 
				
			||||||
 | 
					   selected = false;
 | 
				
			||||||
 | 
					   selection = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					reset.onclick = function(_){
 | 
				
			||||||
 | 
					   clrsel.onclick();
 | 
				
			||||||
 | 
					   if(!animating)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   flags = 0;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   mousedx = mousedy = mousedz = 0;
 | 
				
			||||||
 | 
					   positionsupdated = true;
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					      SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bns.onclick=function(e){
 | 
				
			||||||
 | 
					   if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
 | 
				
			||||||
 | 
					   {   
 | 
				
			||||||
 | 
					      cns = ins.value;
 | 
				
			||||||
 | 
					      fragmentShaderDefs = '\n const int cns = ' + cns + ';';
 | 
				
			||||||
 | 
					      if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnsamp.onclick=ev_supersample;
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					if(fs != undefined)
 | 
				
			||||||
 | 
					    editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					   if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					delete editor.KeyBinding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let pause_resume = function(){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      lastTime = Date.now();
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					   animating = !animating;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(!(shift && alt) && lastClick&& Date.now()-lastClick<200)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   lastClick = Date.now();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					pause.onclick = pause_resume;
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseover', function(e){
 | 
				
			||||||
 | 
					   over = true;
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags |= mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousedown', function(e){
 | 
				
			||||||
 | 
					      moving = true
 | 
				
			||||||
 | 
					      mouselastX = mouselastY =  undefined;
 | 
				
			||||||
 | 
					      let i = hitTest([2*e.offsetX/ parseInt(canvas1.style.width)-1, 
 | 
				
			||||||
 | 
					         1-2*e.offsetY/ parseInt(canvas1.style.height), -1]);
 | 
				
			||||||
 | 
					      if(i >= 0)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         dragging = true;
 | 
				
			||||||
 | 
					         selected = true;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else if(selected = true){
 | 
				
			||||||
 | 
					         dragging = false;
 | 
				
			||||||
 | 
					         selected = false;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousemove', function(e){
 | 
				
			||||||
 | 
					      if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
 | 
				
			||||||
 | 
					         let dx = (mouselastX - e.offsetX), 
 | 
				
			||||||
 | 
					             dy = (mouselastY - e.offsetY);
 | 
				
			||||||
 | 
					         if(movescene){
 | 
				
			||||||
 | 
					            sRotation = matrix_multiply(sRotation, matrix_rotateY(-dy/60));
 | 
				
			||||||
 | 
					            sRotation = matrix_multiply(sRotation, matrix_rotateX(-dx/60)); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         } 
 | 
				
			||||||
 | 
					         else if(!selected)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					               mousedx -= dx/60;
 | 
				
			||||||
 | 
					               mousedy -= dy/60;
 | 
				
			||||||
 | 
					               positionsupdated = true;
 | 
				
			||||||
 | 
					         }else if(dragging){
 | 
				
			||||||
 | 
					               let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					               m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					               let dv = matrix_multiply(m, [2*-dx/ parseInt(canvas1.style.width), 
 | 
				
			||||||
 | 
					                  2*dy/ parseInt(canvas1.style.height), 0, 1]).slice(0,3);
 | 
				
			||||||
 | 
					               SphTr[selection] = matrix_multiply(SphTr[selection], matrix_translate(dv[0], dv[1], dv[2]));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mouselastX = e.offsetX;
 | 
				
			||||||
 | 
					      mouselastY = e.offsetY;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseup', function(e){
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   dragging = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseout', function(e){
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags &= !mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   over = false;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('wheel', function(e){
 | 
				
			||||||
 | 
					   if(!selected){
 | 
				
			||||||
 | 
					      mousedz += e.wheelDelta/600;
 | 
				
			||||||
 | 
					      positionsupdated = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      SphDletaR[selection] += e.wheelDelta / 800;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.scroll(function(e) {e.stopPropagation();});
 | 
				
			||||||
 | 
					rtx.style.cursor="pointer";
 | 
				
			||||||
 | 
					let rtswitch = function(){
 | 
				
			||||||
 | 
					   alert('Ray Tracing is off due to global silicon shortage. \nSend me an RTX 3090 to enable Ray Tracing again.')
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					rtx.addEventListener('click', rtswitch);
 | 
				
			||||||
 | 
					var requestAnimationFrame = window.requestAnimationFrame ||
 | 
				
			||||||
 | 
					 window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 | 
				
			||||||
 | 
					let fpscounter = function(time){
 | 
				
			||||||
 | 
					      if (start === undefined)
 | 
				
			||||||
 | 
					         start = time;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
 | 
				
			||||||
 | 
					      start = time;
 | 
				
			||||||
 | 
					      if(fpson)
 | 
				
			||||||
 | 
					         ;//requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         start = undefined;
 | 
				
			||||||
 | 
					         fps.innerHTML = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = true;
 | 
				
			||||||
 | 
					   else if(ctrl && alt && e.code == 'KeyT'){
 | 
				
			||||||
 | 
					      const mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)?mask:0);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (ctrl &&e.code == 'KeyS'){
 | 
				
			||||||
 | 
					      let a = document.createElement('a');
 | 
				
			||||||
 | 
					      a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
 | 
				
			||||||
 | 
					      a.download = 'shader.frag';
 | 
				
			||||||
 | 
					      a.click();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyR')
 | 
				
			||||||
 | 
					      rtswitch();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyN')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      reset.onclick();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyP')
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyF')
 | 
				
			||||||
 | 
					      if(!fpson)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         fpson = true;
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fpson = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(e.code == 'ArrowUp' || e.code == 'ArrowDown' || e.code =='ArrowLeft'
 | 
				
			||||||
 | 
					      ||e.code == 'ArrowRight' || e.code =='KeyW'||e.code =='KeyS')
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         switch(e.code){
 | 
				
			||||||
 | 
					         case 'ArrowUp':
 | 
				
			||||||
 | 
					            facing = -2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowDown':
 | 
				
			||||||
 | 
					            facing = 2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowLeft':
 | 
				
			||||||
 | 
					            facing = -1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowRight':
 | 
				
			||||||
 | 
					            facing = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'KeyW':
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'KeyS':
 | 
				
			||||||
 | 
					            break;  
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      running = 50;
 | 
				
			||||||
 | 
					      rebuild = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(fullscreen && selected ){
 | 
				
			||||||
 | 
					      if(e.code =='KeyF'||e.code =='KeyB'){
 | 
				
			||||||
 | 
					            let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					            m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					            m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch(e.code){   
 | 
				
			||||||
 | 
					               case 'KeyB':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, -0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					               case 'KeyF':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, 0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;                
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            SphTr[selection] = matrix_multiply(SphTr[selection], m);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					let squareMesh = new Float32Array([ -1,-1,1,0,0,0,1,-1, 1,1,0,0,0,1,-1, -1,-1,0,0,0,1, -1,1,-1,0 ,0,0,1]);
 | 
				
			||||||
 | 
					let sphereMesh   = createMesh(32, 32, uvToSphere);
 | 
				
			||||||
 | 
					let tubeMesh     = createMesh(32, 2, uvToTube,0,1);
 | 
				
			||||||
 | 
					let diskMesh     = createMesh(32, 2, uvToDisk,0,1);
 | 
				
			||||||
 | 
					let tubeMesh2     = createMesh(32, 2, uvToTube,0,2);
 | 
				
			||||||
 | 
					let diskNMesh2    = createMesh(32, 2, uvToDisk, -1,2);
 | 
				
			||||||
 | 
					let diskPMesh2    = createMesh(32, 2, uvToDisk,  1,2);
 | 
				
			||||||
 | 
					let tubeMesh3     = createMesh(32, 2, uvToTube,0,3);
 | 
				
			||||||
 | 
					let diskNMesh3    = createMesh(32, 2, uvToDisk, -1,3);
 | 
				
			||||||
 | 
					let diskPMesh3    = createMesh(32, 2, uvToDisk,  1,3);
 | 
				
			||||||
 | 
					let diskNMesh    = createMesh(32, 2, uvToDisk, -1,1);
 | 
				
			||||||
 | 
					let diskPMesh    = createMesh(32, 2, uvToDisk,  1,1);
 | 
				
			||||||
 | 
					let cylinderMesh = glueMeshes(glueMeshes(tubeMesh, diskPMesh), diskNMesh);
 | 
				
			||||||
 | 
					let cylinderMesh2 = glueMeshes(glueMeshes(tubeMesh2, diskPMesh2), diskNMesh2);
 | 
				
			||||||
 | 
					let cylinderMesh3 = glueMeshes(glueMeshes(tubeMesh3, diskPMesh3), diskNMesh3);
 | 
				
			||||||
 | 
					let torusMash    = createMesh(32, 32, uvToTorus, 1, 5);
 | 
				
			||||||
 | 
					let head = createCube(1.5,1,1, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let objects = [];
 | 
				
			||||||
 | 
					let addObject = (obj, mat) => {
 | 
				
			||||||
 | 
					   objects.push([obj, mat]);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					let clearObject = () => {delete objects; objects = [];};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let delta_height = 0, delta_l = [0,0];
 | 
				
			||||||
 | 
					class State{
 | 
				
			||||||
 | 
					   constructor() {
 | 
				
			||||||
 | 
					      this.leg = true;
 | 
				
			||||||
 | 
					      this.progress = 0;
 | 
				
			||||||
 | 
					      this.rh = this.lh = .5*pi;
 | 
				
			||||||
 | 
					      this.lf = this.rf = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   initialize(){
 | 
				
			||||||
 | 
					      this.leg = true;
 | 
				
			||||||
 | 
					      this.progress = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   next(){
 | 
				
			||||||
 | 
					      //return this.presentation();
 | 
				
			||||||
 | 
					      if(running <= 0)
 | 
				
			||||||
 | 
					         return {rh:.5*pi, lh:.5*pi, rf:0, lf:0, dh:0,dl:0}
 | 
				
			||||||
 | 
					      running --;
 | 
				
			||||||
 | 
					      const steps = 100;
 | 
				
			||||||
 | 
					      let dl = 0;
 | 
				
			||||||
 | 
					      if(this.progress >= steps/2)
 | 
				
			||||||
 | 
					      { 
 | 
				
			||||||
 | 
					         this.progress = 0;
 | 
				
			||||||
 | 
					         this.leg = !this.leg;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let delta = [-pi/5, 0.5*pi, 0.44*pi, 0.55*pi];
 | 
				
			||||||
 | 
					      for (let i = 0; i < 4; ++i) delta[i] /= steps;
 | 
				
			||||||
 | 
					      if(this.leg)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         if(this.progress < steps/4)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            this.lh += delta[0];
 | 
				
			||||||
 | 
					            this.rh += delta[3];
 | 
				
			||||||
 | 
					            this.lf += delta[1];
 | 
				
			||||||
 | 
					            this.rf += delta[2];
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            this.lh -= delta[0];
 | 
				
			||||||
 | 
					            this.rh -= delta[3];
 | 
				
			||||||
 | 
					            this.lf -= delta[1];
 | 
				
			||||||
 | 
					            this.rf-= delta[2];  
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         if(this.progress < steps/4)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            this.lh += delta[3];
 | 
				
			||||||
 | 
					            this.rh += delta[0];
 | 
				
			||||||
 | 
					            this.lf += delta[2];
 | 
				
			||||||
 | 
					            this.rf += delta[1];
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            this.lh -= delta[3];
 | 
				
			||||||
 | 
					            this.rh -= delta[0];
 | 
				
			||||||
 | 
					            this.lf -= delta[2];
 | 
				
			||||||
 | 
					            this.rf-= delta[1];  
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let delta_h = Math.max((1-cos(abs(this.lh - pi/2)))*.5+(1-cos(abs(this.lf)))*.6,(1-cos(abs(this.rh - pi/2)))*.5+(1-cos(abs(this.rf)))*.6);
 | 
				
			||||||
 | 
					      this.progress++;  
 | 
				
			||||||
 | 
					      return  {lh:this.lh, lf:this.lf, rh:this.rh,rf:this.rf, dh:delta_h, dl:1.8522/steps};
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   // presentation(){
 | 
				
			||||||
 | 
					   //    return {lh:.4*pi, lf:pi/6,rh:.7*pi, rf:pi/8, dh:0};
 | 
				
			||||||
 | 
					   // }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let star1 = [], star = []; 
 | 
				
			||||||
 | 
					let sakura = [];
 | 
				
			||||||
 | 
					let star2=[], newstar, star4;
 | 
				
			||||||
 | 
					const curvex = matrix_multiply(hermiteMat, [-.3,.8,.6,.5]);
 | 
				
			||||||
 | 
					const curvey = matrix_multiply(hermiteMat, [-.2,.5,.7,.2]);
 | 
				
			||||||
 | 
					const curvez = matrix_multiply(hermiteMat, [-.5,.2,.3,.8]);
 | 
				
			||||||
 | 
					let adt = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let build_objects = (state)=>{
 | 
				
			||||||
 | 
					   if(running === 0)
 | 
				
			||||||
 | 
					      rebuild = false;
 | 
				
			||||||
 | 
					   let {lh, lf, rh, rf, dh, dl} = state.next();
 | 
				
			||||||
 | 
					   delta_l[abs(facing)-1] +=  Math.sign(facing) * dl;
 | 
				
			||||||
 | 
					   delta_height = dh;
 | 
				
			||||||
 | 
					   clearObject();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.rotateX(pi/2);
 | 
				
			||||||
 | 
					         M.scale(0.5, 0.5, 1);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0,1,0);
 | 
				
			||||||
 | 
					         addObject(head, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0.5, 0.2, 0.3);
 | 
				
			||||||
 | 
					         M.rotateX(pi/4);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.4);
 | 
				
			||||||
 | 
					            M.rotateX(-0.53*pi);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.4);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-0.5, 0.2, 0.3);
 | 
				
			||||||
 | 
					         M.rotateX(pi/4);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.4);
 | 
				
			||||||
 | 
					            M.rotateX(-0.55*pi);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.4);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					      M.restore();      
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0.3, -1, 0.);
 | 
				
			||||||
 | 
					         M.rotateX(lh);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.45);
 | 
				
			||||||
 | 
					            M.rotateX(lf);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.6);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-0.3, -1, 0.);
 | 
				
			||||||
 | 
					         M.rotateX(rh);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.45);
 | 
				
			||||||
 | 
					            M.rotateX(rf);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.6);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   if(running < 0)
 | 
				
			||||||
 | 
					      rebuild = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					let build_splines = ()=>{
 | 
				
			||||||
 | 
					   star = [], star1 = [], star2 = [], star4 = [], newstar = [], adt = [], sakura = [];
 | 
				
			||||||
 | 
					   var n = 11, innerN = Math.ceil((paths[0].length*n)/paths[1].length);
 | 
				
			||||||
 | 
					   for(let j = 0; j < paths[0].length; ++j)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let xf = paths[0][j][0], yf = paths[0][j][1];
 | 
				
			||||||
 | 
					      for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					         let t = k/n;
 | 
				
			||||||
 | 
					         star1.push([7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         0,0,0,1]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for(let j = 13; j >=0; j--)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let xf = paths[1][j][0], yf = paths[1][j][1];
 | 
				
			||||||
 | 
					      for(var k = innerN-1; k >=0 ; --k){
 | 
				
			||||||
 | 
					         let t = k/(innerN-1);
 | 
				
			||||||
 | 
					         star2.push([7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         0,0,0,1]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   for(let j = paths[1].length-1; j >12; --j)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let xf = paths[1][j][0], yf = paths[1][j][1];
 | 
				
			||||||
 | 
					      for(var k = innerN; k >=0 ; --k){
 | 
				
			||||||
 | 
					         let t = k/innerN;
 | 
				
			||||||
 | 
					         star2.push([7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         0,0,0,1]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   let concat = (a, b) => b.forEach(e => a.push(e));
 | 
				
			||||||
 | 
					   for(let i = 0; i < star1.length; ++i){
 | 
				
			||||||
 | 
					      concat(star, star1[i]);
 | 
				
			||||||
 | 
					      concat(star, star2[i]);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   n = 25;
 | 
				
			||||||
 | 
					   for(let l = 2; l < 6; ++l)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      adt[l - 2] = [];
 | 
				
			||||||
 | 
					      for(let j = 0; j < paths[l].length; ++j)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         let xf = paths[l][j][0], yf = paths[l][j][1];
 | 
				
			||||||
 | 
					         for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					            let t = k/n;
 | 
				
			||||||
 | 
					            adt[l-2].push(10+l,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            -dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            0,0,0,1);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   n = 20;
 | 
				
			||||||
 | 
					   for(let l = 6; l < 13; ++l)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      sakura[l-6] = [];
 | 
				
			||||||
 | 
					      for(let j = 0; j < paths[l].length; ++j)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         let xf = paths[l][j][0], yf = paths[l][j][1];
 | 
				
			||||||
 | 
					         for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					            let t = k/n;
 | 
				
			||||||
 | 
					            sakura[l-6].push(10,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            0,0,0,1);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   star4 = star.slice();
 | 
				
			||||||
 | 
					   newstar = star.slice()
 | 
				
			||||||
 | 
					   for(let i = 0; i < star.length; i+=7)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      star4[i] = 9;
 | 
				
			||||||
 | 
					      newstar[i] = 8;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let state = new State();
 | 
				
			||||||
 | 
					var M = new Matrix();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   let uTime;
 | 
				
			||||||
 | 
					   buildsplines &&=  build_splines();
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (Date.now() - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (lastTime - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   Sph[0] = [0,0.05*Math.cos(uTime + 1.),.045*Math.cos(uTime), 1,.15];
 | 
				
			||||||
 | 
					   Sph[1] = [0,0,0,1,.25];
 | 
				
			||||||
 | 
					   Sph[2] = [.22*Math.sin(uTime*1.2),0.05,.22*Math.cos(uTime*1.2),1,.05];
 | 
				
			||||||
 | 
					   Sph[3] = [.9*Math.sin(uTime*.4),0.,.9*Math.cos(uTime*.4),1,.25];
 | 
				
			||||||
 | 
					   Sph[4] = [0.5*Math.sin(uTime*1.),0.08*Math.sin(uTime *0.9),.5*Math.cos(uTime*1.),1,.12];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++ i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let trsph = matrix_multiply(SphTr[i], Sph[i]);
 | 
				
			||||||
 | 
					      trsph[3] = Sph[i][4];
 | 
				
			||||||
 | 
					      setUniform('4fv', 'Sph['+ i + ']', trsph);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(presentation){
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.scale(0.3);
 | 
				
			||||||
 | 
					         M.rotateY(uTime/5);
 | 
				
			||||||
 | 
					         M.rotateX(1);
 | 
				
			||||||
 | 
					         overall_ground = M.value();
 | 
				
			||||||
 | 
					         if(facing !=2)
 | 
				
			||||||
 | 
					            M.rotateY(pi*(facing/2));
 | 
				
			||||||
 | 
					         M.translate(delta_l[0], -delta_height, delta_l[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         //M.translate(0, -delta_height, 0);
 | 
				
			||||||
 | 
					         overall_trans = M.value();
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   }else{
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					        // M.rotateY(2);
 | 
				
			||||||
 | 
					         M.translate(-.3, -.3, 0);
 | 
				
			||||||
 | 
					         M.rotateX(.6);
 | 
				
			||||||
 | 
					         M.rotateZ(.35);
 | 
				
			||||||
 | 
					         M.scale(0.3);
 | 
				
			||||||
 | 
					         overall_ground = M.value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         M.translate(delta_l[0], -delta_height, delta_l[1]);
 | 
				
			||||||
 | 
					         if(facing !=2)
 | 
				
			||||||
 | 
					            M.rotateY(pi*(facing/2));
 | 
				
			||||||
 | 
					         overall_trans = M.value();
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(rebuild)
 | 
				
			||||||
 | 
					      build_objects(state);
 | 
				
			||||||
 | 
					   for(const [obj, mat] of objects){
 | 
				
			||||||
 | 
					      let m = matrix_multiply(sRotation,matrix_multiply(overall_trans, mat));
 | 
				
			||||||
 | 
					      setM(m);
 | 
				
			||||||
 | 
					      drawMesh(obj);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					      // M.rotateX(uTime/4);
 | 
				
			||||||
 | 
					      const _curvez = matrix_multiply(hermiteMat, [-.5,-.2,.3,.8]);
 | 
				
			||||||
 | 
					   // M.rotateZ(uTime/4);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					       M.rotateZ((uTime));
 | 
				
			||||||
 | 
					      //M.scale(100);
 | 
				
			||||||
 | 
					      setM(M.value());
 | 
				
			||||||
 | 
					      drawMesh(new Float32Array(star));
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					   let t = (sin(uTime/1.5)), mat = [t*t*t, t*t, t, 1]
 | 
				
			||||||
 | 
					   if(t < 0)
 | 
				
			||||||
 | 
					   {   mat = const_multiply(-t, [1,1,1,1]);
 | 
				
			||||||
 | 
					      mat[3] +=1;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   M.translate(dot(curvex, mat)*2, dot(curvey, mat)*2, dot(curvez, mat)*2);
 | 
				
			||||||
 | 
					   M.scale(0.2);
 | 
				
			||||||
 | 
					   setM(M.value());
 | 
				
			||||||
 | 
					   drawMesh(new Float32Array(newstar));
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   const __curvey = matrix_multiply(hermiteMat, [-.3,.5,1.9,.8]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					   M.translate(0,dot(__curvey, mat)*4, 0);
 | 
				
			||||||
 | 
					   t = abs(((uTime%4)/1.2)), mat = [t*t*t, t*t, t, 1];
 | 
				
			||||||
 | 
					   M.rotateZ(dot(__curvey, mat));
 | 
				
			||||||
 | 
					   M.scale(0.2);
 | 
				
			||||||
 | 
					   setM(M.value());
 | 
				
			||||||
 | 
					   drawMesh(new Float32Array(star4));
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					      M.scale(0.1);
 | 
				
			||||||
 | 
					      M.translate(6,0,1);
 | 
				
			||||||
 | 
					      M.rotateX(1);
 | 
				
			||||||
 | 
					      M.rotateY(uTime/4);
 | 
				
			||||||
 | 
					      t = abs(sin((uTime%3.1415)/3.)), mat = [t*t*t, t*t, t, 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      //M.scale(abs((dot(matrix_multiply(hermiteMat, [-.3,.9,1.7,2.8]), mat))));
 | 
				
			||||||
 | 
					      setM(M.value());
 | 
				
			||||||
 | 
					      drawMesh(torusMash,gl.LINES);
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					   M.translate(-.7,.75,0);
 | 
				
			||||||
 | 
					   //M.rotateZ(pi);
 | 
				
			||||||
 | 
					   M.scale(0.6)
 | 
				
			||||||
 | 
					   setM(M.value());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for(let l = 2; l < 6; ++l)
 | 
				
			||||||
 | 
					      drawMesh(new Float32Array(adt[l-2]),gl.LINE_LOOP);
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					  // M.scale(sin(uTime/2));
 | 
				
			||||||
 | 
					  M.translate(-.23, .7, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   M.rotateZ(sin(uTime/6) + 0.2);
 | 
				
			||||||
 | 
					   M.scale(0.4);
 | 
				
			||||||
 | 
					      for(let i = 0; i < 10; i++){
 | 
				
			||||||
 | 
					         M.scale(0.995);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					         setM(M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         for(let l = 8; l < 13; ++l)
 | 
				
			||||||
 | 
					            drawMesh(new Float32Array(sakura[l-8]),gl.LINE_LOOP);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					   M.translate(0.2, .7, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   M.rotateZ(sin(uTime/6) + 0.2);
 | 
				
			||||||
 | 
					   M.scale(0.4);
 | 
				
			||||||
 | 
					      for(let i = 0; i < 10; i++){
 | 
				
			||||||
 | 
					         M.scale(0.995);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					         setM(M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         for(let l = 8; l < 13; ++l)
 | 
				
			||||||
 | 
					            drawMesh(new Float32Array(sakura[l-8]),gl.LINE_LOOP);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					   M.translate(.7, .7, 0);
 | 
				
			||||||
 | 
					   M.rotateZ(sin(uTime/6) + 0.2);
 | 
				
			||||||
 | 
					   M.scale(0.6);
 | 
				
			||||||
 | 
					      for(let i = 0; i < 10; i++){
 | 
				
			||||||
 | 
					         M.scale(0.995);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					         setM(M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         for(let l = 8; l < 13; ++l)
 | 
				
			||||||
 | 
					            drawMesh(new Float32Array(sakura[l-8]),gl.LINE_LOOP);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   M.restore()
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					   M.translate(0,-3.155,0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   M.rotateX(pi/2);
 | 
				
			||||||
 | 
					   M.scale(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   setM(matrix_multiply(sRotation,matrix_multiply(overall_ground,M.value())));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   drawMesh(squareMesh);
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   if(positionsupdated)
 | 
				
			||||||
 | 
					      updatePositions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 //  setM(M.value());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					//pjsk.play();
 | 
				
			||||||
@ -0,0 +1,454 @@
 | 
				
			|||||||
 | 
					//Header file, contains global variable definitions, 
 | 
				
			||||||
 | 
					// asynchronized shader loading and utility functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mousedx = 0, mousedy = 0, mousedz = 0;
 | 
				
			||||||
 | 
					let seldx = 0, seldy = 0, seldz = 0;
 | 
				
			||||||
 | 
					var enableSelection = false;
 | 
				
			||||||
 | 
					var cx = 1, cy = 1, sx = 0, sy = 0;
 | 
				
			||||||
 | 
					var mouselastX, mouselastY;
 | 
				
			||||||
 | 
					var fl = 3;
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					var vs, fs;
 | 
				
			||||||
 | 
					var bezierMat = [-1,3,-3,1,3,-6,3,0,-3,3,0,0,1,0,0,0], 
 | 
				
			||||||
 | 
					    hermiteMat = [2,-3,0,1,-2,3,0,0,1,-2,1,0,1,-1,0,0];
 | 
				
			||||||
 | 
					var starColors = [0.9921, 0.5378,0.7109,
 | 
				
			||||||
 | 
					                    0.65, 0.56, 0.992,
 | 
				
			||||||
 | 
					                    0.992,0.7994,0.2402,
 | 
				
			||||||
 | 
					                    0.1760,0.5094,0.5378,
 | 
				
			||||||
 | 
					                    .1164, .1274, .2289,
 | 
				
			||||||
 | 
					                    .9784,.71,.4482,
 | 
				
			||||||
 | 
					                ], n_shapes = starColors.length/3;
 | 
				
			||||||
 | 
					var editor = undefined
 | 
				
			||||||
 | 
					var cos = Math.cos, sin = Math.sin, tan = Math.tan,
 | 
				
			||||||
 | 
					    acos = Math.acos, asin = Math.asin, atan = Math.atan,
 | 
				
			||||||
 | 
					    sqrt = Math.sqrt, pi = Math.PI, abs = Math.abs;
 | 
				
			||||||
 | 
					var positionsupdated = true;
 | 
				
			||||||
 | 
					var paths = [], origpath= [];
 | 
				
			||||||
 | 
					let vsfetch = new XMLHttpRequest(); 
 | 
				
			||||||
 | 
					vsfetch.open('GET', './shader.vert');
 | 
				
			||||||
 | 
					vsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    vs = vsfetch.responseText;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					vsfetch.send();
 | 
				
			||||||
 | 
					//* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					let fsfetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					fsfetch.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					fsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    fs = (fsfetch.responseText);
 | 
				
			||||||
 | 
					    //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					    if (editor != undefined)
 | 
				
			||||||
 | 
					        editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					fsfetch.send();
 | 
				
			||||||
 | 
					let pathFetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					pathFetch.open('GET', './paths.txt');
 | 
				
			||||||
 | 
					pathFetch.onloadend = function () {
 | 
				
			||||||
 | 
					    let text = pathFetch.responseText;
 | 
				
			||||||
 | 
					    let currX = 0, currY = 0, maxX = -1000, maxY = -1000, minX = 1000, minY = 1000;
 | 
				
			||||||
 | 
					    var currShape = [], currCurve = [];
 | 
				
			||||||
 | 
					    let i = 0;
 | 
				
			||||||
 | 
					    let postProcess = () => {
 | 
				
			||||||
 | 
					        if(currShape.length){
 | 
				
			||||||
 | 
					            let spanX = maxX - minX;
 | 
				
			||||||
 | 
					            let spanY = maxY - minY;
 | 
				
			||||||
 | 
					            let span = Math.max(spanX, spanY);
 | 
				
			||||||
 | 
					            for (var k = 0; k < currShape.length; ++k) {
 | 
				
			||||||
 | 
					                let funcs = [];
 | 
				
			||||||
 | 
					                const curve = currShape[k];
 | 
				
			||||||
 | 
					                for (let j = 0; j < curve.length; j += 2){
 | 
				
			||||||
 | 
					                    curve[j] = (curve[j] - minX) / span-spanX/(span*2);
 | 
				
			||||||
 | 
					                    curve[j + 1] = (curve[j + 1] - minY) / span - spanY/(span*2);
 | 
				
			||||||
 | 
					                    origpath.push(1,curve[j], curve[j+1],0,0,0,1);
 | 
				
			||||||
 | 
					                    if(j%6==0 && j > 5){
 | 
				
			||||||
 | 
					                        let X = [], Y = [];
 | 
				
			||||||
 | 
					                        for(let k = j - 6; k <= j+1; k += 2){
 | 
				
			||||||
 | 
					                            X.push(curve[k]);
 | 
				
			||||||
 | 
					                            Y.push(curve[k+1]);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                        funcs.push([matrix_multiply(bezierMat, X), 
 | 
				
			||||||
 | 
					                                    matrix_multiply(bezierMat, Y)]);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                paths.push(funcs);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let read_num = () =>{
 | 
				
			||||||
 | 
					        let num = 0, sign = 1, accepted = 0;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        while(i < text.length && (text[i] <'0' || text[i] > '9') && text[i]!='-') ++i;
 | 
				
			||||||
 | 
					        if(text[i] == '-')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            sign = -1;
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while(i < text.length&&text[i] >= '0' && text[i] <= '9'){
 | 
				
			||||||
 | 
					            let n = text[i++] - '0';
 | 
				
			||||||
 | 
					            accepted *= 10;
 | 
				
			||||||
 | 
					            accepted += n;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        num += accepted;
 | 
				
			||||||
 | 
					        if(text[i] == '.'){
 | 
				
			||||||
 | 
					            i++;
 | 
				
			||||||
 | 
					            let multiplier = 0.1;
 | 
				
			||||||
 | 
					            accepted = 0;
 | 
				
			||||||
 | 
					            while(i < text.length&&text[i] >= '0' && text[i] <= '9'){
 | 
				
			||||||
 | 
					                let n = text[i++] - '0';
 | 
				
			||||||
 | 
					                accepted += n * multiplier;
 | 
				
			||||||
 | 
					                multiplier /= 10;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            num += accepted;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return num * sign;
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					    let cRevs = [], c_idx = 0, prevX = 0, prevY = 0, getC = ()=>{
 | 
				
			||||||
 | 
					        return cRevs[c_idx--];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let get_next = (delta = false) => {
 | 
				
			||||||
 | 
					        if(delta){
 | 
				
			||||||
 | 
					            currX = prevX + read_num();
 | 
				
			||||||
 | 
					            currY = prevY + read_num();
 | 
				
			||||||
 | 
					        }else{
 | 
				
			||||||
 | 
					            currX = read_num();
 | 
				
			||||||
 | 
					            currY = read_num();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        maxX = currX > maxX? currX:maxX;
 | 
				
			||||||
 | 
					        maxY = currY > maxY? currY:maxY;
 | 
				
			||||||
 | 
					        minX = currX < minX? currX:minX;
 | 
				
			||||||
 | 
					        minY = currY < minY? currY:minY;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        currCurve.push(currX);
 | 
				
			||||||
 | 
					        currCurve.push(currY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while( i < text.length ){
 | 
				
			||||||
 | 
					        if(text[i] == 'z'){
 | 
				
			||||||
 | 
					            currCurve.length && currShape.push(currCurve);
 | 
				
			||||||
 | 
					            currCurve = [];
 | 
				
			||||||
 | 
					            ++i
 | 
				
			||||||
 | 
					        } else if (text[i] == 'N'){
 | 
				
			||||||
 | 
					            postProcess();
 | 
				
			||||||
 | 
					            currShape = [];
 | 
				
			||||||
 | 
					            maxX = -1000, maxY = -1000, minX = 1000, minY = 1000;
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					        } else if (text[i] == 'c'){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            prevX = currX;
 | 
				
			||||||
 | 
					            prevY = currY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for(let j = 0; j < 3; ++j){
 | 
				
			||||||
 | 
					                get_next(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (text[i] == 'C'){
 | 
				
			||||||
 | 
					            for(let j = 0; j < 3; ++j){
 | 
				
			||||||
 | 
					                get_next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (text[i] == 'M'){
 | 
				
			||||||
 | 
					            get_next();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else ++i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					pathFetch.send();
 | 
				
			||||||
 | 
					let matrix_inverse = src => {
 | 
				
			||||||
 | 
					    let dst = [], det = 0, cofactor = (c, r) => {
 | 
				
			||||||
 | 
					       let s = (i, j) => src[c+i & 3 | (r+j & 3) << 2];
 | 
				
			||||||
 | 
					       return (c+r & 1 ? -1 : 1) * ( (s(1,1) * (s(2,2) * s(3,3) - s(3,2) * s(2,3)))
 | 
				
			||||||
 | 
					                                   - (s(2,1) * (s(1,2) * s(3,3) - s(3,2) * s(1,3)))
 | 
				
			||||||
 | 
					                                   + (s(3,1) * (s(1,2) * s(2,3) - s(2,2) * s(1,3))) );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (let n = 0 ; n < 16 ; n++) dst.push(cofactor(n >> 2, n & 3));
 | 
				
			||||||
 | 
					    for (let n = 0 ; n <  4 ; n++) det += src[n] * dst[n << 2];
 | 
				
			||||||
 | 
					    for (let n = 0 ; n < 16 ; n++) dst[n] /= det;
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// I HAVE IMPLEMENTED THESE FUNCTIONS FOR YOU
 | 
				
			||||||
 | 
					let matrix_identity = () => {
 | 
				
			||||||
 | 
					    return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_translate = (x, y, z) => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[12] = x;
 | 
				
			||||||
 | 
					    m[13] = y;
 | 
				
			||||||
 | 
					    m[14] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_perspective = (m) => {
 | 
				
			||||||
 | 
					    let ret = []
 | 
				
			||||||
 | 
					    for (let i = 0; i < 16; i ++)
 | 
				
			||||||
 | 
					        ret[i] = m[i];
 | 
				
			||||||
 | 
					    for (let i = 2; i < 15; i += 4)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ret[i] = -ret[i]; 
 | 
				
			||||||
 | 
					        ret[i+1] += ret[i]/fl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// YOU NEED TO PROPERLY IMPLEMENT THE FOLLOWING FIVE FUNCTIONS:
 | 
				
			||||||
 | 
					let matrix_rotateX = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    m[6] = sin(theta);
 | 
				
			||||||
 | 
					    m[9] = -sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let matrix_rotateY = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[2] = -sin(theta);
 | 
				
			||||||
 | 
					    m[8] = sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_rotateZ= theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[1] = sin(theta);
 | 
				
			||||||
 | 
					    m[4] = -sin(theta);
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_scale = (x, y, z) => {
 | 
				
			||||||
 | 
					    if (y === undefined)
 | 
				
			||||||
 | 
					        y = z = x;
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = x;
 | 
				
			||||||
 | 
					    m[5] = y;
 | 
				
			||||||
 | 
					    m[10] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_multiply = (a, b, m = 4, n = 4) => { //dim=mn*nm=mm
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    if (b.length < m*n) { //mat-vec multiply (i did this for my convenience)
 | 
				
			||||||
 | 
					        for (let i = 0; i < m; ++i) {
 | 
				
			||||||
 | 
					            res[i] = 0;
 | 
				
			||||||
 | 
					            for (let j = 0; j < n; ++j)
 | 
				
			||||||
 | 
					                res[i] += b[j] * a[m * j + i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    } //otherwise mm multiply
 | 
				
			||||||
 | 
					    for (let i = 0; i < m; ++i)
 | 
				
			||||||
 | 
					        for (let j = 0; j < m; ++j) {
 | 
				
			||||||
 | 
					            var t = 0;
 | 
				
			||||||
 | 
					            for (let k = 0; k < n; ++k)
 | 
				
			||||||
 | 
					                t += a[k * m + j] * b[i * n + k];
 | 
				
			||||||
 | 
					            res.push(t);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let const_multiply = (c, a) => {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++ i)
 | 
				
			||||||
 | 
					        m[i] = a[i] * c;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function dot(a, b){
 | 
				
			||||||
 | 
					    let m = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m += a[i] * b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function plus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] + b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function minus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] - b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function normalize(v){
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    sum = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        sum += v[i] * v[i];
 | 
				
			||||||
 | 
					    sum = sqrt(sum);
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        res[i] = v[i] / sum;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let Matrix = function() {
 | 
				
			||||||
 | 
					    let top = 0, m = [ matrix_identity() ];
 | 
				
			||||||
 | 
					    this.identity = () => m[top] = matrix_identity();
 | 
				
			||||||
 | 
					    this.translate = (x,y,z) => m[top] = matrix_multiply(m[top], matrix_translate(x,y,z));
 | 
				
			||||||
 | 
					    this.rotateX = theta     => m[top] = matrix_multiply(m[top], matrix_rotateX(theta));
 | 
				
			||||||
 | 
					    this.rotateY = theta     => m[top] = matrix_multiply(m[top], matrix_rotateY(theta));
 | 
				
			||||||
 | 
					    this.rotateZ = theta     => m[top] = matrix_multiply(m[top], matrix_rotateZ(theta));
 | 
				
			||||||
 | 
					    this.scale   = (x,y,z)   => m[top] = matrix_multiply(m[top], matrix_scale(x,y,z));
 | 
				
			||||||
 | 
					    this.value   = ()        => m[top];
 | 
				
			||||||
 | 
					    this.save    = ()        => { m[top+1] = m[top].slice(); top++; }
 | 
				
			||||||
 | 
					    this.restore = ()        => --top;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let setM = (m) => {
 | 
				
			||||||
 | 
					    let mm = matrix_perspective(m);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'uMatrix', false, mm);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'invMatrix', false, matrix_inverse(m));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 //------ CREATING MESH SHAPES
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 // CREATE A MESH FROM A PARAMETRIC FUNCTION
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let createMesh = (nu, nv, f, data, oid = 0) => {
 | 
				
			||||||
 | 
					    let tmp = [];
 | 
				
			||||||
 | 
					    for (let v = 0 ; v < 1 ; v += 1/nv) {
 | 
				
			||||||
 | 
					       for (let u = 0 ; u <= 1 ; u += 1/nu) {
 | 
				
			||||||
 | 
					          tmp = tmp.concat(f(u,v,oid,data));
 | 
				
			||||||
 | 
					          tmp = tmp.concat(f(u,v+1/nv,oid,data));
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       tmp = tmp.concat(f(1,v,oid,data));
 | 
				
			||||||
 | 
					       tmp = tmp.concat(f(0,v+1/nv,oid,data));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new Float32Array(tmp);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 // GLUE TWO MESHES TOGETHER INTO A SINGLE MESH
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let glueMeshes = (a, b) => {
 | 
				
			||||||
 | 
					    let c = [];
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < a.length ; i++)
 | 
				
			||||||
 | 
					       c.push(a[i]);                           // a
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					       c.push(a[a.length - VERTEX_SIZE + i]);  // + last vertex of a
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					       c.push(b[i]);                           // + first vertex of b
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < b.length ; i++)
 | 
				
			||||||
 | 
					       c.push(b[i]);                           // + b
 | 
				
			||||||
 | 
					    return new Float32Array(c);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToSphere = (u,v, i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let phi   = Math.PI * (v - .5);
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let z = Math.sin(phi);
 | 
				
			||||||
 | 
					    return [i, x,y,z].concat(normalize([x, y, z]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToTube = (u,v,i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta);
 | 
				
			||||||
 | 
					    let z = 2 * v - 1;
 | 
				
			||||||
 | 
					    return [i,x,y,z].concat(normalize([x,y,0]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToDisk = (u,v,i,dz) => {
 | 
				
			||||||
 | 
					    if (dz === undefined)
 | 
				
			||||||
 | 
					       dz = 0;
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * v;
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * v;
 | 
				
			||||||
 | 
					    let z = dz;
 | 
				
			||||||
 | 
					    return [i,x,y,z].concat([0,0,Math.sign(z)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 let uvToTorus = (u,v,i,r) => {
 | 
				
			||||||
 | 
					    let theta = 2 * pi;
 | 
				
			||||||
 | 
					    let phi = theta * v;
 | 
				
			||||||
 | 
					    theta *= u;
 | 
				
			||||||
 | 
					    let x = 1 + r * cos(phi);
 | 
				
			||||||
 | 
					    let y = sin(theta)*x;
 | 
				
			||||||
 | 
					    x *=cos(theta);
 | 
				
			||||||
 | 
					    let z = r * sin(phi);
 | 
				
			||||||
 | 
					    let tx = -sin(theta), ty = cos(theta),tsx = sin(phi), tsy = tsx*tx, tsz = cos(phi);
 | 
				
			||||||
 | 
					    tsx*=-ty;
 | 
				
			||||||
 | 
					    return [i,x, y, z].concat(normalize([ty*tsz*0.5, -tx*tsz, tx*tsy-ty*tsx]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createCube = (w, h, l,id) => {
 | 
				
			||||||
 | 
					    let mesh = [];
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,0,1,0]);
 | 
				
			||||||
 | 
					    return new Float32Array(mesh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					function updatePositions() {
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    setUniform('3f', 'V0', m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz));
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    setUniform('Matrix3fv', 'transformation', false, [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]);
 | 
				
			||||||
 | 
					    positionsupdated = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest(pos){
 | 
				
			||||||
 | 
					    if(!enableSelection)
 | 
				
			||||||
 | 
					        return -1; 
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    let V = [m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz)];
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    let trPos = matrix_multiply([m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]], pos, 3,3);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    let W=normalize(minus(trPos, V));
 | 
				
			||||||
 | 
					    let tMin=10000.;
 | 
				
			||||||
 | 
					    let iMin = -1;
 | 
				
			||||||
 | 
					    for(let i=0;i<cns;i++){
 | 
				
			||||||
 | 
					    let Vp=minus(V, matrix_multiply(SphTr[i], Sph[i]));
 | 
				
			||||||
 | 
					    let B=dot(W,Vp);
 | 
				
			||||||
 | 
					    let C=dot(Vp,Vp)-Sph[i][4]*Sph[i][4];
 | 
				
			||||||
 | 
					    let D=B*B-C;
 | 
				
			||||||
 | 
					    if(D>0.){
 | 
				
			||||||
 | 
					       let t=-B-sqrt(D);
 | 
				
			||||||
 | 
					       if(t > 0.0 && t < tMin){
 | 
				
			||||||
 | 
					          tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					          iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return iMin;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
@ -0,0 +1,214 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					var ns = 0, cns = 0;
 | 
				
			||||||
 | 
					fragmentShaderHeader+= 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					var fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;   
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					     bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   } 
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let texture = [], gl, program;
 | 
				
			||||||
 | 
					let textures = []; 
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					   console.log('glstart');
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = 'In Spring Break We Did Homeworks.';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader +fragmentShaderDefs+ fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; ++i){
 | 
				
			||||||
 | 
					            loadTexture(gl, './'+(i+1)+'.jpg', i); //Texture loading.
 | 
				
			||||||
 | 
					            textures[i] = i;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
 | 
				
			||||||
 | 
					         positionsupdated = true;
 | 
				
			||||||
 | 
					         let attribs = [
 | 
				
			||||||
 | 
					            .05,.05,.1,  .5,.5,1.,  1.,.5,.5,20.,  0., .0, 1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  1.,.5,.5,  1.,.5,.5,10.,  .3,1.,1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  .71,.71,.71,  .71,.71,.71,10.,  0.3,.0,1.5,
 | 
				
			||||||
 | 
					            .1,.1,.1,  .71,.71,.71,  .71,.71,.71,10.,  0.05,0., 1.,
 | 
				
			||||||
 | 
					            .0,.0,.0,  .0,.0,.0,  .0,.0,.0,40.,  0.,.85,1.5
 | 
				
			||||||
 | 
					         ]
 | 
				
			||||||
 | 
					         var offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Ambient['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Diffuse['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('4fv', 'Specular['+i+']', attribs.slice(offset, offset += 4));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'ks['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kr['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kf['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < n_shapes; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'starColors['+i+']', starColors.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         // gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					         //    [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					         gl.enable(gl.DEPTH_TEST);
 | 
				
			||||||
 | 
					         gl.depthFunc(gl.LEQUAL);
 | 
				
			||||||
 | 
					         gl.clearDepth(-1);
 | 
				
			||||||
 | 
					         let oid = gl.getAttribLocation(program, 'oid');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(oid);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(oid, 1, gl.FLOAT, false, 4*7, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 4*7, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let normal = gl.getAttribLocation(program, 'normal');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(normal);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(normal, 3, gl.FLOAT, false, 4*7, 4*4);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         //gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   if(gl)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					      (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//let VERTEX_SIZE = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let VERTEX_SIZE = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let drawMesh = (mesh, func = gl.TRIANGLE_STRIP) => {
 | 
				
			||||||
 | 
					   gl.bufferData(gl.ARRAY_BUFFER, mesh, gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					   gl.drawArrays(func, 0, mesh.length / VERTEX_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					M11.02,39.45c-2.67-2.97-5.37-5.93-8.01-8.94c-2.42-2.76-2.92-5.66-1.11-8.78c0.81-1.39,1.97-2.41,3.65-2.76
 | 
				
			||||||
 | 
					c3.9-0.82,7.78-1.71,11.67-2.56c0.86-0.19,1.5-0.51,1.99-1.38c1.9-3.42,3.92-6.76,5.89-10.14c2.6-4.46,9.11-4.47,11.71-0.04
 | 
				
			||||||
 | 
					c1.98,3.37,3.99,6.72,5.89,10.14c0.48,0.86,1.08,1.23,1.96,1.42c3.94,0.85,7.88,1.68,11.81,2.6c2.44,0.57,3.73,2.34,4.36,4.65
 | 
				
			||||||
 | 
					c0.77,2.82-0.27,5.08-2.16,7.14c-2.52,2.74-4.97,5.53-7.44,8.32c-0.18,0.2-0.41,0.49-0.38,0.72c0.18,1.94,0.41,3.87,0.63,5.8
 | 
				
			||||||
 | 
					c0.12,1.04,0.33,2.07,0.36,3.11c0.05,1.93,0.55,3.8,0.17,5.81c-0.65,3.42-4.81,6.08-8.02,4.95c-1.83-0.64-3.65-1.36-5.44-2.11
 | 
				
			||||||
 | 
					c-2.24-0.94-4.48-1.89-6.67-2.95c-0.75-0.36-1.36-0.27-2.02,0.03c-2.75,1.22-5.47,2.48-8.24,3.66c-1.3,0.56-2.64,1.08-4.01,1.43
 | 
				
			||||||
 | 
					c-2.45,0.63-4.53-0.26-6.14-2.08c-1.65-1.86-2.05-4.09-1.55-6.54c0.26-1.25,0.25-2.55,0.37-3.83
 | 
				
			||||||
 | 
					C10.52,44.62,10.77,42.12,11.02,39.45z M56.81,25.75c0.02-1.65-1.04-2.64-2.79-3.01c-4.04-0.84-8.06-1.74-12.1-2.57
 | 
				
			||||||
 | 
					c-0.91-0.19-1.58-0.65-2.04-1.42c-0.98-1.64-1.93-3.29-2.89-4.93c-1.32-2.26-2.6-4.55-3.98-6.77c-1.12-1.79-2.96-1.74-4.13,0.04
 | 
				
			||||||
 | 
					c-0.65,0.99-1.23,2.04-1.83,3.07c-1.66,2.84-3.32,5.68-4.97,8.52c-0.48,0.83-1.17,1.32-2.14,1.5c-1.82,0.34-3.62,0.74-5.42,1.14
 | 
				
			||||||
 | 
					c-2.45,0.54-4.92,1.04-7.34,1.68C5,23.57,4.46,25.5,5.92,27.15c1.64,1.85,3.31,3.69,4.95,5.54c1.33,1.5,2.68,2.97,3.92,4.54
 | 
				
			||||||
 | 
					c0.38,0.48,0.61,1.21,0.61,1.82c0.01,1.33-0.17,2.65-0.29,3.98c-0.09,0.99-0.19,1.98-0.3,2.97c-0.26,2.26-0.58,4.51-0.77,6.78
 | 
				
			||||||
 | 
					c-0.05,0.52,0.18,1.14,0.48,1.59c0.8,1.19,1.9,1.37,3.54,0.65c3.75-1.66,7.49-3.32,11.22-5.02c1.06-0.48,2.04-0.61,3.13-0.1
 | 
				
			||||||
 | 
					c1.94,0.92,3.9,1.78,5.86,2.65c2.05,0.91,4.11,1.78,6.15,2.69c0.93,0.42,1.77,0.3,2.52-0.37c0.76-0.68,1.19-1.49,0.83-2.55
 | 
				
			||||||
 | 
					c-0.08-0.22-0.12-0.46-0.14-0.7c-0.21-2.51-0.38-5.02-0.61-7.53c-0.12-1.32-0.38-2.63-0.51-3.95c-0.11-1.09-0.17-2.16,0.7-3.09
 | 
				
			||||||
 | 
					c1.83-1.95,3.6-3.95,5.37-5.94c1.23-1.39,2.46-2.79,3.64-4.22C56.54,26.51,56.69,25.99,56.81,25.75z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M66.36,818.02c-106.2-110.9-61-662.8-36.4-813.56c71.19,1.55,58.77-12.26,72.22,57.92c12.21-15.09,10.15-62.97,37.19-55.8
 | 
				
			||||||
 | 
					c-11.66,49.82-40.93,95.92-1.62,142.63c15.22,3.36,56.55-137.38,59.66-136.45c2.49,0.74-22.25,91.36-42.07,162.69
 | 
				
			||||||
 | 
					c8.65,35.12,58.93,87.86,92.29,98.19c14.23-79.7,33.22-361.27,73.99-244.33c41.13-55.27-7.85,38.44-11.46,55.28
 | 
				
			||||||
 | 
					c-18.92,98.99-27.77,241.63,53.45,119.52c20.21-34.31,20.1-114.01,53.68-126.53c3.84-12.82,10.48-73.87,24.02-73.1
 | 
				
			||||||
 | 
					c12.83-0.56,65.91-1.83,35.15,7.41c-61.79-15.5-48.75,200.28-45.07,243.92c2.25,20.42,27.14,13.8,38.12,25.45
 | 
				
			||||||
 | 
					c6.03,4.39,36.44,27.66,18.27,21.91c-40.8-27.63-66.71-54.35-46.2,16.36c-19.89-38.23,1.59-50.13-50.98-60.73
 | 
				
			||||||
 | 
					c8.31-2.96,35.82,10.04,30.87-4.68c-5.47-26.59-6.9-54.75-14.96-80.46c-22.25,80.4-137.99,191.25-134.59,255.33
 | 
				
			||||||
 | 
					c28.43-24.91,73.72-62.68,120.64-46.55c78.08,7.49,7.79-16.2-21.17-22.89c25.68-8.32,88.81,23.09,96.53,50.48
 | 
				
			||||||
 | 
					c-14.88-13.87-8.97-8.07-4.72,6.57c-20.12-14.39-11.58-35.73-44.46-26.75c28.79,18.11,36.81,27.82,49.27,59.28
 | 
				
			||||||
 | 
					c-15.78,0.19,5.06,35.44-28.02-9.3c-39.56-53.22-130.39-50.05-158.76,12.21c-0.57,107.56,60.34,213.63,68.06,323.78
 | 
				
			||||||
 | 
					c1.71,10.93,25.65,17.02,33.27,28.59c-11.57-2.96-19.66-12.97-31.03-16.47c-1.22,193.89-65.94,75.43,75.87,233.86
 | 
				
			||||||
 | 
					c-37.15-15.29-59.1-63.14-92.21-88.24c-15.18-7.04-28.22,43.71-46.26,43.68c57.38-81.24-1.81-123.16,10.19-218.4
 | 
				
			||||||
 | 
					c8.56,76.16-24.52,144.42-59.52,208.52c-8.14,12.44,0.12,54.47-13.87,54.44c9.71-16.15,13.17-61.15-18.44-81.22
 | 
				
			||||||
 | 
					C166.51,916.66,113.43,878.18,66.36,818.02z M925.87,407.64c-54.74-44.89,19.53-197.95-29.21-257.87
 | 
				
			||||||
 | 
					c-7.8,0.23,0.01,139.34-12.78,138.06c-0.76-11.74,2.94-57.56-13.24-57.45c-12.13,43.49-18.05,56.87-20.76,56.35
 | 
				
			||||||
 | 
					c-3.44-0.66-1.37-22.36-9.37-26.3c-1.4-0.69-3.39-0.47-6.27,1.08c-37.75,31.13-5.8-23.15-21.95-34.81
 | 
				
			||||||
 | 
					c-10.77-4.3-7.19,51.51-13.81,37.09c-6.3-84.43-23.11-192.91-70.65-258.62c15.21,86.12,50.46,187.09,38.31,278.79
 | 
				
			||||||
 | 
					c-21.94-86.63-52.72-175.52-70.62-266.49c2.29-9.8-18.19-21-13.94-4.4c30.28,57.1,21.26,334.09,14.6,185.12
 | 
				
			||||||
 | 
					c-1.5-9.87,2.15-67.2-7.12-67.14c-2.9,30.13-5.79,60.27-8.69,90.4c-32.81-59.32-16.97-176.63-52.31-212.83
 | 
				
			||||||
 | 
					c11.12,94.4-6.13,188.39-24.34,280.85c3.07-43.88,20.04-96.61,8.43-137.16c-6.3,14.9-20.93,66.96-26.59,61.57
 | 
				
			||||||
 | 
					c-8.59-0.89-9.05-48.09-14.45-48.15c-3.39-0.04-6.04,18.34-7.95,31.07c-7.59,50.46-15.93,93.98-17.18,93.85
 | 
				
			||||||
 | 
					c8.57-40.75,5.67-198.5-18.91-251.56c4.95,62.89-1.02,125.94-10.23,188.11c3.54-69.31,13.94-164.75-15.9-222.74
 | 
				
			||||||
 | 
					c32.11,126.08-28.75,489.29,30.52,197.35c28.79,98.72-65.28,261.35,58.73,108.86c-37.19,187.32,36.13-32.28,47.76-103.08
 | 
				
			||||||
 | 
					c8.96,94.67-2.01-42.55,6.66-79.88c30.75,97.92,53.06,199.4-5.06,292.92C737.6,336.4,694.28,5.48,752.2,275.59
 | 
				
			||||||
 | 
					c12.58,35.83-30.59,24.88-39.09,50.66c61.29-24.55,38.95-35.44,52.83,53.39c0.4,3.52-0.24,7.19-4.7,7.28
 | 
				
			||||||
 | 
					c-25.86,1.03-45.18,18.23-57.25,38.9c13.43-3.39,50.98-46.17,61.23-33.44c-21.97,29.52-78.97,40.99-72.67,90.22
 | 
				
			||||||
 | 
					c3.55-15.72,78.25-89.59,75.21-54.58c-1.37,4.97-0.6,13.02-7.63,13.72c-61.1,2.32-80.25,119.34-40.63,125.28
 | 
				
			||||||
 | 
					c-13.21-11.3-15.2-27.18-9.08-34.25c7.41-8.57,27.36-4.95,29.07,0.51c0.78,2.5-2.15,5.13-0.96,7.46c0.58,1.13,2.72,1.77,8.48,1.56
 | 
				
			||||||
 | 
					c38.89-7.77,7.11,28.36-12.62,33.66c17.65,7.15,41.53-6.09,43.26-25.21c-13.61-10.4-3.01-29.64,12.23-22.19
 | 
				
			||||||
 | 
					c39.17-39.2-23.35-78.46-17.83-98.65c2.53-4.97,11.94-9.86,47.83-3.67c17.2,5.95,27.38,81.41,34.69,33.83
 | 
				
			||||||
 | 
					c26.79,65.65,1.08,95.95-22.65,157.49c-19.8,84.29-61.4,159.4-148.77,185.06c-117.87,55.02-132.92,97.58-258.09,25.2
 | 
				
			||||||
 | 
					c46.48,32.06,76.67,55,136.6,42.95c-16.18,37.26-58.98,60.98-65.42,102.39c20.1-25.76,40.19-51.51,60.29-77.27
 | 
				
			||||||
 | 
					c-8.67,85.19,10.27,58.11-48.65,125.91c90.48-25.72,17.5-180.83,122.56-177.14c18.96,52.7-4.18,120.02,8.63,173.54
 | 
				
			||||||
 | 
					c2.68-39.19,12.24-88.12,46.19-106.21c456.17,81.79,348.93-736.88,256.65-896.72c22.97,42.24,68.59,278.45,36,201.55
 | 
				
			||||||
 | 
					c-3.91-9.81-16.93-10.42-12.04,2.06c-3.92,64.31,14.29,179.15-11.75,192.94z M348.31,563.23c5.68,9.7,20.47-3.9,12.83-8.26c-3.76-6.73-7.6-13.49-12.17-19.69
 | 
				
			||||||
 | 
					c-8.79-11.93,9.75-6.48,8.3-13.53c21.55,9.97,28.08,14.2,46.14-5.3c-0.61,18.31-0.16,38.03-18.36,50.23
 | 
				
			||||||
 | 
					c18.72,10.53,30.46-6.95,33.62-24.89c-25.93,2.12,1.38-48.33,8.9-22.45c7.53-11.49,6.87-26.71,9.65-39.21
 | 
				
			||||||
 | 
					C420.8,350.18,268.58,459.17,348.31,563.23z M517.13,804.37c-10.18-5.07-29.37-7.14-13.37-22.49
 | 
				
			||||||
 | 
					c18.15-20.96,102.96-23.38,73.03,12.59c29.3-17.57-7.7-35.22-30.46-31.69C518.69,758.1,459.7,799.43,517.13,804.37z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M106.8,0c-3.3,4.6-6.3,9.4-8.8,14.5c-2.8-5-5.7-9.8-8.8-14.5C52.9,32.5,56.8,74.2,98,99.6c0,0,0,0,0,0c0,0,0,0,0,0C139.5,74,142.9,32.2,106.8,0z M5.4,60.7c3.7,4.5,7.4,8.8,11,12.8c-5.4,1-10.9,2.3-16.5,3.9 c19.6,44.6,60.5,53.8,97.4,22.5c0,0,0,0,0,0c0,0,0,0,0,0C85.9,52.4,47.2,36.3,5.4,60.7z M31.2,174.9c5.3-1.5,10.5-3.8,15.6-6.6c-0.8,5.7-1.2,11.3-1.4,16.8c48.5-4.9,69.9-40.9,51.5-85.7c0,0,0,0-0.1,0c0,0,0,0,0,0C48.2,95.8,20.9,127.6,31.2,174.9zM148.3,186.1c-0.4-5.5-0.9-11.1-1.4-16.8c5.1,2.4,10.3,4.6,15.6,6.6c10.4-47.6-17.3-79.1-65.6-75.5c0,0,0,0,0,0c0,0-0.1,0-0.1,0C78.3,145.5,100.1,181.3,148.3,186.1z M195.1,76.9c-5.9-1.5-11.5-2.9-16.5-3.9c3.9-4,7.6-8.3,11-12.8c-42.1-24.6-80.6-8-92.1,39.1c0,0,0,0,0,0c0,0,0,0,0,0C134.9,130.9,175.6,121.2,195.1,76.9z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M35.2,14.9c-2.4,0-4.8,1-6.5,2.7c-1.7-1.7-4.1-2.7-6.5-2.7c-5.6,0.2-10,5-9.8,10.6c0,9.7,13.1,17.8,14.6,18.6c1,0.6,2.3,0.6,3.3,0C31.8,43.2,45,35.2,45,25.5C45.2,19.8,40.8,15.1,35.2,14.9z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M140 20C73 20 20 74 20 140c0 135 136 170 228 303 c88-132 229-173 229-303 c0-66-54-120-120-120c-48 0-90 28-109 69c-19-41-60-69-108-69z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					uniform vec3 starColors[10];
 | 
				
			||||||
 | 
					uniform vec3 V0;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 color =foregroundColor.xyz;
 | 
				
			||||||
 | 
					   float sp = 0.4, df = 0.4, amb = 0.4, ex=5.;
 | 
				
			||||||
 | 
					   vec3 l = vec3(1,1,1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(id < 1.5) {color = vec3(0.,1.,0.2034);}
 | 
				
			||||||
 | 
					   else if (id < 2.5) color = vec3(1.,.16,.36);
 | 
				
			||||||
 | 
					   else if (id < 3.5) {color = vec3(1.0000, 0.7725, 0.7725);sp = .5; df=.8; amb = .05;}
 | 
				
			||||||
 | 
					   else if (id < 4.5) {color = vec3(0.9612,0.3057,0.3369);sp = .5; df=.5; amb = .5; ex=20.;}
 | 
				
			||||||
 | 
					   else if (id < 6.5) {}
 | 
				
			||||||
 | 
					   else if (id < 7.5) {color = starColors[0]; sp = 0.3, df = 0.3, amb = 0.8, ex=5.;}
 | 
				
			||||||
 | 
					   else if (id < 8.5) {color = starColors[1]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 9.5) {color = starColors[2]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 10.5) {color = starColors[3]; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 12.5) {color = starColors[4]; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 13.5) {color = starColors[4]*2.; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 14.5) {color = .4*foregroundColor + .8*starColors[4]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 15.5) {color = .3*vec3(0.9612,0.3057,0.3369)+.8*starColors[4]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   if(id < 0.){
 | 
				
			||||||
 | 
					       vec3 P = vec3(sin(glpos.y*1.), sin(glpos.x*1.5+1.),  cos(glpos.z*1.));
 | 
				
			||||||
 | 
					   // APPLY PROCEDURAL NOISE TEXTURE.
 | 
				
			||||||
 | 
					       float cloud = min(0.99, max(0., 1. * noise(1. * P)));
 | 
				
			||||||
 | 
					       color =  (1.-cloud)*color + starColors[5] * cloud*3.;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=normalize(glpos-V);
 | 
				
			||||||
 | 
					   vec3 realLDir=normalize(LDir - glpos);
 | 
				
			||||||
 | 
					   color = color*(amb+ df*max(0.,dot(norm,realLDir)))
 | 
				
			||||||
 | 
					                        + sp*pow(max(0., dot(2.*dot(norm, realLDir)*norm-realLDir, -W)),ex)*l;
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(color), 1.);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					uniform mat4 uMatrix;
 | 
				
			||||||
 | 
					uniform mat4 invMatrix;
 | 
				
			||||||
 | 
					uniform mat3 transformation;
 | 
				
			||||||
 | 
					attribute float oid;
 | 
				
			||||||
 | 
					attribute vec3 aPos;
 | 
				
			||||||
 | 
					attribute vec3 normal;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    vec4 pos = uMatrix * vec4(aPos, 1.);
 | 
				
			||||||
 | 
					    gl_Position = pos ;
 | 
				
			||||||
 | 
					    glpos = pos.xyz;
 | 
				
			||||||
 | 
					    id = oid;
 | 
				
			||||||
 | 
					    norm = normalize(vec4(normal,0.)*invMatrix).xyz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.5 KiB  | 
@ -0,0 +1,105 @@
 | 
				
			|||||||
 | 
					<!--<video src="pjsk.mp4" id="pjsk" muted="muted" loop="true" style="position:fixed; left:0; top:0;max-width:100%;min-width:100%;min-height: 100%;z-index: -100;"></video>-->
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.js" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					<script src=lib7.header.js></script>
 | 
				
			||||||
 | 
					<script src=lib7.js></script>
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					 .ace_gutter-layer {
 | 
				
			||||||
 | 
					   /* original width is 48px */
 | 
				
			||||||
 | 
					   width: 25px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 .ace_gutter-layer > * {
 | 
				
			||||||
 | 
					   /* 48 - 32 = 16 */
 | 
				
			||||||
 | 
					   margin-left: 0;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .ace_gutter-cell {
 | 
				
			||||||
 | 
					  padding-left: 0 !important;
 | 
				
			||||||
 | 
					  padding-right: 3px !important;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 .code{ 
 | 
				
			||||||
 | 
					    font-family: "monaco, menlo, ubuntu mono, consolas, source-code-pro" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					 </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- VERTEX SHADER: YOU PROBABLY DON'T WANT TO CHANGE THIS RIGHT NOW -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: THIS IS WHERE YOU WILL DO YOUR WORK -------->
 | 
				
			||||||
 | 
					<!!-------- FRAGMENT SHADER: MOVED TO ./shader.frag!! LOADED IN lib2.js -------->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<font size=7 color=#909090>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Magician
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img id="rtx" style="float:right;" src="./RTXon.svg" type="image/svg+xml"
 | 
				
			||||||
 | 
					   alt="Turn Ray Tracing On/OFF" title="Turn Ray Tracing On/OFF" height=60px /img>
 | 
				
			||||||
 | 
					<div id="fps" style="font-size:25;float:right;margin-right:18px;"></div>
 | 
				
			||||||
 | 
					<TABLE cellspacing=0 cellpadding=0><TR>
 | 
				
			||||||
 | 
					<td><font color=red size=5><div id=errorMessage></div></font></td>
 | 
				
			||||||
 | 
					</TR><TR>
 | 
				
			||||||
 | 
					<table cellspacing=0>
 | 
				
			||||||
 | 
					<tr>
 | 
				
			||||||
 | 
					<td valign=top>
 | 
				
			||||||
 | 
					<div id="ace" style="opacity:90%;width:800px;height:2200px;"></div>
 | 
				
			||||||
 | 
					</td><td valign=top style="background-color:azure;opacity: 100%;">
 | 
				
			||||||
 | 
					<body bgcolor=white text=black link=black alink=blue vlink=blue>
 | 
				
			||||||
 | 
					   <center>
 | 
				
			||||||
 | 
					      <!!--- SUPER SAMPLING THE W/H PARAMS FOR CANVAS ARE RENDER SIZE, IN THE CSS IS ACTUAL(DISPLAY) SIZE.--->
 | 
				
			||||||
 | 
					   <canvas id='canvas1' style=" background-color:#FFF7F8;opacity: 100%;overflow: hidden !important; width: 600px !important; height:600px !important;" width=1199 height=1199></canvas>
 | 
				
			||||||
 | 
					   </center>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					<div id="controls">
 | 
				
			||||||
 | 
					<input type="number" id="ins" style="display:none;margin-left:0px;font-size:24px;width:35px;height:45px" value="5" max="5" min = "1">
 | 
				
			||||||
 | 
					<button id="bns" style="display:none;margin-left:0px;font-size:24px;width:105px;height:45px">Spheres</button>
 | 
				
			||||||
 | 
					<input type="number" id="insamp" style="margin-left:2px;font-size:24px;width:60px;height:45px" value="2" max="10" min = "0.1" step="0.2">
 | 
				
			||||||
 | 
					<button id="bnsamp" style="margin-left:0px;font-size:24px;width:190px;height:45px">Super Sampling</button>
 | 
				
			||||||
 | 
					<button id="bnfs" style="margin-left:2px;font-size:24px;width:180px;height:45px">Fullscreen</button>
 | 
				
			||||||
 | 
					<button id="clrsel" style="display:none;margin-left:0px;font-size:24px;width:180px;height:45px">Clear Selection</button>
 | 
				
			||||||
 | 
					<button id="reset" style="margin-left:0px;font-size:24px;width:100px;height:45px">Reset</button>
 | 
				
			||||||
 | 
					<button id="mov" style="margin-left:0px;font-size:24px;width:180px;height:45px">Move Lighting</button>
 | 
				
			||||||
 | 
					<button id="pause" style="margin-left:0px;font-size:24px;width:100px;height:45px">Pause</button>
 | 
				
			||||||
 | 
					<div style='font-size:25px;'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <font color=#000000>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					   <i style="font-size:28px;">What's new: </i>
 | 
				
			||||||
 | 
					   <p style="font-size:24px;"> 
 | 
				
			||||||
 | 
					        I made a 3D character with Bezier splines and surface of revolution.<br>
 | 
				
			||||||
 | 
					        Because human body is more complicated than the shapes I've created so far, 
 | 
				
			||||||
 | 
					   I first made up a simple and highly symmetric character and drew it on paper. Then I used the pen tool 
 | 
				
			||||||
 | 
					   in Adobe Illustrator to trace some segments of the contour in my drawing that I can use to create 
 | 
				
			||||||
 | 
					   the 3D mesh by rotating it. The selected paths are in the end of (see <a href="./paths.txt">path.txt</a>)<br>
 | 
				
			||||||
 | 
					        The character is supposed to look like the below image (or <a href="./schema.svg">schema.svg</a>). 
 | 
				
			||||||
 | 
					   It would look much more realistic if I use another spline to make the radius change over u. But this would require 
 | 
				
			||||||
 | 
					   a 3D model, which is hard for me to create.<br>
 | 
				
			||||||
 | 
					   <center><image id="schema" src='./schema.svg'></image></center>
 | 
				
			||||||
 | 
					   </p>
 | 
				
			||||||
 | 
					   <div id="howitworks">
 | 
				
			||||||
 | 
					   <br>
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <p>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div></td>
 | 
				
			||||||
 | 
					</tr></table>
 | 
				
			||||||
 | 
					</TR></TABLE>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!!-------- YOU PROBABLY WANT TO CHANGE ANYTHING BELOW RIGHT NOW -------->
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					<script src="lib7.ext.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					   setInterval(() => {
 | 
				
			||||||
 | 
					      if(window.vs != null && window.fs != null&& canvas1.setShaders === undefined)
 | 
				
			||||||
 | 
					         gl_start(canvas1, vs, fs);
 | 
				
			||||||
 | 
					   }, 200);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -0,0 +1,783 @@
 | 
				
			|||||||
 | 
					let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
 | 
				
			||||||
 | 
					let lastClick = undefined;
 | 
				
			||||||
 | 
					let animating = true;
 | 
				
			||||||
 | 
					let flags = 0x0;
 | 
				
			||||||
 | 
					var uTime = 0, startTime = Date.now();
 | 
				
			||||||
 | 
					let lastTime = Date.now(), rotTime = 0;
 | 
				
			||||||
 | 
					var lastFrameTime = 0;
 | 
				
			||||||
 | 
					let oldDocument;
 | 
				
			||||||
 | 
					let fullscreen = false, btntoggled = false;
 | 
				
			||||||
 | 
					let movescene = true;
 | 
				
			||||||
 | 
					let oldparents = {};
 | 
				
			||||||
 | 
					var tr, div;
 | 
				
			||||||
 | 
					let canvas_originalsize;
 | 
				
			||||||
 | 
					let Sph = [];
 | 
				
			||||||
 | 
					let SphTr = [];
 | 
				
			||||||
 | 
					let SphDletaR = [];
 | 
				
			||||||
 | 
					let selected = false, selection = -1, dragging = false;
 | 
				
			||||||
 | 
					let overall_trans = matrix_identity(), overall_ground;
 | 
				
			||||||
 | 
					let rebuild = true, presentation = true, sRotation = matrix_identity();
 | 
				
			||||||
 | 
					let facing = 1, running = 0;
 | 
				
			||||||
 | 
					let curr_mouse_pos = [-10, -10];
 | 
				
			||||||
 | 
					schema.height=screen.height*.9;
 | 
				
			||||||
 | 
					for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					   SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function ev_supersample(e){
 | 
				
			||||||
 | 
					   let multiplier  = insamp.value;
 | 
				
			||||||
 | 
					   let w = parseInt(canvas1.style.width)*multiplier;
 | 
				
			||||||
 | 
					   let h = parseInt(canvas1.style.height)*multiplier;
 | 
				
			||||||
 | 
					   canvas1.height = h;
 | 
				
			||||||
 | 
					   canvas1.width = w;
 | 
				
			||||||
 | 
					   gl.viewport(0, 0, w, h);
 | 
				
			||||||
 | 
					   //gl.clearRect(0, 0, w, h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function toggleFullscreen(element){
 | 
				
			||||||
 | 
					   if(fullscreen)
 | 
				
			||||||
 | 
					   { 
 | 
				
			||||||
 | 
					      if (document.exitFullscreen) 
 | 
				
			||||||
 | 
					         document.exitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.webkitExitFullscreen) 
 | 
				
			||||||
 | 
					         document.webkitExitFullscreen();
 | 
				
			||||||
 | 
					      else if (document.mozCancelFullScreen) 
 | 
				
			||||||
 | 
					         document.mozCancelFullScreen();
 | 
				
			||||||
 | 
					      else if (document.msExitFullscreen) 
 | 
				
			||||||
 | 
					         document.msExitFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = false;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      if(element.requestFullscreen)
 | 
				
			||||||
 | 
					         element.requestFullscreen();
 | 
				
			||||||
 | 
					      else if (element.webkitRequestFullscreen)
 | 
				
			||||||
 | 
					         element.webkitRequestFullscreen();
 | 
				
			||||||
 | 
					      else if(element.msRequestFullscreen)
 | 
				
			||||||
 | 
					         element.msRequestFullscreen();
 | 
				
			||||||
 | 
					      fullscreen = true;
 | 
				
			||||||
 | 
					      bnfs.innerText = "Exit Fullscreen";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnfs.onclick = function(e){
 | 
				
			||||||
 | 
					   if(e === "no")
 | 
				
			||||||
 | 
					      ;
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      btntoggled = true;
 | 
				
			||||||
 | 
					   if(fullscreen){
 | 
				
			||||||
 | 
					      oldparents[controls].appendChild(controls);
 | 
				
			||||||
 | 
					      oldparents[canvas1].appendChild(canvas1);
 | 
				
			||||||
 | 
					      canvas1.style.width = canvas_originalsize[0];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas_originalsize[1];
 | 
				
			||||||
 | 
					      howitworks.hidden = false;
 | 
				
			||||||
 | 
					   }else{
 | 
				
			||||||
 | 
					      div = document.createElement("div");
 | 
				
			||||||
 | 
					      tr = document.createElement("table").insertRow();
 | 
				
			||||||
 | 
					      tr.style.backgroundColor="white";
 | 
				
			||||||
 | 
					      let size = Math.min(screen.availHeight, screen.availWidth);
 | 
				
			||||||
 | 
					      canvas_originalsize = [canvas1.style.width, canvas1.style.height, canvas1.width, canvas1.height];
 | 
				
			||||||
 | 
					      canvas1.style.height = canvas1.style.width = size;
 | 
				
			||||||
 | 
					      howitworks.hidden=true;
 | 
				
			||||||
 | 
					      oldparents[controls] = controls.parentNode;
 | 
				
			||||||
 | 
					      oldparents[canvas1] = canvas1.parentNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let td1 = tr.insertCell();
 | 
				
			||||||
 | 
					      td1.appendChild(canvas1);
 | 
				
			||||||
 | 
					      let td2;
 | 
				
			||||||
 | 
					      td2 = tr.insertCell();
 | 
				
			||||||
 | 
					      td2.style.verticalAlign="top";
 | 
				
			||||||
 | 
					      td2.appendChild(controls);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      div.appendChild(tr);
 | 
				
			||||||
 | 
					      document.body.appendChild(div);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   toggleFullscreen(div);
 | 
				
			||||||
 | 
					   ev_supersample();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					mov.onclick=function(_){
 | 
				
			||||||
 | 
					   movescene = !movescene;
 | 
				
			||||||
 | 
					   if(!movescene)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mov.innerText= "Move Scene";
 | 
				
			||||||
 | 
					      mov.style.width = "170px";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      mov.innerText = "Move Lighting";
 | 
				
			||||||
 | 
					      mov.style.width = "180px";
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					document.addEventListener("webkitfullscreenchange", ()=>{if(!btntoggled && fullscreen)bnfs.onclick("no");btntoggled = false;});
 | 
				
			||||||
 | 
					document.addEventListener("fullscreenchange", ()=>{if(!btntoggled && fullscreen)bnfs.onclick("no");btntoggled = false;});
 | 
				
			||||||
 | 
					clrsel.onclick=function(_){
 | 
				
			||||||
 | 
					   setUniform("1i", "sel", -1);
 | 
				
			||||||
 | 
					   selected = false;
 | 
				
			||||||
 | 
					   selection = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					reset.onclick = function(_){
 | 
				
			||||||
 | 
					   clrsel.onclick();
 | 
				
			||||||
 | 
					   if(!animating)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   flags = 0;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   mousedx = mousedy = mousedz = 0;
 | 
				
			||||||
 | 
					   positionsupdated = true;
 | 
				
			||||||
 | 
					   for(let i = 0; i < ns; ++i)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      SphTr[i]=matrix_identity();
 | 
				
			||||||
 | 
					      SphDletaR[i] = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bns.onclick=function(e){
 | 
				
			||||||
 | 
					   if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
 | 
				
			||||||
 | 
					   {   
 | 
				
			||||||
 | 
					      cns = ins.value;
 | 
				
			||||||
 | 
					      fragmentShaderDefs = '\n const int cns = ' + cns + ';';
 | 
				
			||||||
 | 
					      if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					         canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bnsamp.onclick=ev_supersample;
 | 
				
			||||||
 | 
					// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
 | 
				
			||||||
 | 
					ace.require("ace/ext/language_tools");
 | 
				
			||||||
 | 
					var editor = ace.edit("ace", {
 | 
				
			||||||
 | 
					   mode:"ace/mode/glsl",
 | 
				
			||||||
 | 
					   theme:"ace/theme/crimson_editor"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setOptions({
 | 
				
			||||||
 | 
					   enableBasicAutocompletion: true,
 | 
				
			||||||
 | 
					   enableSnippets: true,
 | 
				
			||||||
 | 
					   enableLiveAutocompletion: true,
 | 
				
			||||||
 | 
					   fontSize: 14,
 | 
				
			||||||
 | 
					   fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
 | 
				
			||||||
 | 
					   fixedWidthGutter: true,
 | 
				
			||||||
 | 
					   showGutter: true,
 | 
				
			||||||
 | 
					   showPrintMargin: false,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					editor.setAutoScrollEditorIntoView(true);
 | 
				
			||||||
 | 
					if(fs != undefined)
 | 
				
			||||||
 | 
					    editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					editor.session.on('change', function(delta) {
 | 
				
			||||||
 | 
					   if(typeof canvas1.setShaders === "function")
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      canvas1.setShaders(vs, editor.getSession().getValue());
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
 | 
				
			||||||
 | 
					delete editor.KeyBinding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let pause_resume = function(){
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					      lastTime = Date.now();
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					      startTime += Date.now() - lastTime;   
 | 
				
			||||||
 | 
					   animating = !animating;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					canvas1.addEventListener('click',function(ev){
 | 
				
			||||||
 | 
					   if(!(shift && alt) && lastClick&& Date.now()-lastClick<200)
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   lastClick = Date.now();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					pause.onclick = pause_resume;
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseover', function(e){
 | 
				
			||||||
 | 
					   over = true;
 | 
				
			||||||
 | 
					   if(e.offsetX >0 && e.offsetY > 0)
 | 
				
			||||||
 | 
					      curr_mouse_pos = [2*e.offsetX/ parseInt(canvas1.style.width)-1, 
 | 
				
			||||||
 | 
					         1-2*e.offsetY/ parseInt(canvas1.style.height), -1];
 | 
				
			||||||
 | 
					   else over = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousedown', function(e){
 | 
				
			||||||
 | 
					      moving = true;
 | 
				
			||||||
 | 
					      rotTime = uTime;
 | 
				
			||||||
 | 
					      presentation = false;
 | 
				
			||||||
 | 
					      mouselastX = mouselastY =  undefined;
 | 
				
			||||||
 | 
					      let i = hitTest([2*e.offsetX/ parseInt(canvas1.style.width)-1, 
 | 
				
			||||||
 | 
					         1-2*e.offsetY/ parseInt(canvas1.style.height), -1]);
 | 
				
			||||||
 | 
					      if(i >= 0)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         dragging = true;
 | 
				
			||||||
 | 
					         selected = true;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else if(selected = true){
 | 
				
			||||||
 | 
					         dragging = false;
 | 
				
			||||||
 | 
					         selected = false;
 | 
				
			||||||
 | 
					         setUniform("1i", "sel", i);
 | 
				
			||||||
 | 
					         selection = i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mousemove', function(e){
 | 
				
			||||||
 | 
					      curr_mouse_pos = [2*e.offsetX/ parseInt(canvas1.style.width)-1, 
 | 
				
			||||||
 | 
					         1-2*e.offsetY/ parseInt(canvas1.style.height), -1];
 | 
				
			||||||
 | 
					      if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
 | 
				
			||||||
 | 
					         let dx = (mouselastX - e.offsetX), 
 | 
				
			||||||
 | 
					             dy = (mouselastY - e.offsetY);
 | 
				
			||||||
 | 
					         if(movescene){
 | 
				
			||||||
 | 
					            sRotation = matrix_multiply(sRotation, matrix_rotateY(-dy/60));
 | 
				
			||||||
 | 
					            sRotation = matrix_multiply(sRotation, matrix_rotateX(-dx/60)); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         } 
 | 
				
			||||||
 | 
					         else if(!selected)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					               mousedx -= dx/60;
 | 
				
			||||||
 | 
					               mousedy -= dy/60;
 | 
				
			||||||
 | 
					               positionsupdated = true;
 | 
				
			||||||
 | 
					         }else if(dragging){
 | 
				
			||||||
 | 
					               let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					               m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					               let dv = matrix_multiply(m, [2*-dx/ parseInt(canvas1.style.width), 
 | 
				
			||||||
 | 
					                  2*dy/ parseInt(canvas1.style.height), 0, 1]).slice(0,3);
 | 
				
			||||||
 | 
					               SphTr[selection] = matrix_multiply(SphTr[selection], matrix_translate(dv[0], dv[1], dv[2]));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mouselastX = e.offsetX;
 | 
				
			||||||
 | 
					      mouselastY = e.offsetY;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseup', function(e){
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					   dragging = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('mouseout', function(e){
 | 
				
			||||||
 | 
					   const mask = 0x8;
 | 
				
			||||||
 | 
					   flags &= !mask;
 | 
				
			||||||
 | 
					   setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   over = false;
 | 
				
			||||||
 | 
					   moving = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.addEventListener('wheel', function(e){
 | 
				
			||||||
 | 
					   if(!selected){
 | 
				
			||||||
 | 
					      mousedz += e.wheelDelta/600;
 | 
				
			||||||
 | 
					      positionsupdated = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else{
 | 
				
			||||||
 | 
					      SphDletaR[selection] += e.wheelDelta / 800;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					canvas1.scroll(function(e) {e.stopPropagation();});
 | 
				
			||||||
 | 
					rtx.style.cursor="pointer";
 | 
				
			||||||
 | 
					let rtswitch = function(){
 | 
				
			||||||
 | 
					   alert('Ray Tracing is off for now. I\'ll try to add it back as some sort of background or texture later.')
 | 
				
			||||||
 | 
					   rtx.src='./RTXon.svg';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					rtx.addEventListener('click', rtswitch);
 | 
				
			||||||
 | 
					var requestAnimationFrame = window.requestAnimationFrame ||
 | 
				
			||||||
 | 
					 window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
 | 
				
			||||||
 | 
					let fpscounter = function(time){
 | 
				
			||||||
 | 
					      if (start === undefined)
 | 
				
			||||||
 | 
					         start = time;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
 | 
				
			||||||
 | 
					      start = time;
 | 
				
			||||||
 | 
					      if(fpson)
 | 
				
			||||||
 | 
					         ;//requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         start = undefined;
 | 
				
			||||||
 | 
					         fps.innerHTML = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					document.addEventListener('keydown',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = true;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = true;
 | 
				
			||||||
 | 
					   else if(ctrl && alt && e.code == 'KeyT'){
 | 
				
			||||||
 | 
					      const mask = 0x1;
 | 
				
			||||||
 | 
					      flags = flags&!mask | (!(flags&mask)?mask:0);
 | 
				
			||||||
 | 
					      setUniform('1i', 'flags', flags);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if (ctrl &&e.code == 'KeyS'){
 | 
				
			||||||
 | 
					      let a = document.createElement('a');
 | 
				
			||||||
 | 
					      a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
 | 
				
			||||||
 | 
					      a.download = 'shader.frag';
 | 
				
			||||||
 | 
					      a.click();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyR')
 | 
				
			||||||
 | 
					      rtswitch();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyN')
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      reset.onclick();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyP')
 | 
				
			||||||
 | 
					      pause_resume();
 | 
				
			||||||
 | 
					   else if(ctrl && alt&&e.code == 'KeyF')
 | 
				
			||||||
 | 
					      if(!fpson)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         fpson = true;
 | 
				
			||||||
 | 
					         requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					         fpson = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(e.code == 'ArrowUp' || e.code == 'ArrowDown' || e.code =='ArrowLeft'
 | 
				
			||||||
 | 
					      ||e.code == 'ArrowRight' || e.code =='KeyW'||e.code =='KeyS')
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         switch(e.code){
 | 
				
			||||||
 | 
					         case 'ArrowUp':
 | 
				
			||||||
 | 
					            facing = -2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowDown':
 | 
				
			||||||
 | 
					            facing = 2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowLeft':
 | 
				
			||||||
 | 
					            facing = -1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'ArrowRight':
 | 
				
			||||||
 | 
					            facing = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'KeyW':
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					         case 'KeyS':
 | 
				
			||||||
 | 
					            break;  
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      running = 50;
 | 
				
			||||||
 | 
					      rebuild = true;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if(fullscreen && selected ){
 | 
				
			||||||
 | 
					      if(e.code =='KeyF'||e.code =='KeyB'){
 | 
				
			||||||
 | 
					            let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					            m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					            m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch(e.code){   
 | 
				
			||||||
 | 
					               case 'KeyB':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, -0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;
 | 
				
			||||||
 | 
					               case 'KeyF':
 | 
				
			||||||
 | 
					                  var dv = matrix_multiply(m, [0,0, 0.1, 1]).slice(0,3);
 | 
				
			||||||
 | 
					                  m = matrix_translate(dv[0], dv[1], dv[2]);
 | 
				
			||||||
 | 
					                  break;                
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            SphTr[selection] = matrix_multiply(SphTr[selection], m);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.addEventListener('keyup',(e)=>{
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Control'))
 | 
				
			||||||
 | 
					      ctrl = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Alt'))
 | 
				
			||||||
 | 
					      alt = false;
 | 
				
			||||||
 | 
					   if(e.code.startsWith('Shift'))
 | 
				
			||||||
 | 
					      shift = false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					let squareMesh = new Float32Array([ -1,-1,1,0,0,0,1,-1, 1,1,0,0,0,1,-1, -1,-1,0,0,0,1, -1,1,-1,0 ,0,0,1]);
 | 
				
			||||||
 | 
					let sphereMesh   = createMesh(32, 32, uvToSphere);
 | 
				
			||||||
 | 
					let tubeMesh     = createMesh(32, 2, uvToTube,0,1);
 | 
				
			||||||
 | 
					let diskMesh     = createMesh(32, 2, uvToDisk,0,1);
 | 
				
			||||||
 | 
					let tubeMesh2     = createMesh(32, 2, uvToTube,0,2);
 | 
				
			||||||
 | 
					let diskNMesh2    = createMesh(32, 2, uvToDisk, -1,2);
 | 
				
			||||||
 | 
					let diskPMesh2    = createMesh(32, 2, uvToDisk,  1,2);
 | 
				
			||||||
 | 
					let tubeMesh3     = createMesh(32, 2, uvToTube,0,3);
 | 
				
			||||||
 | 
					let diskNMesh3    = createMesh(32, 2, uvToDisk, -1,3);
 | 
				
			||||||
 | 
					let diskPMesh3    = createMesh(32, 2, uvToDisk,  1,3);
 | 
				
			||||||
 | 
					let diskNMesh    = createMesh(32, 2, uvToDisk, -1,1);
 | 
				
			||||||
 | 
					let diskPMesh    = createMesh(32, 2, uvToDisk,  1,1);
 | 
				
			||||||
 | 
					let cylinderMesh = glueMeshes(glueMeshes(tubeMesh, diskPMesh), diskNMesh);
 | 
				
			||||||
 | 
					let cylinderMesh2 = glueMeshes(glueMeshes(tubeMesh2, diskPMesh2), diskNMesh2);
 | 
				
			||||||
 | 
					let cylinderMesh3 = glueMeshes(glueMeshes(tubeMesh3, diskPMesh3), diskNMesh3);
 | 
				
			||||||
 | 
					let torusMash    = createMesh(32, 32, uvToTorus, 1, 5);
 | 
				
			||||||
 | 
					let head = createCube(1.5,1,1, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let objects = [];
 | 
				
			||||||
 | 
					let addObject = (obj, mat) => {
 | 
				
			||||||
 | 
					   objects.push([obj, mat]);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					let clearObject = () => {delete objects; objects = [];};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let delta_height = 0, delta_l = [0,0];
 | 
				
			||||||
 | 
					class State{
 | 
				
			||||||
 | 
					   constructor() {
 | 
				
			||||||
 | 
					      this.leg = true;
 | 
				
			||||||
 | 
					      this.progress = 0;
 | 
				
			||||||
 | 
					      this.rh = this.lh = .5*pi;
 | 
				
			||||||
 | 
					      this.lf = this.rf = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   initialize(){
 | 
				
			||||||
 | 
					      this.leg = true;
 | 
				
			||||||
 | 
					      this.progress = 0;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   next(){
 | 
				
			||||||
 | 
					      //return this.presentation();
 | 
				
			||||||
 | 
					      if(running <= 0)
 | 
				
			||||||
 | 
					         return {rh:.5*pi, lh:.5*pi, rf:0, lf:0, dh:0,dl:0}
 | 
				
			||||||
 | 
					      running --;
 | 
				
			||||||
 | 
					      const steps = 100;
 | 
				
			||||||
 | 
					      let dl = 0;
 | 
				
			||||||
 | 
					      if(this.progress >= steps/2)
 | 
				
			||||||
 | 
					      { 
 | 
				
			||||||
 | 
					         this.progress = 0;
 | 
				
			||||||
 | 
					         this.leg = !this.leg;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let delta = [-pi/5, 0.5*pi, 0.44*pi, 0.55*pi];
 | 
				
			||||||
 | 
					      for (let i = 0; i < 4; ++i) delta[i] /= steps;
 | 
				
			||||||
 | 
					      if(this.leg)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         if(this.progress < steps/4)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            this.lh += delta[0];
 | 
				
			||||||
 | 
					            this.rh += delta[3];
 | 
				
			||||||
 | 
					            this.lf += delta[1];
 | 
				
			||||||
 | 
					            this.rf += delta[2];
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            this.lh -= delta[0];
 | 
				
			||||||
 | 
					            this.rh -= delta[3];
 | 
				
			||||||
 | 
					            this.lf -= delta[1];
 | 
				
			||||||
 | 
					            this.rf-= delta[2];  
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else{
 | 
				
			||||||
 | 
					         if(this.progress < steps/4)
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					            this.lh += delta[3];
 | 
				
			||||||
 | 
					            this.rh += delta[0];
 | 
				
			||||||
 | 
					            this.lf += delta[2];
 | 
				
			||||||
 | 
					            this.rf += delta[1];
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else{
 | 
				
			||||||
 | 
					            this.lh -= delta[3];
 | 
				
			||||||
 | 
					            this.rh -= delta[0];
 | 
				
			||||||
 | 
					            this.lf -= delta[2];
 | 
				
			||||||
 | 
					            this.rf-= delta[1];  
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let delta_h = Math.max((1-cos(abs(this.lh - pi/2)))*.5+(1-cos(abs(this.lf)))*.6,(1-cos(abs(this.rh - pi/2)))*.5+(1-cos(abs(this.rf)))*.6);
 | 
				
			||||||
 | 
					      this.progress++;  
 | 
				
			||||||
 | 
					      return  {lh:this.lh, lf:this.lf, rh:this.rh,rf:this.rf, dh:delta_h, dl:1.8522/steps};
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   // presentation(){
 | 
				
			||||||
 | 
					   //    return {lh:.4*pi, lf:pi/6,rh:.7*pi, rf:pi/8, dh:0};
 | 
				
			||||||
 | 
					   // }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let star1 = [], star = []; 
 | 
				
			||||||
 | 
					let sakura = [], stars = [], nstars = 25;
 | 
				
			||||||
 | 
					let star2=[], newstar, star4;
 | 
				
			||||||
 | 
					const curvex = matrix_multiply(hermiteMat, [-.3,.8,.6,.5]);
 | 
				
			||||||
 | 
					const curvey = matrix_multiply(hermiteMat, [-.2,.5,.7,.2]);
 | 
				
			||||||
 | 
					const curvez = matrix_multiply(hermiteMat, [-.5,.2,.3,.8]);
 | 
				
			||||||
 | 
					let adt = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let build_objects = (state)=>{
 | 
				
			||||||
 | 
					   if(running === 0)
 | 
				
			||||||
 | 
					      rebuild = false;
 | 
				
			||||||
 | 
					   let {lh, lf, rh, rf, dh, dl} = state.next();
 | 
				
			||||||
 | 
					   delta_l[abs(facing)-1] +=  Math.sign(facing) * dl;
 | 
				
			||||||
 | 
					   delta_height = dh;
 | 
				
			||||||
 | 
					   clearObject();
 | 
				
			||||||
 | 
					   M.save();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.rotateX(pi/2);
 | 
				
			||||||
 | 
					         M.scale(0.5, 0.5, 1);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0,1,0);
 | 
				
			||||||
 | 
					         addObject(head, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0.5, 0.2, 0.3);
 | 
				
			||||||
 | 
					         M.rotateX(pi/4);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.4);
 | 
				
			||||||
 | 
					            M.rotateX(-0.53*pi);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.4);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-0.5, 0.2, 0.3);
 | 
				
			||||||
 | 
					         M.rotateX(pi/4);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.4);
 | 
				
			||||||
 | 
					            M.rotateX(-0.55*pi);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.4);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh2, M.value());
 | 
				
			||||||
 | 
					      M.restore();      
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0.3, -1, 0.);
 | 
				
			||||||
 | 
					         M.rotateX(lh);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.45);
 | 
				
			||||||
 | 
					            M.rotateX(lf);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.6);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-0.3, -1, 0.);
 | 
				
			||||||
 | 
					         M.rotateX(rh);
 | 
				
			||||||
 | 
					         M.translate(0,0,.5);
 | 
				
			||||||
 | 
					         M.save();
 | 
				
			||||||
 | 
					            M.translate(0,0,.45);
 | 
				
			||||||
 | 
					            M.rotateX(rf);
 | 
				
			||||||
 | 
					            M.scale(0.2, 0.2, 0.6);
 | 
				
			||||||
 | 
					            M.translate(0,0,1);
 | 
				
			||||||
 | 
					            addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					         M.restore();
 | 
				
			||||||
 | 
					         M.scale(0.2, 0.2, 0.5);
 | 
				
			||||||
 | 
					         addObject(cylinderMesh3, M.value());
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   if(running < 0)
 | 
				
			||||||
 | 
					      rebuild = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let build_splines = ()=>{
 | 
				
			||||||
 | 
					   star = [], star1 = [], star2 = [], star4 = [], newstar = [], adt = [], sakura = [];
 | 
				
			||||||
 | 
					   var n = 11, innerN = Math.ceil((paths[0].length*n)/paths[1].length);
 | 
				
			||||||
 | 
					   for(let j = 0; j < paths[0].length; ++j)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let xf = paths[0][j][0], yf = paths[0][j][1];
 | 
				
			||||||
 | 
					      for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					         let t = k/n;
 | 
				
			||||||
 | 
					         star1.push([7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         0,0,0,1]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   for(let j = 13; j >=0; j--)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let xf = paths[1][j][0], yf = paths[1][j][1];
 | 
				
			||||||
 | 
					      for(var k = innerN-1; k >=0 ; --k){
 | 
				
			||||||
 | 
					         let t = k/(innerN-1);
 | 
				
			||||||
 | 
					         star2.push([7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         0,0,0,1]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   for(let j = paths[1].length-1; j >12; --j)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      let xf = paths[1][j][0], yf = paths[1][j][1];
 | 
				
			||||||
 | 
					      for(var k = innerN; k >=0 ; --k){
 | 
				
			||||||
 | 
					         let t = k/innerN;
 | 
				
			||||||
 | 
					         star2.push([7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					         0,0,0,1]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   for(let i = 0; i < star1.length; ++i){
 | 
				
			||||||
 | 
					      concat(star, star1[i]);
 | 
				
			||||||
 | 
					      concat(star, star2[i]);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   n = 25;
 | 
				
			||||||
 | 
					   for(let l = 2; l < 6; ++l)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      adt[l - 2] = [];
 | 
				
			||||||
 | 
					      for(let j = 0; j < paths[l].length; ++j)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         let xf = paths[l][j][0], yf = paths[l][j][1];
 | 
				
			||||||
 | 
					         for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					            let t = k/n;
 | 
				
			||||||
 | 
					            adt[l-2].push(10+l,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            -dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            0,0,0,1);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   n = 20;
 | 
				
			||||||
 | 
					   for(let l = 6; l < 13; ++l)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      sakura[l-6] = [];
 | 
				
			||||||
 | 
					      for(let j = 0; j < paths[l].length; ++j)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					         let xf = paths[l][j][0], yf = paths[l][j][1];
 | 
				
			||||||
 | 
					         for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					            let t = k/n;
 | 
				
			||||||
 | 
					            sakura[l-6].push(10,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					            0,0,0,1);
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   star4 = star.slice();
 | 
				
			||||||
 | 
					   newstar = star.slice()
 | 
				
			||||||
 | 
					   for(let i = 0; i < star.length; i+=7)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      star4[i] = 9;
 | 
				
			||||||
 | 
					      newstar[i] = 8;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   for(let i = 0; i < nstars; ++i){
 | 
				
			||||||
 | 
					      stars.push(star.slice());
 | 
				
			||||||
 | 
					      startz.push(.6*Math.random());
 | 
				
			||||||
 | 
					      random_rot.push(0);
 | 
				
			||||||
 | 
					      random_rot_pos.push(0);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let state = new State();
 | 
				
			||||||
 | 
					var M = new Matrix();
 | 
				
			||||||
 | 
					var buildsplines = true;
 | 
				
			||||||
 | 
					let magician = false, magician_neck = false, 
 | 
				
			||||||
 | 
					   magician_houki = false, body = false, 
 | 
				
			||||||
 | 
					   leg = false, hand = false ;
 | 
				
			||||||
 | 
					let sa2 = [
 | 
				
			||||||
 | 
					   1.6,0.4, .9, 1., .3,.2, -.4,.8, 
 | 
				
			||||||
 | 
					   -.8, -.1, -1.4, .5, -1.6, -.5 
 | 
				
			||||||
 | 
					], fsa2 = [[matrix_multiply(bezierMat,[sa2[0], sa2[2], sa2[4], sa2[6]]),
 | 
				
			||||||
 | 
					            matrix_multiply(bezierMat,[sa2[1], sa2[3], sa2[5], sa2[7]])],
 | 
				
			||||||
 | 
					         [matrix_multiply(bezierMat,[sa2[6], sa2[8], sa2[10], sa2[12]]),
 | 
				
			||||||
 | 
					         matrix_multiply(bezierMat,[sa2[7], sa2[9], sa2[11], sa2[13]])]],
 | 
				
			||||||
 | 
					         random_rot = [0,0,0,0,0,0,0], random_rot_pos = [0,0,0,0,0,0,0], startz = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let division = -1;
 | 
				
			||||||
 | 
					let changeID = (id, obj) => {for(let i = 0; i < obj.length; i+=7) obj[i] = id;}
 | 
				
			||||||
 | 
					function animate(gl) {
 | 
				
			||||||
 | 
					   buildsplines &&=  build_splines();
 | 
				
			||||||
 | 
					   magician = magician?magician:createMeshFromSpline( 13, 32, 4, 4, 0, (i,_,oid) => {
 | 
				
			||||||
 | 
					      if (oid == 4 && i == 10) return 3;
 | 
				
			||||||
 | 
					      else if (oid == 3 && i ==16) return 2;
 | 
				
			||||||
 | 
					      else if(oid == 2 && i == 23) return 1;
 | 
				
			||||||
 | 
					   });
 | 
				
			||||||
 | 
					   magician_neck = magician_neck?magician_neck:createMeshFromSpline( 14, 32, 4, 5, -.2);
 | 
				
			||||||
 | 
					   magician_houki = magician_houki?magician_houki:createMeshFromSpline( 15, 32, 4, 6);
 | 
				
			||||||
 | 
					   body = body?body:createMeshFromSpline( 16, 32, 4, 7, 0, (i, tmp)=>{if(division < 0 && i == 25) division = tmp.length;});
 | 
				
			||||||
 | 
					   leg = leg?leg:createMeshFromSpline(17, 32, 4, 8);
 | 
				
			||||||
 | 
					   hand = hand?hand:createMeshFromSpline(18, 32, 4, 9,.015);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(animating)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (Date.now() - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   else
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      uTime = (lastTime - startTime) / 1000;
 | 
				
			||||||
 | 
					      setUniform('1f', 'uTime', uTime);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   let curve = [];
 | 
				
			||||||
 | 
					   let n = 8;
 | 
				
			||||||
 | 
					   // for(let j = 0; j < paths[13].length; ++j)
 | 
				
			||||||
 | 
					   // {
 | 
				
			||||||
 | 
					   //    let xf = paths[13][j][0], yf = paths[13][j][1];
 | 
				
			||||||
 | 
					   //    for(var k = 0; k <= n; ++k){
 | 
				
			||||||
 | 
					   //       let t = k/n;
 | 
				
			||||||
 | 
					   //       concat(curve, [7,dot(xf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					   //       -dot(yf, [t*t*t, t*t, t, 1]),
 | 
				
			||||||
 | 
					   //       0,0,0,1]);
 | 
				
			||||||
 | 
					   //    }
 | 
				
			||||||
 | 
					   // }
 | 
				
			||||||
 | 
					   // M.save()
 | 
				
			||||||
 | 
					   // M.scale(0.3);
 | 
				
			||||||
 | 
					   // setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					   // drawMesh(leg);
 | 
				
			||||||
 | 
					   // M.restore();
 | 
				
			||||||
 | 
					   // return;
 | 
				
			||||||
 | 
					   M.save()
 | 
				
			||||||
 | 
					      if(presentation){
 | 
				
			||||||
 | 
					         M.rotateX(uTime/12);
 | 
				
			||||||
 | 
					         M.rotateY(uTime/3);
 | 
				
			||||||
 | 
					         M.rotateZ(uTime/6);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         M.rotateX(rotTime/12);
 | 
				
			||||||
 | 
					         M.rotateY(rotTime/3);
 | 
				
			||||||
 | 
					         M.rotateZ(rotTime/6);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      M.scale(0.6);
 | 
				
			||||||
 | 
					      setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					      drawMesh(body.slice(0, division));
 | 
				
			||||||
 | 
					      drawMesh(body.slice(division - 7), gl.LINE_LOOP);
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0,0,-1.05);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(magician);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(0,0,-.53);
 | 
				
			||||||
 | 
					         M.scale(.1);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(magician_neck);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save();
 | 
				
			||||||
 | 
					         M.translate(-1,0,0);
 | 
				
			||||||
 | 
					         M.scale(2);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(magician_houki);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save()
 | 
				
			||||||
 | 
					         M.translate(-.06,0,.85);
 | 
				
			||||||
 | 
					         M.rotateY(0.02);
 | 
				
			||||||
 | 
					         M.scale(1.2);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(leg);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save()
 | 
				
			||||||
 | 
					         M.translate(.06,0,.85);
 | 
				
			||||||
 | 
					         M.rotateY(-0.02);
 | 
				
			||||||
 | 
					         M.scale(1.2);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(leg);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save()
 | 
				
			||||||
 | 
					         M.translate(-.35,0,-.1);
 | 
				
			||||||
 | 
					         M.rotateY(-pi/6);
 | 
				
			||||||
 | 
					         M.scale(.82);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(hand);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					      M.save()
 | 
				
			||||||
 | 
					         M.translate(.35,0,-.1);
 | 
				
			||||||
 | 
					         M.rotateY(pi/6);
 | 
				
			||||||
 | 
					         M.scale(.82);
 | 
				
			||||||
 | 
					         setM(matrix_multiply(sRotation, M.value()));
 | 
				
			||||||
 | 
					         drawMesh(hand);
 | 
				
			||||||
 | 
					      M.restore();
 | 
				
			||||||
 | 
					   M.restore();
 | 
				
			||||||
 | 
					   for(let i = 0; i < nstars; ++ i)
 | 
				
			||||||
 | 
					   {M.save()
 | 
				
			||||||
 | 
					      let f_idx = (uTime/(abs(sin(i*1234))*8 + 10))%2,
 | 
				
			||||||
 | 
					          t = f_idx - Math.floor(f_idx); 
 | 
				
			||||||
 | 
					      f_idx -=t;
 | 
				
			||||||
 | 
					      let curr_mat = [t*t*t, t*t, t, 1];
 | 
				
			||||||
 | 
					      M.translate(1.2*sin(sin(uTime/(i+2)+i + 8)*.9 + dot(fsa2[f_idx][0], curr_mat)*5 + startz[Math.floor(2*startz[i]*nstars)%nstars]), 1.2*cos(i + sin(uTime/(i/2+18)+12)*.1 + startz[nstars-i-1] + dot(fsa2[f_idx][1], curr_mat)*startz[(nstars + i)%nstars]*.4 + i * sin(random_rot_pos[i]/30)/pi), .65*startz[i] + .3*sin(random_rot_pos[i]/20));
 | 
				
			||||||
 | 
					      let epsilon = 1/(i*2+20);
 | 
				
			||||||
 | 
					      let random = () => {
 | 
				
			||||||
 | 
					         var u = 0, v = 0;
 | 
				
			||||||
 | 
					         while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
 | 
				
			||||||
 | 
					         while(v === 0) v = Math.random();
 | 
				
			||||||
 | 
					         return Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v )/pi;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if((window.performance.now() + i*(2+abs(random()))) %69 <2){
 | 
				
			||||||
 | 
					         changeID(Math.ceil(Math.random()*20)-5,stars[i])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					         random_rot[i] += random()*epsilon;
 | 
				
			||||||
 | 
					         random_rot_pos[i] += .5 + abs(random())/(pi+i);
 | 
				
			||||||
 | 
					      //setM(M.value);
 | 
				
			||||||
 | 
					      M.rotateZ(sin(random_rot_pos[i]/10)*pi);
 | 
				
			||||||
 | 
					      M.rotateX(.1*sin(random_rot_pos[i]/(i+50))*pi);
 | 
				
			||||||
 | 
					      M.rotateY(.1*sin(random_rot_pos[i]/(i*2+50))*pi);
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      M.scale(0.2 + startz[i]*.2);
 | 
				
			||||||
 | 
					      setM(M.value());
 | 
				
			||||||
 | 
					      drawMesh(new Float32Array(stars[i]));
 | 
				
			||||||
 | 
					   M.restore();}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(over);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					requestAnimationFrame(fpscounter);
 | 
				
			||||||
 | 
					//pjsk.play();
 | 
				
			||||||
@ -0,0 +1,537 @@
 | 
				
			|||||||
 | 
					//Header file, contains global variable definitions, 
 | 
				
			||||||
 | 
					// asynchronized shader loading and utility functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var mousedx = 0, mousedy = 0, mousedz = 0;
 | 
				
			||||||
 | 
					let seldx = 0, seldy = 0, seldz = 0;
 | 
				
			||||||
 | 
					var enableSelection = false;
 | 
				
			||||||
 | 
					var cx = 1, cy = 1, sx = 0, sy = 0;
 | 
				
			||||||
 | 
					var mouselastX, mouselastY;
 | 
				
			||||||
 | 
					var fl = 3;
 | 
				
			||||||
 | 
					let start;
 | 
				
			||||||
 | 
					var vs, fs;
 | 
				
			||||||
 | 
					var bezierMat = [-1,3,-3,1,3,-6,3,0,-3,3,0,0,1,0,0,0], 
 | 
				
			||||||
 | 
					    hermiteMat = [2,-3,0,1,-2,3,0,0,1,-2,1,0,1,-1,0,0], 
 | 
				
			||||||
 | 
					    catmullRomMat = [ -.5,1,-.5,0, 1.5,-2.5,0,1, -1.5,2,.5,0, .5,-.5,0,0 ];
 | 
				
			||||||
 | 
					var starColors = [0.9921, 0.5378,0.7109,
 | 
				
			||||||
 | 
					                    0.65, 0.56, 0.992,
 | 
				
			||||||
 | 
					                    0.992,0.7994,0.2402,
 | 
				
			||||||
 | 
					                    0.1760,0.5094,0.5378,
 | 
				
			||||||
 | 
					                    .1164, .1274, .2289,
 | 
				
			||||||
 | 
					                    .9784,.71,.4482,
 | 
				
			||||||
 | 
					                ], n_shapes = starColors.length/3;
 | 
				
			||||||
 | 
					var editor = undefined
 | 
				
			||||||
 | 
					var cos = Math.cos, sin = Math.sin, tan = Math.tan,
 | 
				
			||||||
 | 
					    acos = Math.acos, asin = Math.asin, atan = Math.atan,
 | 
				
			||||||
 | 
					    sqrt = Math.sqrt, pi = Math.PI, abs = Math.abs;
 | 
				
			||||||
 | 
					var positionsupdated = true;
 | 
				
			||||||
 | 
					var paths = [], origpath= [], path_misc = [];
 | 
				
			||||||
 | 
					let vsfetch = new XMLHttpRequest(); 
 | 
				
			||||||
 | 
					vsfetch.open('GET', './shader.vert');
 | 
				
			||||||
 | 
					vsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    vs = vsfetch.responseText;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					vsfetch.send();
 | 
				
			||||||
 | 
					//* LOADING FRAGMENT SHADER
 | 
				
			||||||
 | 
					let fsfetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					fsfetch.open('GET', './shader.frag');
 | 
				
			||||||
 | 
					fsfetch.onloadend = function () {
 | 
				
			||||||
 | 
					    fs = (fsfetch.responseText);
 | 
				
			||||||
 | 
					    //* START EVERYTHING AFTER FRAGMENT SHADER IS DOWNLOADED.
 | 
				
			||||||
 | 
					    if (editor != undefined)
 | 
				
			||||||
 | 
					        editor.getSession().setValue(fs);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					fsfetch.send();
 | 
				
			||||||
 | 
					let pathFetch = new XMLHttpRequest();
 | 
				
			||||||
 | 
					pathFetch.open('GET', './paths.txt');
 | 
				
			||||||
 | 
					pathFetch.onloadend = function () {
 | 
				
			||||||
 | 
					    let text = pathFetch.responseText;
 | 
				
			||||||
 | 
					    let currX = 0, currY = 0, maxX = -10000, maxY = -10000, minX = 10000, minY = 10000;
 | 
				
			||||||
 | 
					    var currShape = [], currCurve = [];
 | 
				
			||||||
 | 
					    let i = 0;
 | 
				
			||||||
 | 
					    let postProcess = () => {
 | 
				
			||||||
 | 
					        if(currShape.length){
 | 
				
			||||||
 | 
					            let spanX = maxX - minX;
 | 
				
			||||||
 | 
					            let spanY = maxY - minY;
 | 
				
			||||||
 | 
					            let span = Math.max(spanX, spanY);
 | 
				
			||||||
 | 
					            let l_total = 0;
 | 
				
			||||||
 | 
					            for (var k = 0; k < currShape.length; ++k) {
 | 
				
			||||||
 | 
					                let funcs = [];
 | 
				
			||||||
 | 
					                const curve = currShape[k];
 | 
				
			||||||
 | 
					                for (let j = 0; j < curve.length; j += 2){
 | 
				
			||||||
 | 
					                    curve[j] = (curve[j] - minX) / span-spanX/(span*2);
 | 
				
			||||||
 | 
					                    curve[j + 1] = (curve[j + 1] - minY) / span - spanY/(span*2);
 | 
				
			||||||
 | 
					                    origpath.push(1,curve[j], curve[j+1],0,0,0,1);
 | 
				
			||||||
 | 
					                    if(j%6==0 && j > 5){
 | 
				
			||||||
 | 
					                        let X = [], Y = [];
 | 
				
			||||||
 | 
					                        for(let k = j - 6; k <= j+1; k += 2){
 | 
				
			||||||
 | 
					                            X.push(curve[k]);
 | 
				
			||||||
 | 
					                            Y.push(curve[k+1]);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        let l = (vec_len(minus([X[3], Y[3]], [X[0], Y[0]])) + 
 | 
				
			||||||
 | 
					                        vec_len(minus([X[3], Y[3]], [X[2], Y[2]])) + 
 | 
				
			||||||
 | 
					                        vec_len(minus([X[2], Y[2]], [X[1], Y[1]])) + 
 | 
				
			||||||
 | 
					                        vec_len(minus([X[1], Y[1]], [X[0], Y[0]])))/2.;
 | 
				
			||||||
 | 
					                        l_total += l;
 | 
				
			||||||
 | 
					                        funcs.push([matrix_multiply(bezierMat, X), 
 | 
				
			||||||
 | 
					                                    matrix_multiply(bezierMat, Y), l]);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                paths.push(funcs);
 | 
				
			||||||
 | 
					                path_misc.push([l_total, spanX/(2*span), spanY/(2*span)]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let read_num = () =>{
 | 
				
			||||||
 | 
					        let num = 0, sign = 1, accepted = 0;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        while(i < text.length && (text[i] <'0' || text[i] > '9') && text[i]!='-') ++i;
 | 
				
			||||||
 | 
					        if(text[i] == '-')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            sign = -1;
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while(i < text.length&&text[i] >= '0' && text[i] <= '9'){
 | 
				
			||||||
 | 
					            let n = text[i++] - '0';
 | 
				
			||||||
 | 
					            accepted *= 10;
 | 
				
			||||||
 | 
					            accepted += n;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        num += accepted;
 | 
				
			||||||
 | 
					        if(text[i] == '.'){
 | 
				
			||||||
 | 
					            i++;
 | 
				
			||||||
 | 
					            let multiplier = 0.1;
 | 
				
			||||||
 | 
					            accepted = 0;
 | 
				
			||||||
 | 
					            while(i < text.length&&text[i] >= '0' && text[i] <= '9'){
 | 
				
			||||||
 | 
					                let n = text[i++] - '0';
 | 
				
			||||||
 | 
					                accepted += n * multiplier;
 | 
				
			||||||
 | 
					                multiplier /= 10;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            num += accepted;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return num * sign;
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					    let cRevs = [], c_idx = 0, prevX = 0, prevY = 0, getC = ()=>{
 | 
				
			||||||
 | 
					        return cRevs[c_idx--];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let get_next = (delta = false) => {
 | 
				
			||||||
 | 
					        if(delta){
 | 
				
			||||||
 | 
					            currX = prevX + read_num();
 | 
				
			||||||
 | 
					            currY = prevY + read_num();
 | 
				
			||||||
 | 
					        }else{
 | 
				
			||||||
 | 
					            currX = read_num();
 | 
				
			||||||
 | 
					            currY = read_num();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        maxX = currX > maxX? currX:maxX;
 | 
				
			||||||
 | 
					        maxY = currY > maxY? currY:maxY;
 | 
				
			||||||
 | 
					        minX = currX < minX? currX:minX;
 | 
				
			||||||
 | 
					        minY = currY < minY? currY:minY;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        currCurve.push(currX);
 | 
				
			||||||
 | 
					        currCurve.push(currY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while( i < text.length ){
 | 
				
			||||||
 | 
					        if(text[i] == 'z'){
 | 
				
			||||||
 | 
					            currCurve.length && currShape.push(currCurve);
 | 
				
			||||||
 | 
					            currCurve = [];
 | 
				
			||||||
 | 
					            ++i
 | 
				
			||||||
 | 
					        } else if (text[i] == 'N'){
 | 
				
			||||||
 | 
					            postProcess();
 | 
				
			||||||
 | 
					            currShape = [];
 | 
				
			||||||
 | 
					            maxX = -1000, maxY = -1000, minX = 1000, minY = 1000;
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					        } else if (text[i] == 'c'){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            prevX = currX;
 | 
				
			||||||
 | 
					            prevY = currY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for(let j = 0; j < 3; ++j){
 | 
				
			||||||
 | 
					                get_next(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (text[i] == 'C'){
 | 
				
			||||||
 | 
					            for(let j = 0; j < 3; ++j){
 | 
				
			||||||
 | 
					                get_next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (text[i] == 'M'){
 | 
				
			||||||
 | 
					            get_next();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else ++i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					pathFetch.send();
 | 
				
			||||||
 | 
					let vec_len = v =>{
 | 
				
			||||||
 | 
					    let len = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        len += v[i] * v[i];
 | 
				
			||||||
 | 
					    return sqrt(len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_inverse = src => {
 | 
				
			||||||
 | 
					    let dst = [], det = 0, cofactor = (c, r) => {
 | 
				
			||||||
 | 
					       let s = (i, j) => src[c+i & 3 | (r+j & 3) << 2];
 | 
				
			||||||
 | 
					       return (c+r & 1 ? -1 : 1) * ( (s(1,1) * (s(2,2) * s(3,3) - s(3,2) * s(2,3)))
 | 
				
			||||||
 | 
					                                   - (s(2,1) * (s(1,2) * s(3,3) - s(3,2) * s(1,3)))
 | 
				
			||||||
 | 
					                                   + (s(3,1) * (s(1,2) * s(2,3) - s(2,2) * s(1,3))) );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (let n = 0 ; n < 16 ; n++) dst.push(cofactor(n >> 2, n & 3));
 | 
				
			||||||
 | 
					    for (let n = 0 ; n <  4 ; n++) det += src[n] * dst[n << 2];
 | 
				
			||||||
 | 
					    for (let n = 0 ; n < 16 ; n++) dst[n] /= det;
 | 
				
			||||||
 | 
					    return dst;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// I HAVE IMPLEMENTED THESE FUNCTIONS FOR YOU
 | 
				
			||||||
 | 
					let matrix_identity = () => {
 | 
				
			||||||
 | 
					    return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_translate = (x, y, z) => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[12] = x;
 | 
				
			||||||
 | 
					    m[13] = y;
 | 
				
			||||||
 | 
					    m[14] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_perspective = (m) => {
 | 
				
			||||||
 | 
					    let ret = []
 | 
				
			||||||
 | 
					    for (let i = 0; i < 16; i ++)
 | 
				
			||||||
 | 
					        ret[i] = m[i];
 | 
				
			||||||
 | 
					    for (let i = 2; i < 15; i += 4)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ret[i] = -ret[i]; 
 | 
				
			||||||
 | 
					        ret[i+1] += ret[i]/fl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// YOU NEED TO PROPERLY IMPLEMENT THE FOLLOWING FIVE FUNCTIONS:
 | 
				
			||||||
 | 
					let matrix_rotateX = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    m[6] = sin(theta);
 | 
				
			||||||
 | 
					    m[9] = -sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let matrix_rotateY = theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[2] = -sin(theta);
 | 
				
			||||||
 | 
					    m[8] = sin(theta);
 | 
				
			||||||
 | 
					    m[10] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_rotateZ= theta => {
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = cos(theta);
 | 
				
			||||||
 | 
					    m[1] = sin(theta);
 | 
				
			||||||
 | 
					    m[4] = -sin(theta);
 | 
				
			||||||
 | 
					    m[5] = cos(theta);
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_scale = (x, y, z) => {
 | 
				
			||||||
 | 
					    if (y === undefined)
 | 
				
			||||||
 | 
					        y = z = x;
 | 
				
			||||||
 | 
					    let m = matrix_identity();
 | 
				
			||||||
 | 
					    m[0] = x;
 | 
				
			||||||
 | 
					    m[5] = y;
 | 
				
			||||||
 | 
					    m[10] = z;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let matrix_multiply = (a, b, m = 4, n = 4) => { //dim=mn*nm=mm
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    if (b.length < m*n) { //mat-vec multiply (i did this for my convenience)
 | 
				
			||||||
 | 
					        for (let i = 0; i < m; ++i) {
 | 
				
			||||||
 | 
					            res[i] = 0;
 | 
				
			||||||
 | 
					            for (let j = 0; j < n; ++j)
 | 
				
			||||||
 | 
					                res[i] += b[j] * a[m * j + i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    } //otherwise mm multiply
 | 
				
			||||||
 | 
					    for (let i = 0; i < m; ++i)
 | 
				
			||||||
 | 
					        for (let j = 0; j < m; ++j) {
 | 
				
			||||||
 | 
					            var t = 0;
 | 
				
			||||||
 | 
					            for (let k = 0; k < n; ++k)
 | 
				
			||||||
 | 
					                t += a[k * m + j] * b[i * n + k];
 | 
				
			||||||
 | 
					            res.push(t);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let const_multiply = (c, a) => {
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++ i)
 | 
				
			||||||
 | 
					        m[i] = a[i] * c;
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function dot(a, b){
 | 
				
			||||||
 | 
					    let m = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m += a[i] * b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function plus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] + b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function minus(a, b){
 | 
				
			||||||
 | 
					    let m = [];
 | 
				
			||||||
 | 
					    for(let i = 0; i < a.length; ++i)
 | 
				
			||||||
 | 
					        m[i] = a[i] - b[i];
 | 
				
			||||||
 | 
					    return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function normalize(v){
 | 
				
			||||||
 | 
					    let res = [];
 | 
				
			||||||
 | 
					    sum = 0;
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        sum += v[i] * v[i];
 | 
				
			||||||
 | 
					    sum = sqrt(sum);
 | 
				
			||||||
 | 
					    for(let i = 0; i < v.length; ++ i)
 | 
				
			||||||
 | 
					        res[i] = v[i] / sum;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let Matrix = function() {
 | 
				
			||||||
 | 
					    let top = 0, m = [ matrix_identity() ];
 | 
				
			||||||
 | 
					    this.identity = () => m[top] = matrix_identity();
 | 
				
			||||||
 | 
					    this.translate = (x,y,z) => m[top] = matrix_multiply(m[top], matrix_translate(x,y,z));
 | 
				
			||||||
 | 
					    this.rotateX = theta     => m[top] = matrix_multiply(m[top], matrix_rotateX(theta));
 | 
				
			||||||
 | 
					    this.rotateY = theta     => m[top] = matrix_multiply(m[top], matrix_rotateY(theta));
 | 
				
			||||||
 | 
					    this.rotateZ = theta     => m[top] = matrix_multiply(m[top], matrix_rotateZ(theta));
 | 
				
			||||||
 | 
					    this.scale   = (x,y,z)   => m[top] = matrix_multiply(m[top], matrix_scale(x,y,z));
 | 
				
			||||||
 | 
					    this.value   = ()        => m[top];
 | 
				
			||||||
 | 
					    this.save    = ()        => { m[top+1] = m[top].slice(); top++; }
 | 
				
			||||||
 | 
					    this.restore = ()        => --top;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let setM = (m) => {
 | 
				
			||||||
 | 
					    let mm = matrix_perspective(m);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'uMatrix', false, mm);
 | 
				
			||||||
 | 
					    setUniform('Matrix4fv', 'invMatrix', false, matrix_inverse(m));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 //------ CREATING MESH SHAPES
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 // CREATE A MESH FROM A PARAMETRIC FUNCTION
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let createMesh = (nu, nv, f, data, oid = 0) => {
 | 
				
			||||||
 | 
					    let tmp = [];
 | 
				
			||||||
 | 
					    for (let v = 0 ; v < 1 ; v += 1/nv) {
 | 
				
			||||||
 | 
					       for (let u = 0 ; u <= 1 ; u += 1/nu) {
 | 
				
			||||||
 | 
					          tmp = tmp.concat(f(u,v,oid,data));
 | 
				
			||||||
 | 
					          tmp = tmp.concat(f(u,v+1/nv,oid,data));
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       tmp = tmp.concat(f(1,v,oid,data));
 | 
				
			||||||
 | 
					       tmp = tmp.concat(f(0,v+1/nv,oid,data));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new Float32Array(tmp);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 //Create a Mesh from Splines
 | 
				
			||||||
 | 
					 let createMeshFromSpline = ( idx,
 | 
				
			||||||
 | 
					    nu, nv, oid = 16, additional_offset = 0, f = ()=>{}) => {
 | 
				
			||||||
 | 
					    let S = paths[idx], meta = path_misc[idx];
 | 
				
			||||||
 | 
					    const n_min = 2;
 | 
				
			||||||
 | 
					    let ds = meta[0]/nv, curr_s = 0, curr_d = S[0][2]/Math.ceil(S[0][2]/ds), i = 0, s = 0;
 | 
				
			||||||
 | 
					    let tmp = [], ret = undefined;
 | 
				
			||||||
 | 
					    while (s < meta[0]-1/100000) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let u = 0 ; u <= 1 ; u += 1/nu) {
 | 
				
			||||||
 | 
					          tmp = tmp.concat(getSurface(S[i][1],S[i][0],u,curr_s, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					          tmp = tmp.concat(getSurface(S[i][1],S[i][0],u,curr_s+curr_d, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tmp = tmp.concat(getSurface(S[i][1],S[i][0],0,curr_s, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					        tmp = tmp.concat(getSurface(S[i][1],S[i][0],1,curr_s+curr_d, idx, oid, additional_offset));
 | 
				
			||||||
 | 
					        if( ret = f(i, tmp, oid)){
 | 
				
			||||||
 | 
					            oid = ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        curr_s += curr_d;
 | 
				
			||||||
 | 
					        if(curr_s >= 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            s += S[i][2];
 | 
				
			||||||
 | 
					            ++i;
 | 
				
			||||||
 | 
					            if(i >= S.length) 
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            let curr_n = Math.ceil(S[i][2]/ds);
 | 
				
			||||||
 | 
					            curr_n = curr_n < n_min ? n_min : curr_n;
 | 
				
			||||||
 | 
					            curr_d = 1/curr_n;
 | 
				
			||||||
 | 
					            curr_s = 0;
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new Float32Array(tmp);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 // GLUE TWO MESHES TOGETHER INTO A SINGLE MESH
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let glueMeshes = (a, b) => {
 | 
				
			||||||
 | 
					    let c = [];
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < a.length ; i++)
 | 
				
			||||||
 | 
					       c.push(a[i]);                           // a
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					       c.push(a[a.length - VERTEX_SIZE + i]);  // + last vertex of a
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < VERTEX_SIZE ; i++)
 | 
				
			||||||
 | 
					       c.push(b[i]);                           // + first vertex of b
 | 
				
			||||||
 | 
					    for (let i = 0 ; i < b.length ; i++)
 | 
				
			||||||
 | 
					       c.push(b[i]);                           // + b
 | 
				
			||||||
 | 
					    return new Float32Array(c);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToSphere = (u,v, i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let phi   = Math.PI * (v - .5);
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * Math.cos(phi);
 | 
				
			||||||
 | 
					    let z = Math.sin(phi);
 | 
				
			||||||
 | 
					    return [i, x,y,z].concat(normalize([x, y, z]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToTube = (u,v,i) => {
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta);
 | 
				
			||||||
 | 
					    let y = Math.sin(theta);
 | 
				
			||||||
 | 
					    let z = 2 * v - 1;
 | 
				
			||||||
 | 
					    return [i,x,y,z].concat(normalize([x,y,0]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 let uvToDisk = (u,v,i,dz) => {
 | 
				
			||||||
 | 
					    if (dz === undefined)
 | 
				
			||||||
 | 
					       dz = 0;
 | 
				
			||||||
 | 
					    let theta = 2 * Math.PI * u;
 | 
				
			||||||
 | 
					    let x = Math.cos(theta) * v;
 | 
				
			||||||
 | 
					    let y = Math.sin(theta) * v;
 | 
				
			||||||
 | 
					    let z = dz;
 | 
				
			||||||
 | 
					    return [i,x,y,z].concat([0,0,Math.sign(z)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 let uvToTorus = (u,v,i,r) => {
 | 
				
			||||||
 | 
					    let theta = 2 * pi;
 | 
				
			||||||
 | 
					    let phi = theta * v;
 | 
				
			||||||
 | 
					    theta *= u;
 | 
				
			||||||
 | 
					    let x = 1 + r * cos(phi);
 | 
				
			||||||
 | 
					    let y = sin(theta)*x;
 | 
				
			||||||
 | 
					    x *=cos(theta);
 | 
				
			||||||
 | 
					    let z = r * sin(phi);
 | 
				
			||||||
 | 
					    let tx = -sin(theta), ty = cos(theta),tsx = sin(phi), tsy = tsx*tx, tsz = cos(phi);
 | 
				
			||||||
 | 
					    tsx*=-ty;
 | 
				
			||||||
 | 
					    return [i,x, y, z].concat(normalize([ty*tsz*0.5, -tx*tsz, tx*tsy-ty*tsx]));
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let createCube = (w, h, l,id) => {
 | 
				
			||||||
 | 
					    let mesh = [];
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,-1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,0,1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,-1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,0,-1]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,-l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,-h/2,l/2,1,0,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, w/2,h/2,-l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,l/2,0,1,0]);
 | 
				
			||||||
 | 
					    mesh=mesh.concat([id, -w/2,h/2,-l/2,0,1,0]);
 | 
				
			||||||
 | 
					    return new Float32Array(mesh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					function updatePositions() {
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    setUniform('3f', 'V0', m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz));
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    setUniform('Matrix3fv', 'transformation', false, [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]);
 | 
				
			||||||
 | 
					    positionsupdated = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function hitTest(pos){
 | 
				
			||||||
 | 
					    if(!enableSelection)
 | 
				
			||||||
 | 
					        return -1; 
 | 
				
			||||||
 | 
					    let m = matrix_rotateY(-mousedx);
 | 
				
			||||||
 | 
					    m = matrix_multiply(m, matrix_rotateX(-mousedy));
 | 
				
			||||||
 | 
					    let V = [m[8] * (fl + mousedz), m[9] * (fl + mousedz), m[10] * (fl + mousedz)];
 | 
				
			||||||
 | 
					    m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
 | 
				
			||||||
 | 
					    let trPos = matrix_multiply([m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]], pos, 3,3);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    let W=normalize(minus(trPos, V));
 | 
				
			||||||
 | 
					    let tMin=10000.;
 | 
				
			||||||
 | 
					    let iMin = -1;
 | 
				
			||||||
 | 
					    for(let i=0;i<cns;i++){
 | 
				
			||||||
 | 
					    let Vp=minus(V, matrix_multiply(SphTr[i], Sph[i]));
 | 
				
			||||||
 | 
					    let B=dot(W,Vp);
 | 
				
			||||||
 | 
					    let C=dot(Vp,Vp)-Sph[i][4]*Sph[i][4];
 | 
				
			||||||
 | 
					    let D=B*B-C;
 | 
				
			||||||
 | 
					    if(D>0.){
 | 
				
			||||||
 | 
					       let t=-B-sqrt(D);
 | 
				
			||||||
 | 
					       if(t > 0.0 && t < tMin){
 | 
				
			||||||
 | 
					          tMin = t; // This is an optimization, we don't have to do lighting/tex
 | 
				
			||||||
 | 
					          iMin = i; // for objects that are occuluded, which is expensive!
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return iMin;
 | 
				
			||||||
 | 
					 } 
 | 
				
			||||||
 | 
					 let matrix_transform = (m,p) => {
 | 
				
			||||||
 | 
					    let x = p[0], y = p[1], z = p[2], w = p[3] === undefined ? 1 : p[3];
 | 
				
			||||||
 | 
					    let q = [ m[0]*x + m[4]*y + m[ 8]*z + m[12]*w,
 | 
				
			||||||
 | 
					              m[1]*x + m[5]*y + m[ 9]*z + m[13]*w,
 | 
				
			||||||
 | 
					              m[2]*x + m[6]*y + m[10]*z + m[14]*w,
 | 
				
			||||||
 | 
					              m[3]*x + m[7]*y + m[11]*z + m[15]*w ];
 | 
				
			||||||
 | 
					    return p[3] === undefined ? [ q[0]/q[3],q[1]/q[3],q[2]/q[3] ] : q;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 let evalSpline = (h,t) => {
 | 
				
			||||||
 | 
					    // t *= (h.length - 2) / 2;
 | 
				
			||||||
 | 
					    // let n = 2 * Math.floor(t);
 | 
				
			||||||
 | 
					    // t = t % 1;
 | 
				
			||||||
 | 
					    // let C = matrix_transform(type, [h[n+0],h[n+2],h[n+1],h[n+3]]);
 | 
				
			||||||
 | 
					    // return t*t*t*C[0] + t*t*C[1] + t*C[2] + C[3];
 | 
				
			||||||
 | 
					    return t*t*t*h[0] + t*t*h[1] + t*h[2] + h[3];
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let getSurface = (S0, S1, u, v,offsetidx, id = 15, additional_offset = 0) => {
 | 
				
			||||||
 | 
					    const epsilon = .001;
 | 
				
			||||||
 | 
					    let z0 = evalSpline(S0, v),
 | 
				
			||||||
 | 
					    z1 = evalSpline(S0, v + epsilon),
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    r0 = evalSpline(S1, v)-path_misc[offsetidx][1] + additional_offset,
 | 
				
			||||||
 | 
					    r1 = evalSpline(S1, v + epsilon),
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    tilt = Math.atan2(r0 - r1, z1 - z0);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    let xx = cos(2 * pi * u), yy = sin(2 * pi * u); 
 | 
				
			||||||
 | 
					    let x = r0 *xx,          // POSITION
 | 
				
			||||||
 | 
					    y = r0 *yy, 
 | 
				
			||||||
 | 
					    z = z0,
 | 
				
			||||||
 | 
					    nx = cos(tilt), // NORMAL
 | 
				
			||||||
 | 
					    ny = nx*yy,
 | 
				
			||||||
 | 
					    nz = sin(tilt);
 | 
				
			||||||
 | 
					    nx*=xx;
 | 
				
			||||||
 | 
					    return [id, x,y,z, nx,ny,nz];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					let concat = (a, b) => b.forEach(e => a.push(e));
 | 
				
			||||||
@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// THIS IS THE SUPPORT LIBRARY.  YOU PROBABLY DON'T WANT TO CHANGE ANYTHING HERE JUST YET. 
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let fragmentShaderHeader = [''                      // WHATEVER CODE WE WANT TO PREDEFINE FOR FRAGMENT SHADERS
 | 
				
			||||||
 | 
					   , 'precision highp float;'
 | 
				
			||||||
 | 
					   , 'float noise(vec3 point) { float r = 0.; for (int i=0;i<16;i++) {'
 | 
				
			||||||
 | 
					   , '  vec3 D, p = point + mod(vec3(i,i/4,i/8) , vec3(4.0,2.0,2.0)) +'
 | 
				
			||||||
 | 
					   , '       1.7*sin(vec3(i,5*i,8*i)), C=floor(p), P=p-C-.5, A=abs(P);'
 | 
				
			||||||
 | 
					   , '  C += mod(C.x+C.y+C.z,2.) * step(max(A.yzx,A.zxy),A) * sign(P);'
 | 
				
			||||||
 | 
					   , '  D=34.*sin(987.*float(i)+876.*C+76.*C.yzx+765.*C.zxy);P=p-C-.5;'
 | 
				
			||||||
 | 
					   , '  r+=sin(6.3*dot(P,fract(D)-.5))*pow(max(0.,1.-2.*dot(P,P)),4.);'
 | 
				
			||||||
 | 
					   , '} return .5 * sin(r); }'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					var ns = 0, cns = 0;
 | 
				
			||||||
 | 
					fragmentShaderHeader+= 'const int ns = ' + ns + ';\n';
 | 
				
			||||||
 | 
					var fragmentShaderDefs = 'const int cns = ' + cns + ';\n';
 | 
				
			||||||
 | 
					let nfsh = fragmentShaderHeader.split('\n').length + 1; // NUMBER OF LINES OF CODE IN fragmentShaderHeader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let isFirefox = navigator.userAgent.indexOf('Firefox') > 0;   
 | 
				
			||||||
 | 
					function getBlob(data) {
 | 
				
			||||||
 | 
					   let bytes = new Array(data.length);
 | 
				
			||||||
 | 
					   for (let i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
					     bytes[i] = data.charCodeAt(i);
 | 
				
			||||||
 | 
					   } 
 | 
				
			||||||
 | 
					   return new Blob([new Uint8Array(bytes)]);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					let texture = [], gl, program;
 | 
				
			||||||
 | 
					let textures = []; 
 | 
				
			||||||
 | 
					let lock = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function loadTexture(gl, url, i) {
 | 
				
			||||||
 | 
					   const level = 0;
 | 
				
			||||||
 | 
					   const internalFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const width = 1;
 | 
				
			||||||
 | 
					   const height = 1;
 | 
				
			||||||
 | 
					   const border = 0;
 | 
				
			||||||
 | 
					   const srcFormat = gl.RGBA;
 | 
				
			||||||
 | 
					   const srcType = gl.UNSIGNED_BYTE;
 | 
				
			||||||
 | 
					   if (texture[i] == null)
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      texture[i] = gl.createTexture();
 | 
				
			||||||
 | 
					      const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         width, height, border, srcFormat, srcType,
 | 
				
			||||||
 | 
					         pixel);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   const image = new Image();
 | 
				
			||||||
 | 
					   image.onload = function () {
 | 
				
			||||||
 | 
					      gl.activeTexture(gl.TEXTURE0+i);
 | 
				
			||||||
 | 
					      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
 | 
				
			||||||
 | 
					      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
 | 
				
			||||||
 | 
					         srcFormat, srcType, image);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					      if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
 | 
				
			||||||
 | 
					         gl.generateMipmap(gl.TEXTURE_2D);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
				
			||||||
 | 
					         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					   };
 | 
				
			||||||
 | 
					   image.src = url;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isPowerOf2(value) {
 | 
				
			||||||
 | 
					   return (value & (value - 1)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function gl_start(canvas, vertexShader, fragmentShader) {           // START WEBGL RUNNING IN A CANVAS
 | 
				
			||||||
 | 
					   console.log('glstart');
 | 
				
			||||||
 | 
					   setTimeout(function () {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
 | 
				
			||||||
 | 
					      } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl = this.gl;
 | 
				
			||||||
 | 
					         program = gl.createProgram();                        // Create the WebGL program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         function addshader(type, src) {                                        // Create and attach a WebGL shader.
 | 
				
			||||||
 | 
					            function spacer(color, width, height) {
 | 
				
			||||||
 | 
					               return '<table bgcolor=' + color +
 | 
				
			||||||
 | 
					                  ' width=' + width +
 | 
				
			||||||
 | 
					                  ' height=' + height + '><tr><td> </td></tr></table>';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            errorMessage.innerHTML = 'There is no real magic, but Computer Graphics is a close one.';
 | 
				
			||||||
 | 
					            //  errorMarker.innerHTML = spacer('white', 1, 1) + '<font size=1 color=white>\u25B6</font>';
 | 
				
			||||||
 | 
					            let shader = gl.createShader(type);
 | 
				
			||||||
 | 
					            gl.shaderSource(shader, src);
 | 
				
			||||||
 | 
					            gl.compileShader(shader);
 | 
				
			||||||
 | 
					            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 | 
				
			||||||
 | 
					               let msg = gl.getShaderInfoLog(shader);
 | 
				
			||||||
 | 
					               console.log('Cannot compile shader:\n\n' + msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               let a = msg.substring(6, msg.length);
 | 
				
			||||||
 | 
					               let line = 0;
 | 
				
			||||||
 | 
					               if (a.substring(0, 3) == ' 0:') {
 | 
				
			||||||
 | 
					                  a = a.substring(3, a.length);
 | 
				
			||||||
 | 
					                  line = parseInt(a) - nfsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  editor.session.setAnnotations([{
 | 
				
			||||||
 | 
					                     row: line,
 | 
				
			||||||
 | 
					                     column: 0,
 | 
				
			||||||
 | 
					                     text: msg, 
 | 
				
			||||||
 | 
					                     type: "error" 
 | 
				
			||||||
 | 
					                  }]);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					               let j = a.indexOf(':');
 | 
				
			||||||
 | 
					               a = 'line ' + (line+1) + a.substring(j, a.length);
 | 
				
			||||||
 | 
					               if ((j = a.indexOf('\n')) > 0)
 | 
				
			||||||
 | 
					                  a = a.substring(0, j);
 | 
				
			||||||
 | 
					               errorMessage.innerHTML = a;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					               editor.session.clearAnnotations();
 | 
				
			||||||
 | 
					            gl.attachShader(program, shader);
 | 
				
			||||||
 | 
					         };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         addshader(gl.VERTEX_SHADER, vertexShader);                         // Add the vertex and fragment shaders.
 | 
				
			||||||
 | 
					         addshader(gl.FRAGMENT_SHADER, fragmentShaderHeader +fragmentShaderDefs+ fragmentShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         gl.linkProgram(program);                                               // Link the program, report any errors.
 | 
				
			||||||
 | 
					         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
 | 
				
			||||||
 | 
					            console.log('Could not link the shader program!');
 | 
				
			||||||
 | 
					         gl.useProgram(program);
 | 
				
			||||||
 | 
					         gl.program = program;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; ++i){
 | 
				
			||||||
 | 
					            loadTexture(gl, './'+(i+1)+'.jpg', i); //Texture loading.
 | 
				
			||||||
 | 
					            textures[i] = i;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
 | 
				
			||||||
 | 
					         positionsupdated = true;
 | 
				
			||||||
 | 
					         let attribs = [
 | 
				
			||||||
 | 
					            .05,.05,.1,  .5,.5,1.,  1.,.5,.5,20.,  0., .0, 1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  1.,.5,.5,  1.,.5,.5,10.,  .3,1.,1.3,
 | 
				
			||||||
 | 
					            .1,.05,.05,  .71,.71,.71,  .71,.71,.71,10.,  0.3,.0,1.5,
 | 
				
			||||||
 | 
					            .1,.1,.1,  .71,.71,.71,  .71,.71,.71,10.,  0.05,0., 1.,
 | 
				
			||||||
 | 
					            .0,.0,.0,  .0,.0,.0,  .0,.0,.0,40.,  0.,.85,1.5
 | 
				
			||||||
 | 
					         ]
 | 
				
			||||||
 | 
					         var offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < ns; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Ambient['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('3fv', 'Diffuse['+i+']', attribs.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					            setUniform('4fv', 'Specular['+i+']', attribs.slice(offset, offset += 4));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'ks['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kr['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					            setUniform('1fv', 'kf['+i+']', attribs.slice(offset, offset += 1));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         offset = 0;
 | 
				
			||||||
 | 
					         for(let i = 0; i < n_shapes; i++){
 | 
				
			||||||
 | 
					            setUniform('3fv', 'starColors['+i+']', starColors.slice(offset, offset += 3));
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					         gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
 | 
				
			||||||
 | 
					         // gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
 | 
				
			||||||
 | 
					         //    [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					         gl.enable(gl.DEPTH_TEST);
 | 
				
			||||||
 | 
					         gl.depthFunc(gl.LEQUAL);
 | 
				
			||||||
 | 
					         gl.clearDepth(-1);
 | 
				
			||||||
 | 
					         //gl.enable(gl.BLEND);  
 | 
				
			||||||
 | 
					         //gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
 | 
				
			||||||
 | 
					         let oid = gl.getAttribLocation(program, 'oid');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(oid);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(oid, 1, gl.FLOAT, false, 4*7, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let aPos = gl.getAttribLocation(program, 'aPos');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(aPos);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 4*7, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         let normal = gl.getAttribLocation(program, 'normal');                      // Set aPos attribute for each vertex.
 | 
				
			||||||
 | 
					         gl.enableVertexAttribArray(normal);
 | 
				
			||||||
 | 
					         gl.vertexAttribPointer(normal, 3, gl.FLOAT, false, 4*7, 4*4);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      canvas.setShaders(vertexShader, fragmentShader);                     // Initialize everything,
 | 
				
			||||||
 | 
					      setInterval(function () {                                             // Start the animation loop.
 | 
				
			||||||
 | 
					         gl = canvas.gl;
 | 
				
			||||||
 | 
					         if (gl.startTime === undefined)                                            // First time through,
 | 
				
			||||||
 | 
					            gl.startTime = Date.now();                                              //    record the start time.
 | 
				
			||||||
 | 
					         animate(gl);
 | 
				
			||||||
 | 
					         //gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);                                    // Render the square.
 | 
				
			||||||
 | 
					      }, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   }, 100); // Wait 100 milliseconds after page has loaded before starting WebGL.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// THE animate() CALLBACK FUNCTION CAN BE REDEFINED IN index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function animate() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setUniform(type, name, a, b, c, d, e, f) {
 | 
				
			||||||
 | 
					   if(gl)
 | 
				
			||||||
 | 
					   {  
 | 
				
			||||||
 | 
					      let loc = gl.getUniformLocation(gl.program, name);
 | 
				
			||||||
 | 
					      (gl['uniform' + type])(loc, a, b, c, d, e, f);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//let VERTEX_SIZE = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let VERTEX_SIZE = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let drawMesh = (mesh, func = gl.TRIANGLE_STRIP) => {
 | 
				
			||||||
 | 
					   gl.bufferData(gl.ARRAY_BUFFER, mesh, gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					   gl.drawArrays(func, 0, mesh.length / VERTEX_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					M11.02,39.45c-2.67-2.97-5.37-5.93-8.01-8.94c-2.42-2.76-2.92-5.66-1.11-8.78c0.81-1.39,1.97-2.41,3.65-2.76c3.9-0.82,7.78-1.71,11.67-2.56c0.86-0.19,1.5-0.51,1.99-1.38c1.9-3.42,3.92-6.76,5.89-10.14c2.6-4.46,9.11-4.47,11.71-0.04
 | 
				
			||||||
 | 
					c1.98,3.37,3.99,6.72,5.89,10.14c0.48,0.86,1.08,1.23,1.96,1.42c3.94,0.85,7.88,1.68,11.81,2.6c2.44,0.57,3.73,2.34,4.36,4.65c0.77,2.82-0.27,5.08-2.16,7.14c-2.52,2.74-4.97,5.53-7.44,8.32c-0.18,0.2-0.41,0.49-0.38,0.72c0.18,1.94,0.41,3.87,0.63,5.8
 | 
				
			||||||
 | 
					c0.12,1.04,0.33,2.07,0.36,3.11c0.05,1.93,0.55,3.8,0.17,5.81c-0.65,3.42-4.81,6.08-8.02,4.95c-1.83-0.64-3.65-1.36-5.44-2.11
 | 
				
			||||||
 | 
					c-2.24-0.94-4.48-1.89-6.67-2.95c-0.75-0.36-1.36-0.27-2.02,0.03c-2.75,1.22-5.47,2.48-8.24,3.66c-1.3,0.56-2.64,1.08-4.01,1.43
 | 
				
			||||||
 | 
					c-2.45,0.63-4.53-0.26-6.14-2.08c-1.65-1.86-2.05-4.09-1.55-6.54c0.26-1.25,0.25-2.55,0.37-3.83
 | 
				
			||||||
 | 
					C10.52,44.62,10.77,42.12,11.02,39.45z M56.81,25.75c0.02-1.65-1.04-2.64-2.79-3.01c-4.04-0.84-8.06-1.74-12.1-2.57
 | 
				
			||||||
 | 
					c-0.91-0.19-1.58-0.65-2.04-1.42c-0.98-1.64-1.93-3.29-2.89-4.93c-1.32-2.26-2.6-4.55-3.98-6.77c-1.12-1.79-2.96-1.74-4.13,0.04
 | 
				
			||||||
 | 
					c-0.65,0.99-1.23,2.04-1.83,3.07c-1.66,2.84-3.32,5.68-4.97,8.52c-0.48,0.83-1.17,1.32-2.14,1.5c-1.82,0.34-3.62,0.74-5.42,1.14
 | 
				
			||||||
 | 
					c-2.45,0.54-4.92,1.04-7.34,1.68C5,23.57,4.46,25.5,5.92,27.15c1.64,1.85,3.31,3.69,4.95,5.54c1.33,1.5,2.68,2.97,3.92,4.54
 | 
				
			||||||
 | 
					c0.38,0.48,0.61,1.21,0.61,1.82c0.01,1.33-0.17,2.65-0.29,3.98c-0.09,0.99-0.19,1.98-0.3,2.97c-0.26,2.26-0.58,4.51-0.77,6.78
 | 
				
			||||||
 | 
					c-0.05,0.52,0.18,1.14,0.48,1.59c0.8,1.19,1.9,1.37,3.54,0.65c3.75-1.66,7.49-3.32,11.22-5.02c1.06-0.48,2.04-0.61,3.13-0.1
 | 
				
			||||||
 | 
					c1.94,0.92,3.9,1.78,5.86,2.65c2.05,0.91,4.11,1.78,6.15,2.69c0.93,0.42,1.77,0.3,2.52-0.37c0.76-0.68,1.19-1.49,0.83-2.55
 | 
				
			||||||
 | 
					c-0.08-0.22-0.12-0.46-0.14-0.7c-0.21-2.51-0.38-5.02-0.61-7.53c-0.12-1.32-0.38-2.63-0.51-3.95c-0.11-1.09-0.17-2.16,0.7-3.09
 | 
				
			||||||
 | 
					c1.83-1.95,3.6-3.95,5.37-5.94c1.23-1.39,2.46-2.79,3.64-4.22C56.54,26.51,56.69,25.99,56.81,25.75z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M66.36,818.02c-106.2-110.9-61-662.8-36.4-813.56c71.19,1.55,58.77-12.26,72.22,57.92c12.21-15.09,10.15-62.97,37.19-55.8
 | 
				
			||||||
 | 
					c-11.66,49.82-40.93,95.92-1.62,142.63c15.22,3.36,56.55-137.38,59.66-136.45c2.49,0.74-22.25,91.36-42.07,162.69
 | 
				
			||||||
 | 
					c8.65,35.12,58.93,87.86,92.29,98.19c14.23-79.7,33.22-361.27,73.99-244.33c41.13-55.27-7.85,38.44-11.46,55.28
 | 
				
			||||||
 | 
					c-18.92,98.99-27.77,241.63,53.45,119.52c20.21-34.31,20.1-114.01,53.68-126.53c3.84-12.82,10.48-73.87,24.02-73.1
 | 
				
			||||||
 | 
					c12.83-0.56,65.91-1.83,35.15,7.41c-61.79-15.5-48.75,200.28-45.07,243.92c2.25,20.42,27.14,13.8,38.12,25.45
 | 
				
			||||||
 | 
					c6.03,4.39,36.44,27.66,18.27,21.91c-40.8-27.63-66.71-54.35-46.2,16.36c-19.89-38.23,1.59-50.13-50.98-60.73
 | 
				
			||||||
 | 
					c8.31-2.96,35.82,10.04,30.87-4.68c-5.47-26.59-6.9-54.75-14.96-80.46c-22.25,80.4-137.99,191.25-134.59,255.33
 | 
				
			||||||
 | 
					c28.43-24.91,73.72-62.68,120.64-46.55c78.08,7.49,7.79-16.2-21.17-22.89c25.68-8.32,88.81,23.09,96.53,50.48
 | 
				
			||||||
 | 
					c-14.88-13.87-8.97-8.07-4.72,6.57c-20.12-14.39-11.58-35.73-44.46-26.75c28.79,18.11,36.81,27.82,49.27,59.28
 | 
				
			||||||
 | 
					c-15.78,0.19,5.06,35.44-28.02-9.3c-39.56-53.22-130.39-50.05-158.76,12.21c-0.57,107.56,60.34,213.63,68.06,323.78
 | 
				
			||||||
 | 
					c1.71,10.93,25.65,17.02,33.27,28.59c-11.57-2.96-19.66-12.97-31.03-16.47c-1.22,193.89-65.94,75.43,75.87,233.86
 | 
				
			||||||
 | 
					c-37.15-15.29-59.1-63.14-92.21-88.24c-15.18-7.04-28.22,43.71-46.26,43.68c57.38-81.24-1.81-123.16,10.19-218.4
 | 
				
			||||||
 | 
					c8.56,76.16-24.52,144.42-59.52,208.52c-8.14,12.44,0.12,54.47-13.87,54.44c9.71-16.15,13.17-61.15-18.44-81.22
 | 
				
			||||||
 | 
					C166.51,916.66,113.43,878.18,66.36,818.02z M925.87,407.64c-54.74-44.89,19.53-197.95-29.21-257.87
 | 
				
			||||||
 | 
					c-7.8,0.23,0.01,139.34-12.78,138.06c-0.76-11.74,2.94-57.56-13.24-57.45c-12.13,43.49-18.05,56.87-20.76,56.35
 | 
				
			||||||
 | 
					c-3.44-0.66-1.37-22.36-9.37-26.3c-1.4-0.69-3.39-0.47-6.27,1.08c-37.75,31.13-5.8-23.15-21.95-34.81
 | 
				
			||||||
 | 
					c-10.77-4.3-7.19,51.51-13.81,37.09c-6.3-84.43-23.11-192.91-70.65-258.62c15.21,86.12,50.46,187.09,38.31,278.79
 | 
				
			||||||
 | 
					c-21.94-86.63-52.72-175.52-70.62-266.49c2.29-9.8-18.19-21-13.94-4.4c30.28,57.1,21.26,334.09,14.6,185.12
 | 
				
			||||||
 | 
					c-1.5-9.87,2.15-67.2-7.12-67.14c-2.9,30.13-5.79,60.27-8.69,90.4c-32.81-59.32-16.97-176.63-52.31-212.83
 | 
				
			||||||
 | 
					c11.12,94.4-6.13,188.39-24.34,280.85c3.07-43.88,20.04-96.61,8.43-137.16c-6.3,14.9-20.93,66.96-26.59,61.57
 | 
				
			||||||
 | 
					c-8.59-0.89-9.05-48.09-14.45-48.15c-3.39-0.04-6.04,18.34-7.95,31.07c-7.59,50.46-15.93,93.98-17.18,93.85
 | 
				
			||||||
 | 
					c8.57-40.75,5.67-198.5-18.91-251.56c4.95,62.89-1.02,125.94-10.23,188.11c3.54-69.31,13.94-164.75-15.9-222.74
 | 
				
			||||||
 | 
					c32.11,126.08-28.75,489.29,30.52,197.35c28.79,98.72-65.28,261.35,58.73,108.86c-37.19,187.32,36.13-32.28,47.76-103.08
 | 
				
			||||||
 | 
					c8.96,94.67-2.01-42.55,6.66-79.88c30.75,97.92,53.06,199.4-5.06,292.92C737.6,336.4,694.28,5.48,752.2,275.59
 | 
				
			||||||
 | 
					c12.58,35.83-30.59,24.88-39.09,50.66c61.29-24.55,38.95-35.44,52.83,53.39c0.4,3.52-0.24,7.19-4.7,7.28
 | 
				
			||||||
 | 
					c-25.86,1.03-45.18,18.23-57.25,38.9c13.43-3.39,50.98-46.17,61.23-33.44c-21.97,29.52-78.97,40.99-72.67,90.22
 | 
				
			||||||
 | 
					c3.55-15.72,78.25-89.59,75.21-54.58c-1.37,4.97-0.6,13.02-7.63,13.72c-61.1,2.32-80.25,119.34-40.63,125.28
 | 
				
			||||||
 | 
					c-13.21-11.3-15.2-27.18-9.08-34.25c7.41-8.57,27.36-4.95,29.07,0.51c0.78,2.5-2.15,5.13-0.96,7.46c0.58,1.13,2.72,1.77,8.48,1.56
 | 
				
			||||||
 | 
					c38.89-7.77,7.11,28.36-12.62,33.66c17.65,7.15,41.53-6.09,43.26-25.21c-13.61-10.4-3.01-29.64,12.23-22.19
 | 
				
			||||||
 | 
					c39.17-39.2-23.35-78.46-17.83-98.65c2.53-4.97,11.94-9.86,47.83-3.67c17.2,5.95,27.38,81.41,34.69,33.83
 | 
				
			||||||
 | 
					c26.79,65.65,1.08,95.95-22.65,157.49c-19.8,84.29-61.4,159.4-148.77,185.06c-117.87,55.02-132.92,97.58-258.09,25.2
 | 
				
			||||||
 | 
					c46.48,32.06,76.67,55,136.6,42.95c-16.18,37.26-58.98,60.98-65.42,102.39c20.1-25.76,40.19-51.51,60.29-77.27
 | 
				
			||||||
 | 
					c-8.67,85.19,10.27,58.11-48.65,125.91c90.48-25.72,17.5-180.83,122.56-177.14c18.96,52.7-4.18,120.02,8.63,173.54
 | 
				
			||||||
 | 
					c2.68-39.19,12.24-88.12,46.19-106.21c456.17,81.79,348.93-736.88,256.65-896.72c22.97,42.24,68.59,278.45,36,201.55
 | 
				
			||||||
 | 
					c-3.91-9.81-16.93-10.42-12.04,2.06c-3.92,64.31,14.29,179.15-11.75,192.94z M348.31,563.23c5.68,9.7,20.47-3.9,12.83-8.26c-3.76-6.73-7.6-13.49-12.17-19.69
 | 
				
			||||||
 | 
					c-8.79-11.93,9.75-6.48,8.3-13.53c21.55,9.97,28.08,14.2,46.14-5.3c-0.61,18.31-0.16,38.03-18.36,50.23
 | 
				
			||||||
 | 
					c18.72,10.53,30.46-6.95,33.62-24.89c-25.93,2.12,1.38-48.33,8.9-22.45c7.53-11.49,6.87-26.71,9.65-39.21
 | 
				
			||||||
 | 
					C420.8,350.18,268.58,459.17,348.31,563.23z M517.13,804.37c-10.18-5.07-29.37-7.14-13.37-22.49
 | 
				
			||||||
 | 
					c18.15-20.96,102.96-23.38,73.03,12.59c29.3-17.57-7.7-35.22-30.46-31.69C518.69,758.1,459.7,799.43,517.13,804.37z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M106.8,0c-3.3,4.6-6.3,9.4-8.8,14.5c-2.8-5-5.7-9.8-8.8-14.5C52.9,32.5,56.8,74.2,98,99.6c0,0,0,0,0,0c0,0,0,0,0,0C139.5,74,142.9,32.2,106.8,0z M5.4,60.7c3.7,4.5,7.4,8.8,11,12.8c-5.4,1-10.9,2.3-16.5,3.9 c19.6,44.6,60.5,53.8,97.4,22.5c0,0,0,0,0,0c0,0,0,0,0,0C85.9,52.4,47.2,36.3,5.4,60.7z M31.2,174.9c5.3-1.5,10.5-3.8,15.6-6.6c-0.8,5.7-1.2,11.3-1.4,16.8c48.5-4.9,69.9-40.9,51.5-85.7c0,0,0,0-0.1,0c0,0,0,0,0,0C48.2,95.8,20.9,127.6,31.2,174.9zM148.3,186.1c-0.4-5.5-0.9-11.1-1.4-16.8c5.1,2.4,10.3,4.6,15.6,6.6c10.4-47.6-17.3-79.1-65.6-75.5c0,0,0,0,0,0c0,0-0.1,0-0.1,0C78.3,145.5,100.1,181.3,148.3,186.1z M195.1,76.9c-5.9-1.5-11.5-2.9-16.5-3.9c3.9-4,7.6-8.3,11-12.8c-42.1-24.6-80.6-8-92.1,39.1c0,0,0,0,0,0c0,0,0,0,0,0C134.9,130.9,175.6,121.2,195.1,76.9z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M35.2,14.9c-2.4,0-4.8,1-6.5,2.7c-1.7-1.7-4.1-2.7-6.5-2.7c-5.6,0.2-10,5-9.8,10.6c0,9.7,13.1,17.8,14.6,18.6c1,0.6,2.3,0.6,3.3,0C31.8,43.2,45,35.2,45,25.5C45.2,19.8,40.8,15.1,35.2,14.9z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M140 20C73 20 20 74 20 140c0 135 136 170 228 303 c88-132 229-173 229-303 c0-66-54-120-120-120c-48 0-90 28-109 69c-19-41-60-69-108-69z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M96,2.86c-2.05,4.41-4.22,9.48-6.33,15.17
 | 
				
			||||||
 | 
						c-1.08,2.92-3,8.28-4.95,15.1c-3.16,11.03-4.62,19.6-5.81,26.71c-2.49,14.88-3.28,26.75-3.45,30.36c-0.02,0.43-0.08,1.78-0.2,3.64
 | 
				
			||||||
 | 
						c-0.36,5.44-0.87,9.65-1.16,11.83c0,0-0.56,4.27-1.3,8.34c-0.19,1.07-0.4,2.13-0.4,2.13c-0.02,0.09-0.03,0.16-0.03,0.17
 | 
				
			||||||
 | 
						c-0.05,0.25-5.9,30.37-5.91,40.92c0,0.85,0.03,3.62-1.34,4.24c-0.46,0.21-0.96,0.13-1.34,0.01c-7.07,0.06-12.87,0.76-16.99,1.42
 | 
				
			||||||
 | 
						c0,0-13,2.1-30.7,9.21c-3.62,1.46-7.03,3-7.34,3.14c-2.48,1.13-4.67,2.19-6.52,3.12c1.83-0.17,4-0.52,6.39-1.21
 | 
				
			||||||
 | 
						c1.84-0.53,3.45-1.16,4.82-1.78c0,0,10.45-3.6,19.4-5.26c5.58-1.03,6.34-0.55,17.45-1.7c6.41-0.66,11.59-1.36,14.88-1.84
 | 
				
			||||||
 | 
						c7.74-1.12,10.4-0.32,11,1.04c0.13,0.29,0.13,0.55,0.11,0.94c-0.24,5.58-3.01,9.41-2.26,13.44c0.04,0.22,0.07,0.33,0.33,1.59
 | 
				
			||||||
 | 
						c0.13,0.62,0.56,2.75,0.85,4.34c0.4,2.22,0.41,2.72,0.72,4.65c0.6,3.67,0.9,5.5,1.48,6.82c1.14,2.59,2.86,4.11,4.88,5.88
 | 
				
			||||||
 | 
						c2.01,1.76,3.74,2.73,6.91,4.49c2.61,1.45,4.85,2.52,6.44,3.23z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M12.43,1.78c0.4,0.5,0.94,1.28,1.36,2.32
 | 
				
			||||||
 | 
						c0.67,1.66,0.67,3.07,0.67,4.45c0,0.92,0.04,4.84,0,6.15c-0.19,6.59,0.61,7.24,0,11.71c-0.34,2.51-0.83,4.02-1.19,4.96
 | 
				
			||||||
 | 
						c-0.18,0.48-0.94,2.43-2.52,4.74c-0.44,0.64-1.1,1.54-3.04,3.63c-3.35,3.61-5.27,4.39-5.19,5.19c0.13,1.28,5.07,2.54,25.78,2.55z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M105,654.21c-7.27-2.1-16.75-4.87-27.83-8.17
 | 
				
			||||||
 | 
						c-40.23-11.98-49.04-15.35-58.28-22.6c-5.71-4.47-14.05-12.37-21.32-25.91C2.14,588.3,8.74,575.32,17.11,560
 | 
				
			||||||
 | 
						c13.51-24.74,22.16-40.57,35.49-58.91c7.85-10.79,19.4-25.32,35.36-41.18c0.72-5.12,1.23-9.06,1.53-11.49
 | 
				
			||||||
 | 
						c0.57-4.57,0.8-6.77,2.34-9.27c1.46-2.37,3.38-3.84,4.75-4.7c0.63-143.54,1.26-287.08,1.89-430.62z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M204.68,0.14c-1.76,0.11-4.62,0.27-8.17,0.38
 | 
				
			||||||
 | 
						c-6.7,0.21-8.06-0.01-10.6,0.77c-3.92,1.2-3.97,2.71-8.07,4.59c-2.36,1.08-3.84,1.26-12.22,2.17c-5.45,0.59-10.87,1.53-16.34,1.91
 | 
				
			||||||
 | 
						c-5.84,0.41-9.63,0.36-12,3.2c-1.04,1.25-1.47,2.63-1.66,3.56c-3.32,18.64-2.48,32.37-1.02,41.62c0.57,3.57,3.63,21.7,0.89,34.76
 | 
				
			||||||
 | 
						c-0.17,0.79-0.64,2.93-1.15,5.97c-0.28,1.67-1.58,9.69-1.66,17.62c-0.05,5.4,1.24,12.84,3.83,27.7c0.5,2.88,1.27,7.13,2.17,13.28
 | 
				
			||||||
 | 
						c0.59,4.02,1.01,7.31,1.28,9.45c-0.52,3.62-0.43,6.53-0.26,8.55c0.29,3.26,0.86,4.56,0.13,6.77c-0.77,2.31-1.92,2.45-2.43,4.85
 | 
				
			||||||
 | 
						c-0.48,2.29,0.42,2.86-0.15,4.95c-0.41,1.49-1.13,2.2-2.79,4.24c-1.48,1.82-2.74,3.8-4.21,5.62c-4.31,5.35-8.49,10.81-12.89,16.09
 | 
				
			||||||
 | 
						c-5.78,6.93-6.86,8.58-17.49,21.96c-18.52,23.3-21.63,26.32-32.55,40.21c-24.98,31.79-37.81,53.07-40.72,57.96
 | 
				
			||||||
 | 
						c0,0-7.82,13.11-17.62,36.64c-2.39,5.73-5.45,13.54-6.38,24.13c-0.58,6.56-0.34,12.62,0,12.64c0.41,0.02,0.43-8.67,2.7-18.95
 | 
				
			||||||
 | 
						c1.86-8.39,4.48-14.51,8.17-22.47c8.35-18.03,12.53-27.04,19.74-39.15c9.69-16.26,19.31-28.61,38.55-53.32
 | 
				
			||||||
 | 
						c5.65-7.26,4.63-5.77,17.11-21.45c13.19-16.57,27.11-32.56,39.85-49.48c0.35-0.47,1.41-1.88,3.13-3.42c0,0,2.37-2.12,5.36-3.58
 | 
				
			||||||
 | 
						c6.09-2.99,20.05-2.23,25.95-2c7.4,0.28,14.81-0.1,22.22-0.1c8.52,0,15.39-0.01,19.63-0.01z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M0.94,0.6c2.08,18.15,2.97,32.18,3.39,41.88
 | 
				
			||||||
 | 
						c0,0,0.86,19.42,2.87,34.97c1.76,13.6,2.61,14.56,5.45,32.49c1.14,7.2,1.2,8.27,5.73,44.13c3.64,28.81,4.03,31.51,4.32,38.54
 | 
				
			||||||
 | 
						c0.2,4.94,0.57,17.17-0.63,32.88c-0.89,11.66-2.25,19.73-3,24.73c-3.72,24.69-3.65,45.64-3.59,66.15
 | 
				
			||||||
 | 
						c0.04,13.85,0.17,33.71,3.42,59.26c2.56,20.15,6,35.46,6.44,62.42c0.01,0.88,0.13,1.85,0.2,3.47c0.31,6.41-0.11,11.45-0.35,14.17
 | 
				
			||||||
 | 
						c-3.35,37.28-5.52,47.52-5.52,47.52c-1.06,4.71-2.95,10.98-0.08,13.41c1.1,0.94,2.42,0.94,9.8,0.98c3.87,0.02,7.02,0.04,8.28,0.05z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
 | 
					M9.22,0C6.92,4.49,4,11.35,2.55,20.09
 | 
				
			||||||
 | 
						c-1.21,7.29-0.82,12.5-0.33,20.94C3.3,59.23,3.79,73.41,3.9,76.76c0.65,20.48-0.9,19.3,0.05,35.96c0.7,12.33,2.2,24.62,2.98,30.95
 | 
				
			||||||
 | 
						c1.78,14.5,2.82,18.69,2.45,27.6c-0.42,10.1-1.94,8.9-2.49,20.33c-0.54,11.15,0.83,13.91,0.19,27.57c-0.35,7.5-0.78,6.96-0.98,13.91
 | 
				
			||||||
 | 
						c-0.12,4.35-0.01,6.38,0.61,21.61c0.24,5.92,0.64,10.99,0.78,17.78c0.12,6.38,0.06,11.89,0.02,14.77
 | 
				
			||||||
 | 
						c-0.07,5.78-0.11,8.68-0.27,11.31c-0.96,16.14-5.06,22.75-1.69,25.57c0.93,0.78,1.57,0.55,8.39,0.78c4.83,0.16,8.78,0.42,11.44,0.61z
 | 
				
			||||||
 | 
					N
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 41 KiB  | 
@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 foregroundColor = vec3(.0841, .5329, .9604);
 | 
				
			||||||
 | 
					uniform vec3 starColors[10];
 | 
				
			||||||
 | 
					uniform vec3 V0;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					vec3 LDir=vec3(.5,.5,.5);
 | 
				
			||||||
 | 
					void main(){
 | 
				
			||||||
 | 
					   vec3 color =foregroundColor.xyz;
 | 
				
			||||||
 | 
					   float sp = 0.4, df = 0.4, amb = 0.4, ex=5., alpha = 1.;
 | 
				
			||||||
 | 
					   vec3 l = vec3(1,1,1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if(id < 1.5) {color = vec3(1.0000, 0.7725, 0.7725);sp = 1.; df=.2; amb = .7, ex = 25.;}
 | 
				
			||||||
 | 
					   else if (id < 2.5) color = vec3(1.,.16,.36);
 | 
				
			||||||
 | 
					   else if (id < 3.5) {color = vec3(1.0000, 0.7725, 0.7725);sp = .5; df=.8; amb = .05;}
 | 
				
			||||||
 | 
					   else if (id < 4.5) {color = vec3(0.9612,0.3057,0.3369);sp = .5; df=.5; amb = .5; ex=20.;}
 | 
				
			||||||
 | 
					   else if (id < 6.5) {}
 | 
				
			||||||
 | 
					   else if (id < 7.5) {color = starColors[0]; sp = 0.3, df = 0.3, amb = 0.8, ex=5.;}
 | 
				
			||||||
 | 
					   else if (id < 8.5) {color = starColors[1]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 9.5) {color = starColors[2]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 10.5) {color = starColors[3]; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 12.5) {color = starColors[4]; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 13.5) {color = starColors[4]*2.; sp = 0., df = 0., amb = 1., ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 14.5) {color = .4*foregroundColor + .8*starColors[4]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   else if (id < 15.5) {color = .3*vec3(0.9612,0.3057,0.3369)+.8*starColors[4]; sp = 0.5, df = 0.5, amb = 0.8, ex=10.,l = color;}
 | 
				
			||||||
 | 
					   if(id < 0.){
 | 
				
			||||||
 | 
					       vec3 P = vec3(sin(glpos.y*1.), sin(glpos.x*1.5+1.),  cos(glpos.z*1.));
 | 
				
			||||||
 | 
					   // APPLY PROCEDURAL NOISE TEXTURE.
 | 
				
			||||||
 | 
					       float cloud = min(0.99, max(0., 1. * noise(1. * P)));
 | 
				
			||||||
 | 
					       color =  (1.-cloud)*color + starColors[5] * cloud*3.;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   vec3 V = V0;
 | 
				
			||||||
 | 
					   vec3 W=normalize(glpos-V);
 | 
				
			||||||
 | 
					   vec3 realLDir=normalize(LDir - glpos);
 | 
				
			||||||
 | 
					   color = color*(amb+ df*max(0.,dot(norm,realLDir)))
 | 
				
			||||||
 | 
					                        + sp*pow(max(0., dot(2.*dot(norm, realLDir)*norm-realLDir, -W)),ex)*l;
 | 
				
			||||||
 | 
					   gl_FragColor=vec4(sqrt(color), alpha);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					uniform mat4 uMatrix;
 | 
				
			||||||
 | 
					uniform mat4 invMatrix;
 | 
				
			||||||
 | 
					uniform mat3 transformation;
 | 
				
			||||||
 | 
					attribute float oid;
 | 
				
			||||||
 | 
					attribute vec3 aPos;
 | 
				
			||||||
 | 
					attribute vec3 normal;
 | 
				
			||||||
 | 
					varying float id;
 | 
				
			||||||
 | 
					varying vec3 glpos;
 | 
				
			||||||
 | 
					varying vec3 norm;
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    vec4 pos = uMatrix * vec4(aPos, 1.);
 | 
				
			||||||
 | 
					    gl_Position = pos ;
 | 
				
			||||||
 | 
					    glpos = pos.xyz;
 | 
				
			||||||
 | 
					    id = oid;
 | 
				
			||||||
 | 
					    norm = normalize(vec4(normal,0.)*invMatrix).xyz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "version": "0.1.0",
 | 
				
			||||||
 | 
					    "configurations": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "Launch index.html",
 | 
				
			||||||
 | 
					            "type": "chrome",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "file": "${workspaceFolder}/index.html",
 | 
				
			||||||
 | 
					            "runtimeExecutable": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
 | 
				
			||||||
 | 
					            "runtimeArgs": ["--args", "--allow-file-access-from-files"]
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "windows",
 | 
				
			||||||
 | 
					            "type": "chrome",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "file": "${workspaceFolder}/index.html",
 | 
				
			||||||
 | 
					            "runtimeExecutable": "C:/Users/sunyi/AppData/Local/Google/Chrome SxS/Application/chrome.exe",
 | 
				
			||||||
 | 
					            "runtimeArgs": ["--args", "--allow-file-access-from-files"]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "python.pythonPath": "/usr/local/bin/python"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||