diff --git a/Readme_Image_processing_Gundeep.pdf b/Readme_Image_processing_Gundeep.pdf new file mode 100644 index 0000000..46ffc7b Binary files /dev/null and b/Readme_Image_processing_Gundeep.pdf differ diff --git a/part1/ImageProcessing/ImageProcessing.sdf b/part1/ImageProcessing/ImageProcessing.sdf new file mode 100644 index 0000000..80a5474 Binary files /dev/null and b/part1/ImageProcessing/ImageProcessing.sdf differ diff --git a/part1/ImageProcessing/ImageProcessing/Gaussian.glsl b/part1/ImageProcessing/ImageProcessing/Gaussian.glsl new file mode 100644 index 0000000..d7db6d6 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/Gaussian.glsl @@ -0,0 +1,25 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; +uniform vec2 u_step; + +const int KERNEL_WIDTH = 3; // Odd +const float offset = 3.0; + +const mat3 kernel= mat3( 0.0625, 0.1250, 0.0625,0.1250, 0.2500, 0.1250,0.0625, 0.1250, 0.0625 ); + +void main(void) +{ + vec3 accum = vec3(0.0); + + for (int i = 0; i < KERNEL_WIDTH; ++i) + { + for (int j = 0; j < KERNEL_WIDTH; ++j) + { + vec2 coord = vec2(v_Texcoords.s + ((float(i) - offset) * u_step.s), v_Texcoords.t + ((float(j) - offset) * u_step.t)); + accum += kernel[i][j]*texture2D(u_image, coord).rgb; + } + } + + gl_FragColor = vec4((accum), 1.0); +} diff --git a/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj b/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj index 554291c..00ea89e 100644 --- a/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj +++ b/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj @@ -1,110 +1,128 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - ImageProcessing - {C53A9886-B4FD-487A-83A5-01406BA9E8BF} - Box_Blur - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - - - - Disabled - ..\..\shared32\glew\include;..\..\shared32\freeglut\include;..\Shader_Loading;..\SOIL;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - glew32.lib;%(AdditionalDependencies) - ..\..\shared32\glew\lib;..\..\shared32\freeglut\lib;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - - - true - Console - true - true - MachineX86 - - - - - {25544c77-3b78-405f-a15d-1231d05969f3} - false - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + CppForm + + + + + ImageProcessing + {C53A9886-B4FD-487A-83A5-01406BA9E8BF} + Box_Blur + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + ..\..\shared32\glew\include;..\..\shared32\freeglut\include;..\Shader_Loading;..\SOIL;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + glew32.lib;%(AdditionalDependencies) + ..\..\shared32\glew\lib;..\..\shared32\freeglut\lib;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + true + Console + true + true + MachineX86 + + + + + {25544c77-3b78-405f-a15d-1231d05969f3} + false + + + + + + + + + + + + \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj.filters b/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj.filters new file mode 100644 index 0000000..045c52a --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj.filters @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj.user b/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/ImageProcessing.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/brightness.glsl b/part1/ImageProcessing/ImageProcessing/brightness.glsl new file mode 100644 index 0000000..e17e06a --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/brightness.glsl @@ -0,0 +1,8 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; + +void main(void) +{ + gl_FragColor = vec4(vec3(clamp((texture2D(u_image, v_Texcoords).r*1.6),0.0,1.0),clamp((texture2D(u_image, v_Texcoords).g*1.6),0.0,1.0),clamp((texture2D(u_image, v_Texcoords).b*1.6),0.0,1.0)) ,1); +} \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/contrast.glsl b/part1/ImageProcessing/ImageProcessing/contrast.glsl new file mode 100644 index 0000000..eab7f20 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/contrast.glsl @@ -0,0 +1,12 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; +float value=0.1; + +void main(void) +{ + vec3 contrast=vec3(0.0); + contrast=(texture2D(u_image, v_Texcoords).rgb -vec3(0.5))*2.0 +0.5; + //(texture2D(u_image, v_Texcoords).rgb= (texture2D(u_image, v_Texcoords).rgb*(texture2D(u_image, v_Texcoords).rgb+valu + gl_FragColor = vec4(vec3(contrast),1); +} \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/edge_detection.glsl b/part1/ImageProcessing/ImageProcessing/edge_detection.glsl new file mode 100644 index 0000000..1a34fb6 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/edge_detection.glsl @@ -0,0 +1,30 @@ + +varying vec2 v_Texcoords; + +uniform sampler2D u_image; +uniform vec2 u_step; + +const int KERNEL_WIDTH = 3; // Odd +const float offset = 1.0; + +const mat3 sobel= mat3(-1, -2, -1, 0, 0, 0, 1, 2, 1); + +void main(void) +{ + vec2 accum = vec2(0.0); + + for (int i = 0; i < KERNEL_WIDTH; ++i) + { + for (int j = 0; j < KERNEL_WIDTH; ++j) + { + + vec2 coord = vec2(v_Texcoords.s + ((float(i) - offset) * u_step.s), v_Texcoords.t + ((float(j) - offset) * u_step.t)); + + accum.x += sobel[i][j]*texture2D(u_image, coord).r; + accum.y += sobel[j][i]*texture2D(u_image, coord).g; + + } + } + + gl_FragColor = vec4(vec3(length(accum)), 1.0); +} \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/grayscale.glsl b/part1/ImageProcessing/ImageProcessing/grayscale.glsl new file mode 100644 index 0000000..90e6c6e --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/grayscale.glsl @@ -0,0 +1,13 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; + +void main(void) +{ + const vec3 W = vec3(0.2125, 0.7154, 0.0721); + float luminance = dot(vec3(texture2D(u_image, v_Texcoords).r,texture2D(u_image, v_Texcoords).g,texture2D(u_image, v_Texcoords).g), W); + gl_FragColor = vec4(luminance); + //gl_FragColor = vec3(1.0f)-texture2D(u_image, v_Texcoords); +} + +//Then set the output r, g, and b components to the lumiance. \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/main.cpp b/part1/ImageProcessing/ImageProcessing/main.cpp index 3b1444d..3fba33f 100644 --- a/part1/ImageProcessing/ImageProcessing/main.cpp +++ b/part1/ImageProcessing/ImageProcessing/main.cpp @@ -1,146 +1,188 @@ -#include -#include -#include -#include "Utility.h" -#include "SOIL.h" - -int width = 640; -int height = 480; - -GLuint positionLocation = 0; -GLuint texcoordsLocation = 1; -const char *attributeLocations[] = { "Position", "Tex" }; - -GLuint passthroughProgram; -GLuint boxBlurProgram; - -GLuint initShader(const char *vertexShaderPath, const char *fragmentShaderPath) -{ - GLuint program = Utility::createProgram(vertexShaderPath, fragmentShaderPath, attributeLocations, 2); - GLint location; - - glUseProgram(program); - - if ((location = glGetUniformLocation(program, "u_image")) != -1) - { - glUniform1i(location, 0); - } - - if ((location = glGetUniformLocation(program, "u_step")) != -1) - { - glUniform2f(location, 1.0f / (float)width, 1.0f / (float)height); - } - - return program; -} - -void initTextures() -{ - GLuint image = SOIL_load_OGL_texture("Valve.png", 3, 0, 0); - glBindTexture(GL_TEXTURE_2D, image); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -} - -void initVAO(void) -{ - GLfloat vertices[] = - { - -1.0f, -1.0f, - 1.0f, -1.0f, - 1.0f, 1.0f, - -1.0f, 1.0f, - }; - - GLfloat texcoords[] = - { - 1.0f, 1.0f, - 0.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 0.0f - }; - - GLushort indices[] = { 0, 1, 3, 3, 1, 2 }; - - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - GLuint vertexBufferObjID[3]; - glGenBuffers(3, vertexBufferObjID); - - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glVertexAttribPointer((GLuint)positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(positionLocation); - - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW); - glVertexAttribPointer((GLuint)texcoordsLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(texcoordsLocation); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObjID[2]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); -} - -void display(void) -{ - glClear(GL_COLOR_BUFFER_BIT); - - // VAO, shader program, and texture already bound - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); - - glutPostRedisplay(); - glutSwapBuffers(); -} - -void keyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case '1': - glUseProgram(passthroughProgram); - break; - case '2': - glUseProgram(boxBlurProgram); - break; - } -} - -void reshape(int w, int h) -{ - glViewport(0, 0, (GLsizei)w, (GLsizei)h); -} - -int main(int argc, char* argv[]) -{ - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - glutInitWindowSize(width, height); - glutCreateWindow("Image Processing"); - glewInit(); - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - std::cout << "glewInit failed, aborting." << std::endl; - exit (1); - } - std::cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << std::endl; - std::cout << "OpenGL version " << glGetString(GL_VERSION) << " supported" << std::endl; - - initVAO(); - initTextures(); - passthroughProgram = initShader("passthroughVS.glsl", "passthroughFS.glsl"); - boxBlurProgram = initShader("passthroughVS.glsl", "boxBlurFS.glsl"); - - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutKeyboardFunc(keyboard); - - glUseProgram(passthroughProgram); - glActiveTexture(GL_TEXTURE0); - - glutMainLoop(); - return 0; +#include +#include +#include +#include "Utility.h" +#include "SOIL.h" + +int width = 640; +int height = 480; + +GLuint positionLocation = 0; +GLuint texcoordsLocation = 1; +const char *attributeLocations[] = { "Position", "Tex" }; + +GLuint passthroughProgram; +GLuint boxBlurProgram; +GLuint negativeProgram; +GLuint gaussianProgram; +GLuint grayscaleProgram; +GLuint edge_detectionProgram; +GLuint toonProgram; +GLuint brightnessProgram; +GLuint contrastProgram; +GLuint sepiaProgram; + + +GLuint initShader(const char *vertexShaderPath, const char *fragmentShaderPath) +{ + GLuint program = Utility::createProgram(vertexShaderPath, fragmentShaderPath, attributeLocations, 2); + GLint location; + + glUseProgram(program); + + if ((location = glGetUniformLocation(program, "u_image")) != -1) + { + glUniform1i(location, 0); + } + + if ((location = glGetUniformLocation(program, "u_step")) != -1) + { + glUniform2f(location, 1.0f / (float)width, 1.0f / (float)height); + } + + return program; +} + +void initTextures() +{ + GLuint image = SOIL_load_OGL_texture("Valve.png", 3, 0, 0); + glBindTexture(GL_TEXTURE_2D, image); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} + +void initVAO(void) +{ + GLfloat vertices[] = + { + -1.0f, -1.0f, + 1.0f, -1.0f, + 1.0f, 1.0f, + -1.0f, 1.0f, + }; + + GLfloat texcoords[] = + { + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f + }; + + GLushort indices[] = { 0, 1, 3, 3, 1, 2 }; + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint vertexBufferObjID[3]; + glGenBuffers(3, vertexBufferObjID); + + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glVertexAttribPointer((GLuint)positionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(positionLocation); + + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW); + glVertexAttribPointer((GLuint)texcoordsLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(texcoordsLocation); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObjID[2]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); +} + +void display(void) +{ + glClear(GL_COLOR_BUFFER_BIT); + + // VAO, shader program, and texture already bound + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); + + glutPostRedisplay(); + glutSwapBuffers(); +} + +void keyboard(unsigned char key, int x, int y) +{ + switch (key) + { + case '1': + glUseProgram(passthroughProgram); + break; + case '2': + glUseProgram(boxBlurProgram); + break; + case '3': + glUseProgram(negativeProgram); + break; + case '4': + glUseProgram(gaussianProgram); + break; + case '5': + glUseProgram(grayscaleProgram); + break; + case '6': + glUseProgram(edge_detectionProgram); + break; + case '7': + glUseProgram(toonProgram); + break; + case '8': + glUseProgram(brightnessProgram); + break; + case '9': + glUseProgram(sepiaProgram); + break; + case '0': + glUseProgram(contrastProgram); + break; + + } +} + +void reshape(int w, int h) +{ + glViewport(0, 0, (GLsizei)w, (GLsizei)h); +} + +int main(int argc, char* argv[]) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); + glutInitWindowSize(width, height); + glutCreateWindow("Image Processing"); + glewInit(); + GLenum err = glewInit(); + if (GLEW_OK != err) + { + /* Problem: glewInit failed, something is seriously wrong. */ + std::cout << "glewInit failed, aborting." << std::endl; + exit (1); + } + std::cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << std::endl; + std::cout << "OpenGL version " << glGetString(GL_VERSION) << " supported" << std::endl; + + initVAO(); + initTextures(); + passthroughProgram = initShader("passthroughVS.glsl", "passthroughFS.glsl"); + boxBlurProgram = initShader("passthroughVS.glsl", "boxBlurFS.glsl"); + negativeProgram= initShader("passthroughVS.glsl", "negative.glsl"); + gaussianProgram= initShader("passthroughVS.glsl", "Gaussian.glsl"); + grayscaleProgram= initShader("passthroughVS.glsl", "grayscale.glsl"); + edge_detectionProgram= initShader("passthroughVS.glsl", "edge_detection.glsl"); + brightnessProgram=initShader("passthroughVS.glsl", "brightness.glsl"); + sepiaProgram=initShader("passthroughVS.glsl", "sepia.glsl"); + contrastProgram=initShader("passthroughVS.glsl", "contrast.glsl"); + toonProgram=initShader("passthroughVS.glsl", "toon.glsl"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyboard); + + glUseProgram(passthroughProgram); + glActiveTexture(GL_TEXTURE0); + + glutMainLoop(); + return 0; } \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/negative (2).glsl b/part1/ImageProcessing/ImageProcessing/negative (2).glsl new file mode 100644 index 0000000..e69de29 diff --git a/part1/ImageProcessing/ImageProcessing/negative.glsl b/part1/ImageProcessing/ImageProcessing/negative.glsl new file mode 100644 index 0000000..86cd375 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/negative.glsl @@ -0,0 +1,9 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; + +void main(void) +{ + gl_FragColor = vec4(1.0)- texture2D(u_image, v_Texcoords); + //gl_FragColor = vec3(1.0f)-texture2D(u_image, v_Texcoords); +} \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/passthroughFS.glsl b/part1/ImageProcessing/ImageProcessing/passthroughFS.glsl index fd4e15b..9348c3e 100644 --- a/part1/ImageProcessing/ImageProcessing/passthroughFS.glsl +++ b/part1/ImageProcessing/ImageProcessing/passthroughFS.glsl @@ -1,8 +1,9 @@ -varying vec2 v_Texcoords; - -uniform sampler2D u_image; - -void main(void) -{ - gl_FragColor = texture2D(u_image, v_Texcoords); -} +varying vec2 v_Texcoords; + +uniform sampler2D u_image; + +void main(void) +{ + gl_FragColor = texture2D(u_image, v_Texcoords); + //gl_FragColor = vec3(1.0f)-texture2D(u_image, v_Texcoords); +} diff --git a/part1/ImageProcessing/ImageProcessing/sepia.glsl b/part1/ImageProcessing/ImageProcessing/sepia.glsl new file mode 100644 index 0000000..ad8eab2 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/sepia.glsl @@ -0,0 +1,12 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; + +void main(void) +{ + const vec3 sepia = vec3(0.3625, 0.1494, 0.0701); + float weight=0.23; + vec3 luminance = texture2D(u_image, v_Texcoords)*(1.0 -weight) + sepia*(1.0 - weight); + gl_FragColor = vec4(luminance,1); + //gl_FragColor = vec3(1.0f)-texture2D(u_image, v_Texcoords); +} diff --git a/part1/ImageProcessing/ImageProcessing/toon.cpp b/part1/ImageProcessing/ImageProcessing/toon.cpp new file mode 100644 index 0000000..968f970 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/toon.cpp @@ -0,0 +1,2 @@ +#include "toon.h" + diff --git a/part1/ImageProcessing/ImageProcessing/toon.glsl b/part1/ImageProcessing/ImageProcessing/toon.glsl new file mode 100644 index 0000000..c964977 --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/toon.glsl @@ -0,0 +1,42 @@ + +varying vec2 v_Texcoords; + +uniform sampler2D u_image; +uniform vec2 u_step; + +const int KERNEL_WIDTH = 3; // Odd +const float offset = 1.0; + +const mat3 sobel= mat3(-1, -2, -1, 0, 0, 0, 1, 2, 1); + +void main(void) +{ + vec3 accum = vec3(0.0); + + for (int i = 0; i < KERNEL_WIDTH; ++i) + { + for (int j = 0; j < KERNEL_WIDTH; ++j) + { + + vec2 coord = vec2(v_Texcoords.s + ((float(i) - offset) * u_step.s), v_Texcoords.t + ((float(j) - offset) * u_step.t)); + + accum.x += sobel[i][j]*texture2D(u_image, coord).r; + accum.y += sobel[j][i]*texture2D(u_image, coord).g; + + } + } + + if (length(accum)>0.5) + { + gl_FragColor= vec4(1.0); + } + else + { + float quantize =5; // determine it + vec3 rgb=texture2D(u_image,v_Texcoords).rgb * quantize; + rgb =rgb+ vec3(0.5); + ivec3 irgb = ivec3(rgb); + rgb = vec3(irgb) / quantize; + gl_FragColor = vec4(rgb, 1.0); + } +} \ No newline at end of file diff --git a/part1/ImageProcessing/ImageProcessing/toon.h b/part1/ImageProcessing/ImageProcessing/toon.h new file mode 100644 index 0000000..93d70fc --- /dev/null +++ b/part1/ImageProcessing/ImageProcessing/toon.h @@ -0,0 +1,59 @@ +#pragma once + +namespace Box_Blur { + + using namespace System; + using namespace System::ComponentModel; + using namespace System::Collections; + using namespace System::Windows::Forms; + using namespace System::Data; + using namespace System::Drawing; + + /// + /// Summary for toon + /// + public ref class toon : public System::Windows::Forms::Form + { + public: + toon(void) + { + InitializeComponent(); + // + //TODO: Add the constructor code here + // + } + + protected: + /// + /// Clean up any resources being used. + /// + ~toon() + { + if (components) + { + delete components; + } + } + + private: + /// + /// Required designer variable. + /// + System::ComponentModel::Container ^components; + +#pragma region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + void InitializeComponent(void) + { + this->components = gcnew System::ComponentModel::Container(); + this->Size = System::Drawing::Size(300,300); + this->Text = L"toon"; + this->Padding = System::Windows::Forms::Padding(0); + this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; + } +#pragma endregion + }; +} diff --git a/part1/ImageProcessing/SOIL/SOIL.vcxproj.user b/part1/ImageProcessing/SOIL/SOIL.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/part1/ImageProcessing/SOIL/SOIL.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/part1/ImageProcessing/negative.glsl b/part1/ImageProcessing/negative.glsl new file mode 100644 index 0000000..62a937b --- /dev/null +++ b/part1/ImageProcessing/negative.glsl @@ -0,0 +1,9 @@ +varying vec2 v_Texcoords; + +uniform sampler2D u_image; + +void main(void) +{ + gl_FragColor = vec4(1.0f)- texture2D(u_image, v_Texcoords); + //gl_FragColor = vec3(1.0f)-texture2D(u_image, v_Texcoords); +} \ No newline at end of file diff --git a/part2/gl-matrix.js b/part2/River_with_banks/gl-matrix.js similarity index 96% rename from part2/gl-matrix.js rename to part2/River_with_banks/gl-matrix.js index 8e8a40b..2e1bdb9 100644 --- a/part2/gl-matrix.js +++ b/part2/River_with_banks/gl-matrix.js @@ -1,1909 +1,1909 @@ -/** - * @fileOverview gl-matrix - High performance matrix and vector operations for WebGL - * @author Brandon Jones - * @version 1.2.3 - */ - -/* - * Copyright (c) 2011 Brandon Jones - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - */ - -"use strict"; - -// Type declarations -(function() { - // account for CommonJS environments - var _global = (typeof(exports) != 'undefined') ? global : window; - _global.glMatrixArrayType = _global.MatrixArray = null; - - /** - * @class 3 Dimensional Vector - * @name vec3 - */ - _global.vec3 = {}; - - /** - * @class 3x3 Matrix - * @name mat3 - */ - _global.mat3 = {}; - - /** - * @class 4x4 Matrix - * @name mat4 - */ - _global.mat4 = {}; - - /** - * @class Quaternion - * @name quat4 - */ - _global.quat4 = {}; - - // explicitly sets and returns the type of array to use within glMatrix - _global.setMatrixArrayType = function(type) { - return glMatrixArrayType = MatrixArray = type; - }; - - // auto-detects and returns the best type of array to use within glMatrix, falling - // back to Array if typed arrays are unsupported - _global.determineMatrixArrayType = function() { - return setMatrixArrayType((typeof Float32Array !== 'undefined') ? Float32Array : Array); - }; - - determineMatrixArrayType(); -})(); - -/* - * vec3 - */ - -/** - * Creates a new instance of a vec3 using the default array type - * Any javascript array-like objects containing at least 3 numeric elements can serve as a vec3 - * - * @param {vec3} [vec] vec3 containing values to initialize with - * - * @returns {vec3} New vec3 - */ -vec3.create = function (vec) { - var dest = new MatrixArray(3); - - if (vec) { - dest[0] = vec[0]; - dest[1] = vec[1]; - dest[2] = vec[2]; - } else { - dest[0] = dest[1] = dest[2] = 0; - } - - return dest; -}; - -/** - * Copies the values of one vec3 to another - * - * @param {vec3} vec vec3 containing values to copy - * @param {vec3} dest vec3 receiving copied values - * - * @returns {vec3} dest - */ -vec3.set = function (vec, dest) { - dest[0] = vec[0]; - dest[1] = vec[1]; - dest[2] = vec[2]; - - return dest; -}; - -/** - * Performs a vector addition - * - * @param {vec3} vec First operand - * @param {vec3} vec2 Second operand - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.add = function (vec, vec2, dest) { - if (!dest || vec === dest) { - vec[0] += vec2[0]; - vec[1] += vec2[1]; - vec[2] += vec2[2]; - return vec; - } - - dest[0] = vec[0] + vec2[0]; - dest[1] = vec[1] + vec2[1]; - dest[2] = vec[2] + vec2[2]; - return dest; -}; - -/** - * Performs a vector subtraction - * - * @param {vec3} vec First operand - * @param {vec3} vec2 Second operand - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.subtract = function (vec, vec2, dest) { - if (!dest || vec === dest) { - vec[0] -= vec2[0]; - vec[1] -= vec2[1]; - vec[2] -= vec2[2]; - return vec; - } - - dest[0] = vec[0] - vec2[0]; - dest[1] = vec[1] - vec2[1]; - dest[2] = vec[2] - vec2[2]; - return dest; -}; - -/** - * Performs a vector multiplication - * - * @param {vec3} vec First operand - * @param {vec3} vec2 Second operand - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.multiply = function (vec, vec2, dest) { - if (!dest || vec === dest) { - vec[0] *= vec2[0]; - vec[1] *= vec2[1]; - vec[2] *= vec2[2]; - return vec; - } - - dest[0] = vec[0] * vec2[0]; - dest[1] = vec[1] * vec2[1]; - dest[2] = vec[2] * vec2[2]; - return dest; -}; - -/** - * Negates the components of a vec3 - * - * @param {vec3} vec vec3 to negate - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.negate = function (vec, dest) { - if (!dest) { dest = vec; } - - dest[0] = -vec[0]; - dest[1] = -vec[1]; - dest[2] = -vec[2]; - return dest; -}; - -/** - * Multiplies the components of a vec3 by a scalar value - * - * @param {vec3} vec vec3 to scale - * @param {number} val Value to scale by - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.scale = function (vec, val, dest) { - if (!dest || vec === dest) { - vec[0] *= val; - vec[1] *= val; - vec[2] *= val; - return vec; - } - - dest[0] = vec[0] * val; - dest[1] = vec[1] * val; - dest[2] = vec[2] * val; - return dest; -}; - -/** - * Generates a unit vector of the same direction as the provided vec3 - * If vector length is 0, returns [0, 0, 0] - * - * @param {vec3} vec vec3 to normalize - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.normalize = function (vec, dest) { - if (!dest) { dest = vec; } - - var x = vec[0], y = vec[1], z = vec[2], - len = Math.sqrt(x * x + y * y + z * z); - - if (!len) { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - return dest; - } else if (len === 1) { - dest[0] = x; - dest[1] = y; - dest[2] = z; - return dest; - } - - len = 1 / len; - dest[0] = x * len; - dest[1] = y * len; - dest[2] = z * len; - return dest; -}; - -/** - * Generates the cross product of two vec3s - * - * @param {vec3} vec First operand - * @param {vec3} vec2 Second operand - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.cross = function (vec, vec2, dest) { - if (!dest) { dest = vec; } - - var x = vec[0], y = vec[1], z = vec[2], - x2 = vec2[0], y2 = vec2[1], z2 = vec2[2]; - - dest[0] = y * z2 - z * y2; - dest[1] = z * x2 - x * z2; - dest[2] = x * y2 - y * x2; - return dest; -}; - -/** - * Caclulates the length of a vec3 - * - * @param {vec3} vec vec3 to calculate length of - * - * @returns {number} Length of vec - */ -vec3.length = function (vec) { - var x = vec[0], y = vec[1], z = vec[2]; - return Math.sqrt(x * x + y * y + z * z); -}; - -/** - * Caclulates the dot product of two vec3s - * - * @param {vec3} vec First operand - * @param {vec3} vec2 Second operand - * - * @returns {number} Dot product of vec and vec2 - */ -vec3.dot = function (vec, vec2) { - return vec[0] * vec2[0] + vec[1] * vec2[1] + vec[2] * vec2[2]; -}; - -/** - * Generates a unit vector pointing from one vector to another - * - * @param {vec3} vec Origin vec3 - * @param {vec3} vec2 vec3 to point to - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.direction = function (vec, vec2, dest) { - if (!dest) { dest = vec; } - - var x = vec[0] - vec2[0], - y = vec[1] - vec2[1], - z = vec[2] - vec2[2], - len = Math.sqrt(x * x + y * y + z * z); - - if (!len) { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - return dest; - } - - len = 1 / len; - dest[0] = x * len; - dest[1] = y * len; - dest[2] = z * len; - return dest; -}; - -/** - * Performs a linear interpolation between two vec3 - * - * @param {vec3} vec First vector - * @param {vec3} vec2 Second vector - * @param {number} lerp Interpolation amount between the two inputs - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.lerp = function (vec, vec2, lerp, dest) { - if (!dest) { dest = vec; } - - dest[0] = vec[0] + lerp * (vec2[0] - vec[0]); - dest[1] = vec[1] + lerp * (vec2[1] - vec[1]); - dest[2] = vec[2] + lerp * (vec2[2] - vec[2]); - - return dest; -}; - -/** - * Calculates the euclidian distance between two vec3 - * - * Params: - * @param {vec3} vec First vector - * @param {vec3} vec2 Second vector - * - * @returns {number} Distance between vec and vec2 - */ -vec3.dist = function (vec, vec2) { - var x = vec2[0] - vec[0], - y = vec2[1] - vec[1], - z = vec2[2] - vec[2]; - - return Math.sqrt(x*x + y*y + z*z); -}; - -/** - * Projects the specified vec3 from screen space into object space - * Based on the Mesa gluUnProject implementation - * - * @param {vec3} vec Screen-space vector to project - * @param {mat4} view View matrix - * @param {mat4} proj Projection matrix - * @param {vec4} viewport Viewport as given to gl.viewport [x, y, width, height] - * @param {vec3} [dest] vec3 receiving unprojected result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -vec3.unproject = function (vec, view, proj, viewport, dest) { - if (!dest) { dest = vec; } - - var m = mat4.create(); - var v = new MatrixArray(4); - - v[0] = (vec[0] - viewport[0]) * 2.0 / viewport[2] - 1.0; - v[1] = (vec[1] - viewport[1]) * 2.0 / viewport[3] - 1.0; - v[2] = 2.0 * vec[2] - 1.0; - v[3] = 1.0; - - mat4.multiply(proj, view, m); - if(!mat4.inverse(m)) { return null; } - - mat4.multiplyVec4(m, v); - if(v[3] === 0.0) { return null; } - - dest[0] = v[0] / v[3]; - dest[1] = v[1] / v[3]; - dest[2] = v[2] / v[3]; - - return dest; -}; - -/** - * Returns a string representation of a vector - * - * @param {vec3} vec Vector to represent as a string - * - * @returns {string} String representation of vec - */ -vec3.str = function (vec) { - return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']'; -}; - -/* - * mat3 - */ - -/** - * Creates a new instance of a mat3 using the default array type - * Any javascript array-like object containing at least 9 numeric elements can serve as a mat3 - * - * @param {mat3} [mat] mat3 containing values to initialize with - * - * @returns {mat3} New mat3 - */ -mat3.create = function (mat) { - var dest = new MatrixArray(9); - - if (mat) { - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[3]; - dest[4] = mat[4]; - dest[5] = mat[5]; - dest[6] = mat[6]; - dest[7] = mat[7]; - dest[8] = mat[8]; - } - - return dest; -}; - -/** - * Copies the values of one mat3 to another - * - * @param {mat3} mat mat3 containing values to copy - * @param {mat3} dest mat3 receiving copied values - * - * @returns {mat3} dest - */ -mat3.set = function (mat, dest) { - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[3]; - dest[4] = mat[4]; - dest[5] = mat[5]; - dest[6] = mat[6]; - dest[7] = mat[7]; - dest[8] = mat[8]; - return dest; -}; - -/** - * Sets a mat3 to an identity matrix - * - * @param {mat3} dest mat3 to set - * - * @returns dest if specified, otherwise a new mat3 - */ -mat3.identity = function (dest) { - if (!dest) { dest = mat3.create(); } - dest[0] = 1; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - dest[4] = 1; - dest[5] = 0; - dest[6] = 0; - dest[7] = 0; - dest[8] = 1; - return dest; -}; - -/** - * Transposes a mat3 (flips the values over the diagonal) - * - * Params: - * @param {mat3} mat mat3 to transpose - * @param {mat3} [dest] mat3 receiving transposed values. If not specified result is written to mat - * - * @returns {mat3} dest is specified, mat otherwise - */ -mat3.transpose = function (mat, dest) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) { - var a01 = mat[1], a02 = mat[2], - a12 = mat[5]; - - mat[1] = mat[3]; - mat[2] = mat[6]; - mat[3] = a01; - mat[5] = mat[7]; - mat[6] = a02; - mat[7] = a12; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[3]; - dest[2] = mat[6]; - dest[3] = mat[1]; - dest[4] = mat[4]; - dest[5] = mat[7]; - dest[6] = mat[2]; - dest[7] = mat[5]; - dest[8] = mat[8]; - return dest; -}; - -/** - * Copies the elements of a mat3 into the upper 3x3 elements of a mat4 - * - * @param {mat3} mat mat3 containing values to copy - * @param {mat4} [dest] mat4 receiving copied values - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -mat3.toMat4 = function (mat, dest) { - if (!dest) { dest = mat4.create(); } - - dest[15] = 1; - dest[14] = 0; - dest[13] = 0; - dest[12] = 0; - - dest[11] = 0; - dest[10] = mat[8]; - dest[9] = mat[7]; - dest[8] = mat[6]; - - dest[7] = 0; - dest[6] = mat[5]; - dest[5] = mat[4]; - dest[4] = mat[3]; - - dest[3] = 0; - dest[2] = mat[2]; - dest[1] = mat[1]; - dest[0] = mat[0]; - - return dest; -}; - -/** - * Returns a string representation of a mat3 - * - * @param {mat3} mat mat3 to represent as a string - * - * @param {string} String representation of mat - */ -mat3.str = function (mat) { - return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + - ', ' + mat[3] + ', ' + mat[4] + ', ' + mat[5] + - ', ' + mat[6] + ', ' + mat[7] + ', ' + mat[8] + ']'; -}; - -/* - * mat4 - */ - -/** - * Creates a new instance of a mat4 using the default array type - * Any javascript array-like object containing at least 16 numeric elements can serve as a mat4 - * - * @param {mat4} [mat] mat4 containing values to initialize with - * - * @returns {mat4} New mat4 - */ -mat4.create = function (mat) { - var dest = new MatrixArray(16); - - if (mat) { - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[3]; - dest[4] = mat[4]; - dest[5] = mat[5]; - dest[6] = mat[6]; - dest[7] = mat[7]; - dest[8] = mat[8]; - dest[9] = mat[9]; - dest[10] = mat[10]; - dest[11] = mat[11]; - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - } - - return dest; -}; - -/** - * Copies the values of one mat4 to another - * - * @param {mat4} mat mat4 containing values to copy - * @param {mat4} dest mat4 receiving copied values - * - * @returns {mat4} dest - */ -mat4.set = function (mat, dest) { - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[3]; - dest[4] = mat[4]; - dest[5] = mat[5]; - dest[6] = mat[6]; - dest[7] = mat[7]; - dest[8] = mat[8]; - dest[9] = mat[9]; - dest[10] = mat[10]; - dest[11] = mat[11]; - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - return dest; -}; - -/** - * Sets a mat4 to an identity matrix - * - * @param {mat4} dest mat4 to set - * - * @returns {mat4} dest - */ -mat4.identity = function (dest) { - if (!dest) { dest = mat4.create(); } - dest[0] = 1; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - dest[4] = 0; - dest[5] = 1; - dest[6] = 0; - dest[7] = 0; - dest[8] = 0; - dest[9] = 0; - dest[10] = 1; - dest[11] = 0; - dest[12] = 0; - dest[13] = 0; - dest[14] = 0; - dest[15] = 1; - return dest; -}; - -/** - * Transposes a mat4 (flips the values over the diagonal) - * - * @param {mat4} mat mat4 to transpose - * @param {mat4} [dest] mat4 receiving transposed values. If not specified result is written to mat - * - * @param {mat4} dest is specified, mat otherwise - */ -mat4.transpose = function (mat, dest) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (!dest || mat === dest) { - var a01 = mat[1], a02 = mat[2], a03 = mat[3], - a12 = mat[6], a13 = mat[7], - a23 = mat[11]; - - mat[1] = mat[4]; - mat[2] = mat[8]; - mat[3] = mat[12]; - mat[4] = a01; - mat[6] = mat[9]; - mat[7] = mat[13]; - mat[8] = a02; - mat[9] = a12; - mat[11] = mat[14]; - mat[12] = a03; - mat[13] = a13; - mat[14] = a23; - return mat; - } - - dest[0] = mat[0]; - dest[1] = mat[4]; - dest[2] = mat[8]; - dest[3] = mat[12]; - dest[4] = mat[1]; - dest[5] = mat[5]; - dest[6] = mat[9]; - dest[7] = mat[13]; - dest[8] = mat[2]; - dest[9] = mat[6]; - dest[10] = mat[10]; - dest[11] = mat[14]; - dest[12] = mat[3]; - dest[13] = mat[7]; - dest[14] = mat[11]; - dest[15] = mat[15]; - return dest; -}; - -/** - * Calculates the determinant of a mat4 - * - * @param {mat4} mat mat4 to calculate determinant of - * - * @returns {number} determinant of mat - */ -mat4.determinant = function (mat) { - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], - a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], - a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], - a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; - - return (a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + - a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + - a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + - a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + - a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + - a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33); -}; - -/** - * Calculates the inverse matrix of a mat4 - * - * @param {mat4} mat mat4 to calculate inverse of - * @param {mat4} [dest] mat4 receiving inverse matrix. If not specified result is written to mat - * - * @param {mat4} dest is specified, mat otherwise, null if matrix cannot be inverted - */ -mat4.inverse = function (mat, dest) { - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], - a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], - a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], - a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06), - invDet; - - // Calculate the determinant - if (!d) { return null; } - invDet = 1 / d; - - dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; - dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; - dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; - dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; - dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; - dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; - dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; - dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; - dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; - dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; - dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; - dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; - dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; - dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; - dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; - dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; - - return dest; -}; - -/** - * Copies the upper 3x3 elements of a mat4 into another mat4 - * - * @param {mat4} mat mat4 containing values to copy - * @param {mat4} [dest] mat4 receiving copied values - * - * @returns {mat4} dest is specified, a new mat4 otherwise - */ -mat4.toRotationMat = function (mat, dest) { - if (!dest) { dest = mat4.create(); } - - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[3]; - dest[4] = mat[4]; - dest[5] = mat[5]; - dest[6] = mat[6]; - dest[7] = mat[7]; - dest[8] = mat[8]; - dest[9] = mat[9]; - dest[10] = mat[10]; - dest[11] = mat[11]; - dest[12] = 0; - dest[13] = 0; - dest[14] = 0; - dest[15] = 1; - - return dest; -}; - -/** - * Copies the upper 3x3 elements of a mat4 into a mat3 - * - * @param {mat4} mat mat4 containing values to copy - * @param {mat3} [dest] mat3 receiving copied values - * - * @returns {mat3} dest is specified, a new mat3 otherwise - */ -mat4.toMat3 = function (mat, dest) { - if (!dest) { dest = mat3.create(); } - - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[4]; - dest[4] = mat[5]; - dest[5] = mat[6]; - dest[6] = mat[8]; - dest[7] = mat[9]; - dest[8] = mat[10]; - - return dest; -}; - -/** - * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3 - * The resulting matrix is useful for calculating transformed normals - * - * Params: - * @param {mat4} mat mat4 containing values to invert and copy - * @param {mat3} [dest] mat3 receiving values - * - * @returns {mat3} dest is specified, a new mat3 otherwise, null if the matrix cannot be inverted - */ -mat4.toInverseMat3 = function (mat, dest) { - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], - a10 = mat[4], a11 = mat[5], a12 = mat[6], - a20 = mat[8], a21 = mat[9], a22 = mat[10], - - b01 = a22 * a11 - a12 * a21, - b11 = -a22 * a10 + a12 * a20, - b21 = a21 * a10 - a11 * a20, - - d = a00 * b01 + a01 * b11 + a02 * b21, - id; - - if (!d) { return null; } - id = 1 / d; - - if (!dest) { dest = mat3.create(); } - - dest[0] = b01 * id; - dest[1] = (-a22 * a01 + a02 * a21) * id; - dest[2] = (a12 * a01 - a02 * a11) * id; - dest[3] = b11 * id; - dest[4] = (a22 * a00 - a02 * a20) * id; - dest[5] = (-a12 * a00 + a02 * a10) * id; - dest[6] = b21 * id; - dest[7] = (-a21 * a00 + a01 * a20) * id; - dest[8] = (a11 * a00 - a01 * a10) * id; - - return dest; -}; - -/** - * Performs a matrix multiplication - * - * @param {mat4} mat First operand - * @param {mat4} mat2 Second operand - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @returns {mat4} dest if specified, mat otherwise - */ -mat4.multiply = function (mat, mat2, dest) { - if (!dest) { dest = mat; } - - // Cache the matrix values (makes for huge speed increases!) - var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], - a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], - a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], - a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], - - b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3], - b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7], - b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11], - b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; - - dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; - dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; - dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; - dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; - dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; - dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; - dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; - dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; - dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; - dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; - dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; - dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; - dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; - dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; - dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; - dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; - - return dest; -}; - -/** - * Transforms a vec3 with the given matrix - * 4th vector component is implicitly '1' - * - * @param {mat4} mat mat4 to transform the vector with - * @param {vec3} vec vec3 to transform - * @paran {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns {vec3} dest if specified, vec otherwise - */ -mat4.multiplyVec3 = function (mat, vec, dest) { - if (!dest) { dest = vec; } - - var x = vec[0], y = vec[1], z = vec[2]; - - dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; - dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; - dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; - - return dest; -}; - -/** - * Transforms a vec4 with the given matrix - * - * @param {mat4} mat mat4 to transform the vector with - * @param {vec4} vec vec4 to transform - * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vec - * - * @returns {vec4} dest if specified, vec otherwise - */ -mat4.multiplyVec4 = function (mat, vec, dest) { - if (!dest) { dest = vec; } - - var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; - - dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12] * w; - dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13] * w; - dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14] * w; - dest[3] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15] * w; - - return dest; -}; - -/** - * Translates a matrix by the given vector - * - * @param {mat4} mat mat4 to translate - * @param {vec3} vec vec3 specifying the translation - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @returns {mat4} dest if specified, mat otherwise - */ -mat4.translate = function (mat, vec, dest) { - var x = vec[0], y = vec[1], z = vec[2], - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23; - - if (!dest || mat === dest) { - mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; - mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; - mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; - mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15]; - return mat; - } - - a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; - a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; - a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; - - dest[0] = a00; dest[1] = a01; dest[2] = a02; dest[3] = a03; - dest[4] = a10; dest[5] = a11; dest[6] = a12; dest[7] = a13; - dest[8] = a20; dest[9] = a21; dest[10] = a22; dest[11] = a23; - - dest[12] = a00 * x + a10 * y + a20 * z + mat[12]; - dest[13] = a01 * x + a11 * y + a21 * z + mat[13]; - dest[14] = a02 * x + a12 * y + a22 * z + mat[14]; - dest[15] = a03 * x + a13 * y + a23 * z + mat[15]; - return dest; -}; - -/** - * Scales a matrix by the given vector - * - * @param {mat4} mat mat4 to scale - * @param {vec3} vec vec3 specifying the scale for each axis - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @param {mat4} dest if specified, mat otherwise - */ -mat4.scale = function (mat, vec, dest) { - var x = vec[0], y = vec[1], z = vec[2]; - - if (!dest || mat === dest) { - mat[0] *= x; - mat[1] *= x; - mat[2] *= x; - mat[3] *= x; - mat[4] *= y; - mat[5] *= y; - mat[6] *= y; - mat[7] *= y; - mat[8] *= z; - mat[9] *= z; - mat[10] *= z; - mat[11] *= z; - return mat; - } - - dest[0] = mat[0] * x; - dest[1] = mat[1] * x; - dest[2] = mat[2] * x; - dest[3] = mat[3] * x; - dest[4] = mat[4] * y; - dest[5] = mat[5] * y; - dest[6] = mat[6] * y; - dest[7] = mat[7] * y; - dest[8] = mat[8] * z; - dest[9] = mat[9] * z; - dest[10] = mat[10] * z; - dest[11] = mat[11] * z; - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - return dest; -}; - -/** - * Rotates a matrix by the given angle around the specified axis - * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance - * - * @param {mat4} mat mat4 to rotate - * @param {number} angle Angle (in radians) to rotate - * @param {vec3} axis vec3 representing the axis to rotate around - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @returns {mat4} dest if specified, mat otherwise - */ -mat4.rotate = function (mat, angle, axis, dest) { - var x = axis[0], y = axis[1], z = axis[2], - len = Math.sqrt(x * x + y * y + z * z), - s, c, t, - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23, - b00, b01, b02, - b10, b11, b12, - b20, b21, b22; - - if (!len) { return null; } - if (len !== 1) { - len = 1 / len; - x *= len; - y *= len; - z *= len; - } - - s = Math.sin(angle); - c = Math.cos(angle); - t = 1 - c; - - a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; - a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; - a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; - - // Construct the elements of the rotation matrix - b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; - b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; - b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; - - if (!dest) { - dest = mat; - } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - } - - // Perform rotation-specific matrix multiplication - dest[0] = a00 * b00 + a10 * b01 + a20 * b02; - dest[1] = a01 * b00 + a11 * b01 + a21 * b02; - dest[2] = a02 * b00 + a12 * b01 + a22 * b02; - dest[3] = a03 * b00 + a13 * b01 + a23 * b02; - - dest[4] = a00 * b10 + a10 * b11 + a20 * b12; - dest[5] = a01 * b10 + a11 * b11 + a21 * b12; - dest[6] = a02 * b10 + a12 * b11 + a22 * b12; - dest[7] = a03 * b10 + a13 * b11 + a23 * b12; - - dest[8] = a00 * b20 + a10 * b21 + a20 * b22; - dest[9] = a01 * b20 + a11 * b21 + a21 * b22; - dest[10] = a02 * b20 + a12 * b21 + a22 * b22; - dest[11] = a03 * b20 + a13 * b21 + a23 * b22; - return dest; -}; - -/** - * Rotates a matrix by the given angle around the X axis - * - * @param {mat4} mat mat4 to rotate - * @param {number} angle Angle (in radians) to rotate - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @returns {mat4} dest if specified, mat otherwise - */ -mat4.rotateX = function (mat, angle, dest) { - var s = Math.sin(angle), - c = Math.cos(angle), - a10 = mat[4], - a11 = mat[5], - a12 = mat[6], - a13 = mat[7], - a20 = mat[8], - a21 = mat[9], - a22 = mat[10], - a23 = mat[11]; - - if (!dest) { - dest = mat; - } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows - dest[0] = mat[0]; - dest[1] = mat[1]; - dest[2] = mat[2]; - dest[3] = mat[3]; - - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - } - - // Perform axis-specific matrix multiplication - dest[4] = a10 * c + a20 * s; - dest[5] = a11 * c + a21 * s; - dest[6] = a12 * c + a22 * s; - dest[7] = a13 * c + a23 * s; - - dest[8] = a10 * -s + a20 * c; - dest[9] = a11 * -s + a21 * c; - dest[10] = a12 * -s + a22 * c; - dest[11] = a13 * -s + a23 * c; - return dest; -}; - -/** - * Rotates a matrix by the given angle around the Y axis - * - * @param {mat4} mat mat4 to rotate - * @param {number} angle Angle (in radians) to rotate - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @returns {mat4} dest if specified, mat otherwise - */ -mat4.rotateY = function (mat, angle, dest) { - var s = Math.sin(angle), - c = Math.cos(angle), - a00 = mat[0], - a01 = mat[1], - a02 = mat[2], - a03 = mat[3], - a20 = mat[8], - a21 = mat[9], - a22 = mat[10], - a23 = mat[11]; - - if (!dest) { - dest = mat; - } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows - dest[4] = mat[4]; - dest[5] = mat[5]; - dest[6] = mat[6]; - dest[7] = mat[7]; - - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - } - - // Perform axis-specific matrix multiplication - dest[0] = a00 * c + a20 * -s; - dest[1] = a01 * c + a21 * -s; - dest[2] = a02 * c + a22 * -s; - dest[3] = a03 * c + a23 * -s; - - dest[8] = a00 * s + a20 * c; - dest[9] = a01 * s + a21 * c; - dest[10] = a02 * s + a22 * c; - dest[11] = a03 * s + a23 * c; - return dest; -}; - -/** - * Rotates a matrix by the given angle around the Z axis - * - * @param {mat4} mat mat4 to rotate - * @param {number} angle Angle (in radians) to rotate - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat - * - * @returns {mat4} dest if specified, mat otherwise - */ -mat4.rotateZ = function (mat, angle, dest) { - var s = Math.sin(angle), - c = Math.cos(angle), - a00 = mat[0], - a01 = mat[1], - a02 = mat[2], - a03 = mat[3], - a10 = mat[4], - a11 = mat[5], - a12 = mat[6], - a13 = mat[7]; - - if (!dest) { - dest = mat; - } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row - dest[8] = mat[8]; - dest[9] = mat[9]; - dest[10] = mat[10]; - dest[11] = mat[11]; - - dest[12] = mat[12]; - dest[13] = mat[13]; - dest[14] = mat[14]; - dest[15] = mat[15]; - } - - // Perform axis-specific matrix multiplication - dest[0] = a00 * c + a10 * s; - dest[1] = a01 * c + a11 * s; - dest[2] = a02 * c + a12 * s; - dest[3] = a03 * c + a13 * s; - - dest[4] = a00 * -s + a10 * c; - dest[5] = a01 * -s + a11 * c; - dest[6] = a02 * -s + a12 * c; - dest[7] = a03 * -s + a13 * c; - - return dest; -}; - -/** - * Generates a frustum matrix with the given bounds - * - * @param {number} left Left bound of the frustum - * @param {number} right Right bound of the frustum - * @param {number} bottom Bottom bound of the frustum - * @param {number} top Top bound of the frustum - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @param {mat4} [dest] mat4 frustum matrix will be written into - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -mat4.frustum = function (left, right, bottom, top, near, far, dest) { - if (!dest) { dest = mat4.create(); } - var rl = (right - left), - tb = (top - bottom), - fn = (far - near); - dest[0] = (near * 2) / rl; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - dest[4] = 0; - dest[5] = (near * 2) / tb; - dest[6] = 0; - dest[7] = 0; - dest[8] = (right + left) / rl; - dest[9] = (top + bottom) / tb; - dest[10] = -(far + near) / fn; - dest[11] = -1; - dest[12] = 0; - dest[13] = 0; - dest[14] = -(far * near * 2) / fn; - dest[15] = 0; - return dest; -}; - -/** - * Generates a perspective projection matrix with the given bounds - * - * @param {number} fovy Vertical field of view - * @param {number} aspect Aspect ratio. typically viewport width/height - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @param {mat4} [dest] mat4 frustum matrix will be written into - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -mat4.perspective = function (fovy, aspect, near, far, dest) { - var top = near * Math.tan(fovy * Math.PI / 360.0), - right = top * aspect; - return mat4.frustum(-right, right, -top, top, near, far, dest); -}; - -/** - * Generates a orthogonal projection matrix with the given bounds - * - * @param {number} left Left bound of the frustum - * @param {number} right Right bound of the frustum - * @param {number} bottom Bottom bound of the frustum - * @param {number} top Top bound of the frustum - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @param {mat4} [dest] mat4 frustum matrix will be written into - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -mat4.ortho = function (left, right, bottom, top, near, far, dest) { - if (!dest) { dest = mat4.create(); } - var rl = (right - left), - tb = (top - bottom), - fn = (far - near); - dest[0] = 2 / rl; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - dest[4] = 0; - dest[5] = 2 / tb; - dest[6] = 0; - dest[7] = 0; - dest[8] = 0; - dest[9] = 0; - dest[10] = -2 / fn; - dest[11] = 0; - dest[12] = -(left + right) / rl; - dest[13] = -(top + bottom) / tb; - dest[14] = -(far + near) / fn; - dest[15] = 1; - return dest; -}; - -/** - * Generates a look-at matrix with the given eye position, focal point, and up axis - * - * @param {vec3} eye Position of the viewer - * @param {vec3} center Point the viewer is looking at - * @param {vec3} up vec3 pointing "up" - * @param {mat4} [dest] mat4 frustum matrix will be written into - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -mat4.lookAt = function (eye, center, up, dest) { - if (!dest) { dest = mat4.create(); } - - var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, - eyex = eye[0], - eyey = eye[1], - eyez = eye[2], - upx = up[0], - upy = up[1], - upz = up[2], - centerx = center[0], - centery = center[1], - centerz = center[2]; - - if (eyex === centerx && eyey === centery && eyez === centerz) { - return mat4.identity(dest); - } - - //vec3.direction(eye, center, z); - z0 = eyex - centerx; - z1 = eyey - centery; - z2 = eyez - centerz; - - // normalize (no check needed for 0 because of early return) - len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); - z0 *= len; - z1 *= len; - z2 *= len; - - //vec3.normalize(vec3.cross(up, z, x)); - x0 = upy * z2 - upz * z1; - x1 = upz * z0 - upx * z2; - x2 = upx * z1 - upy * z0; - len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); - if (!len) { - x0 = 0; - x1 = 0; - x2 = 0; - } else { - len = 1 / len; - x0 *= len; - x1 *= len; - x2 *= len; - } - - //vec3.normalize(vec3.cross(z, x, y)); - y0 = z1 * x2 - z2 * x1; - y1 = z2 * x0 - z0 * x2; - y2 = z0 * x1 - z1 * x0; - - len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); - if (!len) { - y0 = 0; - y1 = 0; - y2 = 0; - } else { - len = 1 / len; - y0 *= len; - y1 *= len; - y2 *= len; - } - - dest[0] = x0; - dest[1] = y0; - dest[2] = z0; - dest[3] = 0; - dest[4] = x1; - dest[5] = y1; - dest[6] = z1; - dest[7] = 0; - dest[8] = x2; - dest[9] = y2; - dest[10] = z2; - dest[11] = 0; - dest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); - dest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); - dest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); - dest[15] = 1; - - return dest; -}; - -/** - * Creates a matrix from a quaternion rotation and vector translation - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.translate(dest, vec); - * var quatMat = mat4.create(); - * quat4.toMat4(quat, quatMat); - * mat4.multiply(dest, quatMat); - * - * @param {quat4} quat Rotation quaternion - * @param {vec3} vec Translation vector - * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to a new mat4 - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -mat4.fromRotationTranslation = function (quat, vec, dest) { - if (!dest) { dest = mat4.create(); } - - // Quaternion math - var x = quat[0], y = quat[1], z = quat[2], w = quat[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - dest[0] = 1 - (yy + zz); - dest[1] = xy + wz; - dest[2] = xz - wy; - dest[3] = 0; - dest[4] = xy - wz; - dest[5] = 1 - (xx + zz); - dest[6] = yz + wx; - dest[7] = 0; - dest[8] = xz + wy; - dest[9] = yz - wx; - dest[10] = 1 - (xx + yy); - dest[11] = 0; - dest[12] = vec[0]; - dest[13] = vec[1]; - dest[14] = vec[2]; - dest[15] = 1; - - return dest; -}; - -/** - * Returns a string representation of a mat4 - * - * @param {mat4} mat mat4 to represent as a string - * - * @returns {string} String representation of mat - */ -mat4.str = function (mat) { - return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] + - ', ' + mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] + - ', ' + mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] + - ', ' + mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']'; -}; - -/* - * quat4 - */ - -/** - * Creates a new instance of a quat4 using the default array type - * Any javascript array containing at least 4 numeric elements can serve as a quat4 - * - * @param {quat4} [quat] quat4 containing values to initialize with - * - * @returns {quat4} New quat4 - */ -quat4.create = function (quat) { - var dest = new MatrixArray(4); - - if (quat) { - dest[0] = quat[0]; - dest[1] = quat[1]; - dest[2] = quat[2]; - dest[3] = quat[3]; - } - - return dest; -}; - -/** - * Copies the values of one quat4 to another - * - * @param {quat4} quat quat4 containing values to copy - * @param {quat4} dest quat4 receiving copied values - * - * @returns {quat4} dest - */ -quat4.set = function (quat, dest) { - dest[0] = quat[0]; - dest[1] = quat[1]; - dest[2] = quat[2]; - dest[3] = quat[3]; - - return dest; -}; - -/** - * Calculates the W component of a quat4 from the X, Y, and Z components. - * Assumes that quaternion is 1 unit in length. - * Any existing W component will be ignored. - * - * @param {quat4} quat quat4 to calculate W component of - * @param {quat4} [dest] quat4 receiving calculated values. If not specified result is written to quat - * - * @returns {quat4} dest if specified, quat otherwise - */ -quat4.calculateW = function (quat, dest) { - var x = quat[0], y = quat[1], z = quat[2]; - - if (!dest || quat === dest) { - quat[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); - return quat; - } - dest[0] = x; - dest[1] = y; - dest[2] = z; - dest[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); - return dest; -}; - -/** - * Calculates the dot product of two quaternions - * - * @param {quat4} quat First operand - * @param {quat4} quat2 Second operand - * - * @return {number} Dot product of quat and quat2 - */ -quat4.dot = function(quat, quat2){ - return quat[0]*quat2[0] + quat[1]*quat2[1] + quat[2]*quat2[2] + quat[3]*quat2[3]; -}; - -/** - * Calculates the inverse of a quat4 - * - * @param {quat4} quat quat4 to calculate inverse of - * @param {quat4} [dest] quat4 receiving inverse values. If not specified result is written to quat - * - * @returns {quat4} dest if specified, quat otherwise - */ -quat4.inverse = function(quat, dest) { - var q0 = quat[0], q1 = quat[1], q2 = quat[2], q3 = quat[3], - dot = q0*q0 + q1*q1 + q2*q2 + q3*q3, - invDot = dot ? 1.0/dot : 0; - - // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 - - if(!dest || quat === dest) { - quat[0] *= -invDot; - quat[1] *= -invDot; - quat[2] *= -invDot; - quat[3] *= invDot; - return quat; - } - dest[0] = -quat[0]*invDot; - dest[1] = -quat[1]*invDot; - dest[2] = -quat[2]*invDot; - dest[3] = quat[3]*invDot; - return dest; -}; - - -/** - * Calculates the conjugate of a quat4 - * If the quaternion is normalized, this function is faster than quat4.inverse and produces the same result. - * - * @param {quat4} quat quat4 to calculate conjugate of - * @param {quat4} [dest] quat4 receiving conjugate values. If not specified result is written to quat - * - * @returns {quat4} dest if specified, quat otherwise - */ -quat4.conjugate = function (quat, dest) { - if (!dest || quat === dest) { - quat[0] *= -1; - quat[1] *= -1; - quat[2] *= -1; - return quat; - } - dest[0] = -quat[0]; - dest[1] = -quat[1]; - dest[2] = -quat[2]; - dest[3] = quat[3]; - return dest; -}; - -/** - * Calculates the length of a quat4 - * - * Params: - * @param {quat4} quat quat4 to calculate length of - * - * @returns Length of quat - */ -quat4.length = function (quat) { - var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; - return Math.sqrt(x * x + y * y + z * z + w * w); -}; - -/** - * Generates a unit quaternion of the same direction as the provided quat4 - * If quaternion length is 0, returns [0, 0, 0, 0] - * - * @param {quat4} quat quat4 to normalize - * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat - * - * @returns {quat4} dest if specified, quat otherwise - */ -quat4.normalize = function (quat, dest) { - if (!dest) { dest = quat; } - - var x = quat[0], y = quat[1], z = quat[2], w = quat[3], - len = Math.sqrt(x * x + y * y + z * z + w * w); - if (len === 0) { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - return dest; - } - len = 1 / len; - dest[0] = x * len; - dest[1] = y * len; - dest[2] = z * len; - dest[3] = w * len; - - return dest; -}; - -/** - * Performs a quaternion multiplication - * - * @param {quat4} quat First operand - * @param {quat4} quat2 Second operand - * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat - * - * @returns {quat4} dest if specified, quat otherwise - */ -quat4.multiply = function (quat, quat2, dest) { - if (!dest) { dest = quat; } - - var qax = quat[0], qay = quat[1], qaz = quat[2], qaw = quat[3], - qbx = quat2[0], qby = quat2[1], qbz = quat2[2], qbw = quat2[3]; - - dest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - dest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - dest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - dest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - - return dest; -}; - -/** - * Transforms a vec3 with the given quaternion - * - * @param {quat4} quat quat4 to transform the vector with - * @param {vec3} vec vec3 to transform - * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec - * - * @returns dest if specified, vec otherwise - */ -quat4.multiplyVec3 = function (quat, vec, dest) { - if (!dest) { dest = vec; } - - var x = vec[0], y = vec[1], z = vec[2], - qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3], - - // calculate quat * vec - ix = qw * x + qy * z - qz * y, - iy = qw * y + qz * x - qx * z, - iz = qw * z + qx * y - qy * x, - iw = -qx * x - qy * y - qz * z; - - // calculate result * inverse quat - dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; - dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; - dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; - - return dest; -}; - -/** - * Calculates a 3x3 matrix from the given quat4 - * - * @param {quat4} quat quat4 to create matrix from - * @param {mat3} [dest] mat3 receiving operation result - * - * @returns {mat3} dest if specified, a new mat3 otherwise - */ -quat4.toMat3 = function (quat, dest) { - if (!dest) { dest = mat3.create(); } - - var x = quat[0], y = quat[1], z = quat[2], w = quat[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - dest[0] = 1 - (yy + zz); - dest[1] = xy + wz; - dest[2] = xz - wy; - - dest[3] = xy - wz; - dest[4] = 1 - (xx + zz); - dest[5] = yz + wx; - - dest[6] = xz + wy; - dest[7] = yz - wx; - dest[8] = 1 - (xx + yy); - - return dest; -}; - -/** - * Calculates a 4x4 matrix from the given quat4 - * - * @param {quat4} quat quat4 to create matrix from - * @param {mat4} [dest] mat4 receiving operation result - * - * @returns {mat4} dest if specified, a new mat4 otherwise - */ -quat4.toMat4 = function (quat, dest) { - if (!dest) { dest = mat4.create(); } - - var x = quat[0], y = quat[1], z = quat[2], w = quat[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - dest[0] = 1 - (yy + zz); - dest[1] = xy + wz; - dest[2] = xz - wy; - dest[3] = 0; - - dest[4] = xy - wz; - dest[5] = 1 - (xx + zz); - dest[6] = yz + wx; - dest[7] = 0; - - dest[8] = xz + wy; - dest[9] = yz - wx; - dest[10] = 1 - (xx + yy); - dest[11] = 0; - - dest[12] = 0; - dest[13] = 0; - dest[14] = 0; - dest[15] = 1; - - return dest; -}; - -/** - * Performs a spherical linear interpolation between two quat4 - * - * @param {quat4} quat First quaternion - * @param {quat4} quat2 Second quaternion - * @param {number} slerp Interpolation amount between the two inputs - * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat - * - * @returns {quat4} dest if specified, quat otherwise - */ -quat4.slerp = function (quat, quat2, slerp, dest) { - if (!dest) { dest = quat; } - - var cosHalfTheta = quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3], - halfTheta, - sinHalfTheta, - ratioA, - ratioB; - - if (Math.abs(cosHalfTheta) >= 1.0) { - if (dest !== quat) { - dest[0] = quat[0]; - dest[1] = quat[1]; - dest[2] = quat[2]; - dest[3] = quat[3]; - } - return dest; - } - - halfTheta = Math.acos(cosHalfTheta); - sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); - - if (Math.abs(sinHalfTheta) < 0.001) { - dest[0] = (quat[0] * 0.5 + quat2[0] * 0.5); - dest[1] = (quat[1] * 0.5 + quat2[1] * 0.5); - dest[2] = (quat[2] * 0.5 + quat2[2] * 0.5); - dest[3] = (quat[3] * 0.5 + quat2[3] * 0.5); - return dest; - } - - ratioA = Math.sin((1 - slerp) * halfTheta) / sinHalfTheta; - ratioB = Math.sin(slerp * halfTheta) / sinHalfTheta; - - dest[0] = (quat[0] * ratioA + quat2[0] * ratioB); - dest[1] = (quat[1] * ratioA + quat2[1] * ratioB); - dest[2] = (quat[2] * ratioA + quat2[2] * ratioB); - dest[3] = (quat[3] * ratioA + quat2[3] * ratioB); - - return dest; -}; - -/** - * Returns a string representation of a quaternion - * - * @param {quat4} quat quat4 to represent as a string - * - * @returns {string} String representation of quat - */ -quat4.str = function (quat) { - return '[' + quat[0] + ', ' + quat[1] + ', ' + quat[2] + ', ' + quat[3] + ']'; -}; - +/** + * @fileOverview gl-matrix - High performance matrix and vector operations for WebGL + * @author Brandon Jones + * @version 1.2.3 + */ + +/* + * Copyright (c) 2011 Brandon Jones + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +"use strict"; + +// Type declarations +(function() { + // account for CommonJS environments + var _global = (typeof(exports) != 'undefined') ? global : window; + _global.glMatrixArrayType = _global.MatrixArray = null; + + /** + * @class 3 Dimensional Vector + * @name vec3 + */ + _global.vec3 = {}; + + /** + * @class 3x3 Matrix + * @name mat3 + */ + _global.mat3 = {}; + + /** + * @class 4x4 Matrix + * @name mat4 + */ + _global.mat4 = {}; + + /** + * @class Quaternion + * @name quat4 + */ + _global.quat4 = {}; + + // explicitly sets and returns the type of array to use within glMatrix + _global.setMatrixArrayType = function(type) { + return glMatrixArrayType = MatrixArray = type; + }; + + // auto-detects and returns the best type of array to use within glMatrix, falling + // back to Array if typed arrays are unsupported + _global.determineMatrixArrayType = function() { + return setMatrixArrayType((typeof Float32Array !== 'undefined') ? Float32Array : Array); + }; + + determineMatrixArrayType(); +})(); + +/* + * vec3 + */ + +/** + * Creates a new instance of a vec3 using the default array type + * Any javascript array-like objects containing at least 3 numeric elements can serve as a vec3 + * + * @param {vec3} [vec] vec3 containing values to initialize with + * + * @returns {vec3} New vec3 + */ +vec3.create = function (vec) { + var dest = new MatrixArray(3); + + if (vec) { + dest[0] = vec[0]; + dest[1] = vec[1]; + dest[2] = vec[2]; + } else { + dest[0] = dest[1] = dest[2] = 0; + } + + return dest; +}; + +/** + * Copies the values of one vec3 to another + * + * @param {vec3} vec vec3 containing values to copy + * @param {vec3} dest vec3 receiving copied values + * + * @returns {vec3} dest + */ +vec3.set = function (vec, dest) { + dest[0] = vec[0]; + dest[1] = vec[1]; + dest[2] = vec[2]; + + return dest; +}; + +/** + * Performs a vector addition + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.add = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] += vec2[0]; + vec[1] += vec2[1]; + vec[2] += vec2[2]; + return vec; + } + + dest[0] = vec[0] + vec2[0]; + dest[1] = vec[1] + vec2[1]; + dest[2] = vec[2] + vec2[2]; + return dest; +}; + +/** + * Performs a vector subtraction + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.subtract = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] -= vec2[0]; + vec[1] -= vec2[1]; + vec[2] -= vec2[2]; + return vec; + } + + dest[0] = vec[0] - vec2[0]; + dest[1] = vec[1] - vec2[1]; + dest[2] = vec[2] - vec2[2]; + return dest; +}; + +/** + * Performs a vector multiplication + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.multiply = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] *= vec2[0]; + vec[1] *= vec2[1]; + vec[2] *= vec2[2]; + return vec; + } + + dest[0] = vec[0] * vec2[0]; + dest[1] = vec[1] * vec2[1]; + dest[2] = vec[2] * vec2[2]; + return dest; +}; + +/** + * Negates the components of a vec3 + * + * @param {vec3} vec vec3 to negate + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.negate = function (vec, dest) { + if (!dest) { dest = vec; } + + dest[0] = -vec[0]; + dest[1] = -vec[1]; + dest[2] = -vec[2]; + return dest; +}; + +/** + * Multiplies the components of a vec3 by a scalar value + * + * @param {vec3} vec vec3 to scale + * @param {number} val Value to scale by + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.scale = function (vec, val, dest) { + if (!dest || vec === dest) { + vec[0] *= val; + vec[1] *= val; + vec[2] *= val; + return vec; + } + + dest[0] = vec[0] * val; + dest[1] = vec[1] * val; + dest[2] = vec[2] * val; + return dest; +}; + +/** + * Generates a unit vector of the same direction as the provided vec3 + * If vector length is 0, returns [0, 0, 0] + * + * @param {vec3} vec vec3 to normalize + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.normalize = function (vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + len = Math.sqrt(x * x + y * y + z * z); + + if (!len) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + return dest; + } else if (len === 1) { + dest[0] = x; + dest[1] = y; + dest[2] = z; + return dest; + } + + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + return dest; +}; + +/** + * Generates the cross product of two vec3s + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.cross = function (vec, vec2, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + x2 = vec2[0], y2 = vec2[1], z2 = vec2[2]; + + dest[0] = y * z2 - z * y2; + dest[1] = z * x2 - x * z2; + dest[2] = x * y2 - y * x2; + return dest; +}; + +/** + * Caclulates the length of a vec3 + * + * @param {vec3} vec vec3 to calculate length of + * + * @returns {number} Length of vec + */ +vec3.length = function (vec) { + var x = vec[0], y = vec[1], z = vec[2]; + return Math.sqrt(x * x + y * y + z * z); +}; + +/** + * Caclulates the dot product of two vec3s + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * + * @returns {number} Dot product of vec and vec2 + */ +vec3.dot = function (vec, vec2) { + return vec[0] * vec2[0] + vec[1] * vec2[1] + vec[2] * vec2[2]; +}; + +/** + * Generates a unit vector pointing from one vector to another + * + * @param {vec3} vec Origin vec3 + * @param {vec3} vec2 vec3 to point to + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.direction = function (vec, vec2, dest) { + if (!dest) { dest = vec; } + + var x = vec[0] - vec2[0], + y = vec[1] - vec2[1], + z = vec[2] - vec2[2], + len = Math.sqrt(x * x + y * y + z * z); + + if (!len) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + return dest; + } + + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + return dest; +}; + +/** + * Performs a linear interpolation between two vec3 + * + * @param {vec3} vec First vector + * @param {vec3} vec2 Second vector + * @param {number} lerp Interpolation amount between the two inputs + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.lerp = function (vec, vec2, lerp, dest) { + if (!dest) { dest = vec; } + + dest[0] = vec[0] + lerp * (vec2[0] - vec[0]); + dest[1] = vec[1] + lerp * (vec2[1] - vec[1]); + dest[2] = vec[2] + lerp * (vec2[2] - vec[2]); + + return dest; +}; + +/** + * Calculates the euclidian distance between two vec3 + * + * Params: + * @param {vec3} vec First vector + * @param {vec3} vec2 Second vector + * + * @returns {number} Distance between vec and vec2 + */ +vec3.dist = function (vec, vec2) { + var x = vec2[0] - vec[0], + y = vec2[1] - vec[1], + z = vec2[2] - vec[2]; + + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Projects the specified vec3 from screen space into object space + * Based on the Mesa gluUnProject implementation + * + * @param {vec3} vec Screen-space vector to project + * @param {mat4} view View matrix + * @param {mat4} proj Projection matrix + * @param {vec4} viewport Viewport as given to gl.viewport [x, y, width, height] + * @param {vec3} [dest] vec3 receiving unprojected result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.unproject = function (vec, view, proj, viewport, dest) { + if (!dest) { dest = vec; } + + var m = mat4.create(); + var v = new MatrixArray(4); + + v[0] = (vec[0] - viewport[0]) * 2.0 / viewport[2] - 1.0; + v[1] = (vec[1] - viewport[1]) * 2.0 / viewport[3] - 1.0; + v[2] = 2.0 * vec[2] - 1.0; + v[3] = 1.0; + + mat4.multiply(proj, view, m); + if(!mat4.inverse(m)) { return null; } + + mat4.multiplyVec4(m, v); + if(v[3] === 0.0) { return null; } + + dest[0] = v[0] / v[3]; + dest[1] = v[1] / v[3]; + dest[2] = v[2] / v[3]; + + return dest; +}; + +/** + * Returns a string representation of a vector + * + * @param {vec3} vec Vector to represent as a string + * + * @returns {string} String representation of vec + */ +vec3.str = function (vec) { + return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']'; +}; + +/* + * mat3 + */ + +/** + * Creates a new instance of a mat3 using the default array type + * Any javascript array-like object containing at least 9 numeric elements can serve as a mat3 + * + * @param {mat3} [mat] mat3 containing values to initialize with + * + * @returns {mat3} New mat3 + */ +mat3.create = function (mat) { + var dest = new MatrixArray(9); + + if (mat) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + } + + return dest; +}; + +/** + * Copies the values of one mat3 to another + * + * @param {mat3} mat mat3 containing values to copy + * @param {mat3} dest mat3 receiving copied values + * + * @returns {mat3} dest + */ +mat3.set = function (mat, dest) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + return dest; +}; + +/** + * Sets a mat3 to an identity matrix + * + * @param {mat3} dest mat3 to set + * + * @returns dest if specified, otherwise a new mat3 + */ +mat3.identity = function (dest) { + if (!dest) { dest = mat3.create(); } + dest[0] = 1; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 1; + dest[5] = 0; + dest[6] = 0; + dest[7] = 0; + dest[8] = 1; + return dest; +}; + +/** + * Transposes a mat3 (flips the values over the diagonal) + * + * Params: + * @param {mat3} mat mat3 to transpose + * @param {mat3} [dest] mat3 receiving transposed values. If not specified result is written to mat + * + * @returns {mat3} dest is specified, mat otherwise + */ +mat3.transpose = function (mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +}; + +/** + * Copies the elements of a mat3 into the upper 3x3 elements of a mat4 + * + * @param {mat3} mat mat3 containing values to copy + * @param {mat4} [dest] mat4 receiving copied values + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat3.toMat4 = function (mat, dest) { + if (!dest) { dest = mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +}; + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat mat3 to represent as a string + * + * @param {string} String representation of mat + */ +mat3.str = function (mat) { + return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + + ', ' + mat[3] + ', ' + mat[4] + ', ' + mat[5] + + ', ' + mat[6] + ', ' + mat[7] + ', ' + mat[8] + ']'; +}; + +/* + * mat4 + */ + +/** + * Creates a new instance of a mat4 using the default array type + * Any javascript array-like object containing at least 16 numeric elements can serve as a mat4 + * + * @param {mat4} [mat] mat4 containing values to initialize with + * + * @returns {mat4} New mat4 + */ +mat4.create = function (mat) { + var dest = new MatrixArray(16); + + if (mat) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + return dest; +}; + +/** + * Copies the values of one mat4 to another + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat4} dest mat4 receiving copied values + * + * @returns {mat4} dest + */ +mat4.set = function (mat, dest) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Sets a mat4 to an identity matrix + * + * @param {mat4} dest mat4 to set + * + * @returns {mat4} dest + */ +mat4.identity = function (dest) { + if (!dest) { dest = mat4.create(); } + dest[0] = 1; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = 1; + dest[6] = 0; + dest[7] = 0; + dest[8] = 0; + dest[9] = 0; + dest[10] = 1; + dest[11] = 0; + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + return dest; +}; + +/** + * Transposes a mat4 (flips the values over the diagonal) + * + * @param {mat4} mat mat4 to transpose + * @param {mat4} [dest] mat4 receiving transposed values. If not specified result is written to mat + * + * @param {mat4} dest is specified, mat otherwise + */ +mat4.transpose = function (mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} mat mat4 to calculate determinant of + * + * @returns {number} determinant of mat + */ +mat4.determinant = function (mat) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + return (a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + + a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + + a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + + a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + + a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + + a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33); +}; + +/** + * Calculates the inverse matrix of a mat4 + * + * @param {mat4} mat mat4 to calculate inverse of + * @param {mat4} [dest] mat4 receiving inverse matrix. If not specified result is written to mat + * + * @param {mat4} dest is specified, mat otherwise, null if matrix cannot be inverted + */ +mat4.inverse = function (mat, dest) { + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06), + invDet; + + // Calculate the determinant + if (!d) { return null; } + invDet = 1 / d; + + dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; + dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; + dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; + dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; + dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; + dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; + dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; + dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; + dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; + dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; + dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; + dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; + dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; + dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; + dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; + dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; + + return dest; +}; + +/** + * Copies the upper 3x3 elements of a mat4 into another mat4 + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat4} [dest] mat4 receiving copied values + * + * @returns {mat4} dest is specified, a new mat4 otherwise + */ +mat4.toRotationMat = function (mat, dest) { + if (!dest) { dest = mat4.create(); } + + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + + return dest; +}; + +/** + * Copies the upper 3x3 elements of a mat4 into a mat3 + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat3} [dest] mat3 receiving copied values + * + * @returns {mat3} dest is specified, a new mat3 otherwise + */ +mat4.toMat3 = function (mat, dest) { + if (!dest) { dest = mat3.create(); } + + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[4]; + dest[4] = mat[5]; + dest[5] = mat[6]; + dest[6] = mat[8]; + dest[7] = mat[9]; + dest[8] = mat[10]; + + return dest; +}; + +/** + * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3 + * The resulting matrix is useful for calculating transformed normals + * + * Params: + * @param {mat4} mat mat4 containing values to invert and copy + * @param {mat3} [dest] mat3 receiving values + * + * @returns {mat3} dest is specified, a new mat3 otherwise, null if the matrix cannot be inverted + */ +mat4.toInverseMat3 = function (mat, dest) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[4], a11 = mat[5], a12 = mat[6], + a20 = mat[8], a21 = mat[9], a22 = mat[10], + + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, + + d = a00 * b01 + a01 * b11 + a02 * b21, + id; + + if (!d) { return null; } + id = 1 / d; + + if (!dest) { dest = mat3.create(); } + + dest[0] = b01 * id; + dest[1] = (-a22 * a01 + a02 * a21) * id; + dest[2] = (a12 * a01 - a02 * a11) * id; + dest[3] = b11 * id; + dest[4] = (a22 * a00 - a02 * a20) * id; + dest[5] = (-a12 * a00 + a02 * a10) * id; + dest[6] = b21 * id; + dest[7] = (-a21 * a00 + a01 * a20) * id; + dest[8] = (a11 * a00 - a01 * a10) * id; + + return dest; +}; + +/** + * Performs a matrix multiplication + * + * @param {mat4} mat First operand + * @param {mat4} mat2 Second operand + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.multiply = function (mat, mat2, dest) { + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3], + b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7], + b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11], + b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; + + return dest; +}; + +/** + * Transforms a vec3 with the given matrix + * 4th vector component is implicitly '1' + * + * @param {mat4} mat mat4 to transform the vector with + * @param {vec3} vec vec3 to transform + * @paran {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +mat4.multiplyVec3 = function (mat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2]; + + dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + + return dest; +}; + +/** + * Transforms a vec4 with the given matrix + * + * @param {mat4} mat mat4 to transform the vector with + * @param {vec4} vec vec4 to transform + * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vec + * + * @returns {vec4} dest if specified, vec otherwise + */ +mat4.multiplyVec4 = function (mat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; + + dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12] * w; + dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13] * w; + dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14] * w; + dest[3] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15] * w; + + return dest; +}; + +/** + * Translates a matrix by the given vector + * + * @param {mat4} mat mat4 to translate + * @param {vec3} vec vec3 specifying the translation + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.translate = function (mat, vec, dest) { + var x = vec[0], y = vec[1], z = vec[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; + + if (!dest || mat === dest) { + mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15]; + return mat; + } + + a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; + a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; + a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; + + dest[0] = a00; dest[1] = a01; dest[2] = a02; dest[3] = a03; + dest[4] = a10; dest[5] = a11; dest[6] = a12; dest[7] = a13; + dest[8] = a20; dest[9] = a21; dest[10] = a22; dest[11] = a23; + + dest[12] = a00 * x + a10 * y + a20 * z + mat[12]; + dest[13] = a01 * x + a11 * y + a21 * z + mat[13]; + dest[14] = a02 * x + a12 * y + a22 * z + mat[14]; + dest[15] = a03 * x + a13 * y + a23 * z + mat[15]; + return dest; +}; + +/** + * Scales a matrix by the given vector + * + * @param {mat4} mat mat4 to scale + * @param {vec3} vec vec3 specifying the scale for each axis + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @param {mat4} dest if specified, mat otherwise + */ +mat4.scale = function (mat, vec, dest) { + var x = vec[0], y = vec[1], z = vec[2]; + + if (!dest || mat === dest) { + mat[0] *= x; + mat[1] *= x; + mat[2] *= x; + mat[3] *= x; + mat[4] *= y; + mat[5] *= y; + mat[6] *= y; + mat[7] *= y; + mat[8] *= z; + mat[9] *= z; + mat[10] *= z; + mat[11] *= z; + return mat; + } + + dest[0] = mat[0] * x; + dest[1] = mat[1] * x; + dest[2] = mat[2] * x; + dest[3] = mat[3] * x; + dest[4] = mat[4] * y; + dest[5] = mat[5] * y; + dest[6] = mat[6] * y; + dest[7] = mat[7] * y; + dest[8] = mat[8] * z; + dest[9] = mat[9] * z; + dest[10] = mat[10] * z; + dest[11] = mat[11] * z; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the specified axis + * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {vec3} axis vec3 representing the axis to rotate around + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotate = function (mat, angle, axis, dest) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; + + if (!len) { return null; } + if (len !== 1) { + len = 1 / len; + x *= len; + y *= len; + z *= len; + } + + s = Math.sin(angle); + c = Math.cos(angle); + t = 1 - c; + + a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; + a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; + a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform rotation-specific matrix multiplication + dest[0] = a00 * b00 + a10 * b01 + a20 * b02; + dest[1] = a01 * b00 + a11 * b01 + a21 * b02; + dest[2] = a02 * b00 + a12 * b01 + a22 * b02; + dest[3] = a03 * b00 + a13 * b01 + a23 * b02; + + dest[4] = a00 * b10 + a10 * b11 + a20 * b12; + dest[5] = a01 * b10 + a11 * b11 + a21 * b12; + dest[6] = a02 * b10 + a12 * b11 + a22 * b12; + dest[7] = a03 * b10 + a13 * b11 + a23 * b12; + + dest[8] = a00 * b20 + a10 * b21 + a20 * b22; + dest[9] = a01 * b20 + a11 * b21 + a21 * b22; + dest[10] = a02 * b20 + a12 * b21 + a22 * b22; + dest[11] = a03 * b20 + a13 * b21 + a23 * b22; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateX = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a10 = mat[4], + a11 = mat[5], + a12 = mat[6], + a13 = mat[7], + a20 = mat[8], + a21 = mat[9], + a22 = mat[10], + a23 = mat[11]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[4] = a10 * c + a20 * s; + dest[5] = a11 * c + a21 * s; + dest[6] = a12 * c + a22 * s; + dest[7] = a13 * c + a23 * s; + + dest[8] = a10 * -s + a20 * c; + dest[9] = a11 * -s + a21 * c; + dest[10] = a12 * -s + a22 * c; + dest[11] = a13 * -s + a23 * c; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateY = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a00 = mat[0], + a01 = mat[1], + a02 = mat[2], + a03 = mat[3], + a20 = mat[8], + a21 = mat[9], + a22 = mat[10], + a23 = mat[11]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[0] = a00 * c + a20 * -s; + dest[1] = a01 * c + a21 * -s; + dest[2] = a02 * c + a22 * -s; + dest[3] = a03 * c + a23 * -s; + + dest[8] = a00 * s + a20 * c; + dest[9] = a01 * s + a21 * c; + dest[10] = a02 * s + a22 * c; + dest[11] = a03 * s + a23 * c; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateZ = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a00 = mat[0], + a01 = mat[1], + a02 = mat[2], + a03 = mat[3], + a10 = mat[4], + a11 = mat[5], + a12 = mat[6], + a13 = mat[7]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[0] = a00 * c + a10 * s; + dest[1] = a01 * c + a11 * s; + dest[2] = a02 * c + a12 * s; + dest[3] = a03 * c + a13 * s; + + dest[4] = a00 * -s + a10 * c; + dest[5] = a01 * -s + a11 * c; + dest[6] = a02 * -s + a12 * c; + dest[7] = a03 * -s + a13 * c; + + return dest; +}; + +/** + * Generates a frustum matrix with the given bounds + * + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.frustum = function (left, right, bottom, top, near, far, dest) { + if (!dest) { dest = mat4.create(); } + var rl = (right - left), + tb = (top - bottom), + fn = (far - near); + dest[0] = (near * 2) / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = (near * 2) / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = (right + left) / rl; + dest[9] = (top + bottom) / tb; + dest[10] = -(far + near) / fn; + dest[11] = -1; + dest[12] = 0; + dest[13] = 0; + dest[14] = -(far * near * 2) / fn; + dest[15] = 0; + return dest; +}; + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {number} fovy Vertical field of view + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.perspective = function (fovy, aspect, near, far, dest) { + var top = near * Math.tan(fovy * Math.PI / 360.0), + right = top * aspect; + return mat4.frustum(-right, right, -top, top, near, far, dest); +}; + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.ortho = function (left, right, bottom, top, near, far, dest) { + if (!dest) { dest = mat4.create(); } + var rl = (right - left), + tb = (top - bottom), + fn = (far - near); + dest[0] = 2 / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = 2 / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = 0; + dest[9] = 0; + dest[10] = -2 / fn; + dest[11] = 0; + dest[12] = -(left + right) / rl; + dest[13] = -(top + bottom) / tb; + dest[14] = -(far + near) / fn; + dest[15] = 1; + return dest; +}; + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing "up" + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.lookAt = function (eye, center, up, dest) { + if (!dest) { dest = mat4.create(); } + + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; + + if (eyex === centerx && eyey === centery && eyez === centerz) { + return mat4.identity(dest); + } + + //vec3.direction(eye, center, z); + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + // normalize (no check needed for 0 because of early return) + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + //vec3.normalize(vec3.cross(up, z, x)); + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + //vec3.normalize(vec3.cross(z, x, y)); + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + dest[0] = x0; + dest[1] = y0; + dest[2] = z0; + dest[3] = 0; + dest[4] = x1; + dest[5] = y1; + dest[6] = z1; + dest[7] = 0; + dest[8] = x2; + dest[9] = y2; + dest[10] = z2; + dest[11] = 0; + dest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + dest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + dest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + dest[15] = 1; + + return dest; +}; + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {quat4} quat Rotation quaternion + * @param {vec3} vec Translation vector + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to a new mat4 + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.fromRotationTranslation = function (quat, vec, dest) { + if (!dest) { dest = mat4.create(); } + + // Quaternion math + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + dest[3] = 0; + dest[4] = xy - wz; + dest[5] = 1 - (xx + zz); + dest[6] = yz + wx; + dest[7] = 0; + dest[8] = xz + wy; + dest[9] = yz - wx; + dest[10] = 1 - (xx + yy); + dest[11] = 0; + dest[12] = vec[0]; + dest[13] = vec[1]; + dest[14] = vec[2]; + dest[15] = 1; + + return dest; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat mat4 to represent as a string + * + * @returns {string} String representation of mat + */ +mat4.str = function (mat) { + return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] + + ', ' + mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] + + ', ' + mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] + + ', ' + mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']'; +}; + +/* + * quat4 + */ + +/** + * Creates a new instance of a quat4 using the default array type + * Any javascript array containing at least 4 numeric elements can serve as a quat4 + * + * @param {quat4} [quat] quat4 containing values to initialize with + * + * @returns {quat4} New quat4 + */ +quat4.create = function (quat) { + var dest = new MatrixArray(4); + + if (quat) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + } + + return dest; +}; + +/** + * Copies the values of one quat4 to another + * + * @param {quat4} quat quat4 containing values to copy + * @param {quat4} dest quat4 receiving copied values + * + * @returns {quat4} dest + */ +quat4.set = function (quat, dest) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + + return dest; +}; + +/** + * Calculates the W component of a quat4 from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat4} quat quat4 to calculate W component of + * @param {quat4} [dest] quat4 receiving calculated values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.calculateW = function (quat, dest) { + var x = quat[0], y = quat[1], z = quat[2]; + + if (!dest || quat === dest) { + quat[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return quat; + } + dest[0] = x; + dest[1] = y; + dest[2] = z; + dest[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return dest; +}; + +/** + * Calculates the dot product of two quaternions + * + * @param {quat4} quat First operand + * @param {quat4} quat2 Second operand + * + * @return {number} Dot product of quat and quat2 + */ +quat4.dot = function(quat, quat2){ + return quat[0]*quat2[0] + quat[1]*quat2[1] + quat[2]*quat2[2] + quat[3]*quat2[3]; +}; + +/** + * Calculates the inverse of a quat4 + * + * @param {quat4} quat quat4 to calculate inverse of + * @param {quat4} [dest] quat4 receiving inverse values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.inverse = function(quat, dest) { + var q0 = quat[0], q1 = quat[1], q2 = quat[2], q3 = quat[3], + dot = q0*q0 + q1*q1 + q2*q2 + q3*q3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + if(!dest || quat === dest) { + quat[0] *= -invDot; + quat[1] *= -invDot; + quat[2] *= -invDot; + quat[3] *= invDot; + return quat; + } + dest[0] = -quat[0]*invDot; + dest[1] = -quat[1]*invDot; + dest[2] = -quat[2]*invDot; + dest[3] = quat[3]*invDot; + return dest; +}; + + +/** + * Calculates the conjugate of a quat4 + * If the quaternion is normalized, this function is faster than quat4.inverse and produces the same result. + * + * @param {quat4} quat quat4 to calculate conjugate of + * @param {quat4} [dest] quat4 receiving conjugate values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.conjugate = function (quat, dest) { + if (!dest || quat === dest) { + quat[0] *= -1; + quat[1] *= -1; + quat[2] *= -1; + return quat; + } + dest[0] = -quat[0]; + dest[1] = -quat[1]; + dest[2] = -quat[2]; + dest[3] = quat[3]; + return dest; +}; + +/** + * Calculates the length of a quat4 + * + * Params: + * @param {quat4} quat quat4 to calculate length of + * + * @returns Length of quat + */ +quat4.length = function (quat) { + var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; + return Math.sqrt(x * x + y * y + z * z + w * w); +}; + +/** + * Generates a unit quaternion of the same direction as the provided quat4 + * If quaternion length is 0, returns [0, 0, 0, 0] + * + * @param {quat4} quat quat4 to normalize + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.normalize = function (quat, dest) { + if (!dest) { dest = quat; } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + len = Math.sqrt(x * x + y * y + z * z + w * w); + if (len === 0) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + return dest; + } + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + dest[3] = w * len; + + return dest; +}; + +/** + * Performs a quaternion multiplication + * + * @param {quat4} quat First operand + * @param {quat4} quat2 Second operand + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.multiply = function (quat, quat2, dest) { + if (!dest) { dest = quat; } + + var qax = quat[0], qay = quat[1], qaz = quat[2], qaw = quat[3], + qbx = quat2[0], qby = quat2[1], qbz = quat2[2], qbw = quat2[3]; + + dest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + dest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + dest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + dest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + return dest; +}; + +/** + * Transforms a vec3 with the given quaternion + * + * @param {quat4} quat quat4 to transform the vector with + * @param {vec3} vec vec3 to transform + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns dest if specified, vec otherwise + */ +quat4.multiplyVec3 = function (quat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return dest; +}; + +/** + * Calculates a 3x3 matrix from the given quat4 + * + * @param {quat4} quat quat4 to create matrix from + * @param {mat3} [dest] mat3 receiving operation result + * + * @returns {mat3} dest if specified, a new mat3 otherwise + */ +quat4.toMat3 = function (quat, dest) { + if (!dest) { dest = mat3.create(); } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + + dest[3] = xy - wz; + dest[4] = 1 - (xx + zz); + dest[5] = yz + wx; + + dest[6] = xz + wy; + dest[7] = yz - wx; + dest[8] = 1 - (xx + yy); + + return dest; +}; + +/** + * Calculates a 4x4 matrix from the given quat4 + * + * @param {quat4} quat quat4 to create matrix from + * @param {mat4} [dest] mat4 receiving operation result + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +quat4.toMat4 = function (quat, dest) { + if (!dest) { dest = mat4.create(); } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + dest[3] = 0; + + dest[4] = xy - wz; + dest[5] = 1 - (xx + zz); + dest[6] = yz + wx; + dest[7] = 0; + + dest[8] = xz + wy; + dest[9] = yz - wx; + dest[10] = 1 - (xx + yy); + dest[11] = 0; + + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + + return dest; +}; + +/** + * Performs a spherical linear interpolation between two quat4 + * + * @param {quat4} quat First quaternion + * @param {quat4} quat2 Second quaternion + * @param {number} slerp Interpolation amount between the two inputs + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.slerp = function (quat, quat2, slerp, dest) { + if (!dest) { dest = quat; } + + var cosHalfTheta = quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3], + halfTheta, + sinHalfTheta, + ratioA, + ratioB; + + if (Math.abs(cosHalfTheta) >= 1.0) { + if (dest !== quat) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + } + return dest; + } + + halfTheta = Math.acos(cosHalfTheta); + sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + + if (Math.abs(sinHalfTheta) < 0.001) { + dest[0] = (quat[0] * 0.5 + quat2[0] * 0.5); + dest[1] = (quat[1] * 0.5 + quat2[1] * 0.5); + dest[2] = (quat[2] * 0.5 + quat2[2] * 0.5); + dest[3] = (quat[3] * 0.5 + quat2[3] * 0.5); + return dest; + } + + ratioA = Math.sin((1 - slerp) * halfTheta) / sinHalfTheta; + ratioB = Math.sin(slerp * halfTheta) / sinHalfTheta; + + dest[0] = (quat[0] * ratioA + quat2[0] * ratioB); + dest[1] = (quat[1] * ratioA + quat2[1] * ratioB); + dest[2] = (quat[2] * ratioA + quat2[2] * ratioB); + dest[3] = (quat[3] * ratioA + quat2[3] * ratioB); + + return dest; +}; + +/** + * Returns a string representation of a quaternion + * + * @param {quat4} quat quat4 to represent as a string + * + * @returns {string} String representation of quat + */ +quat4.str = function (quat) { + return '[' + quat[0] + ', ' + quat[1] + ', ' + quat[2] + ', ' + quat[3] + ']'; +}; + diff --git a/part2/River_with_banks/index _3rdVS.html b/part2/River_with_banks/index _3rdVS.html new file mode 100644 index 0000000..55359b1 --- /dev/null +++ b/part2/River_with_banks/index _3rdVS.html @@ -0,0 +1,89 @@ + + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/part2/River_with_banks/index.js b/part2/River_with_banks/index.js new file mode 100644 index 0000000..b8bc058 --- /dev/null +++ b/part2/River_with_banks/index.js @@ -0,0 +1,160 @@ +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + var NUM_WIDTH_PTS = 32; + var NUM_HEIGHT_PTS = 32; + + var message = document.getElementById("message"); + var canvas = document.getElementById("canvas"); + var context = createWebGLContext(canvas, message); + if (!context) { + return; + } + + /////////////////////////////////////////////////////////////////////////// + + context.viewport(0, 0, canvas.width, canvas.height); + context.clearColor(1.0, 1.0, 1.0, 1.0); + context.enable(context.GL_DEPTH_TEST); + + var persp = mat4.create(); + mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); + + var eye = [2.0, 1.0, 3.0]; + var center = [0.0, 0.0, 0.0]; + var up = [0.0, 0.0, 1.0]; + var view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + var positionLocation = 0; + var heightLocation = 1; + var u_modelViewPerspectiveLocation; + //var u_time; + //var delta=0.0; + + (function initializeShader() { + var program; + var vs = getShaderSource(document.getElementById("vs")); + var fs = getShaderSource(document.getElementById("fs")); + + var program = createProgram(context, vs, fs, message); + context.bindAttribLocation(program, positionLocation, "position"); + u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + // utime=context.getUniformLocation(program,"u_time"); + + context.useProgram(program); + })(); + + var heights; + var numberOfIndices; + + (function initializeGrid() { + function uploadMesh(positions, heights, indices) { + // Positions + var positionsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, positionsName); + context.bufferData(context.ARRAY_BUFFER, positions, context.STATIC_DRAW); + context.vertexAttribPointer(positionLocation, 2, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(positionLocation); + + if (heights) + { + // Heights + var heightsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, heightsName); + context.bufferData(context.ARRAY_BUFFER, heights.length * heights.BYTES_PER_ELEMENT, context.STREAM_DRAW); + context.vertexAttribPointer(heightLocation, 1, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(heightLocation); + } + + // Indices + var indicesName = context.createBuffer(); + context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indicesName); + context.bufferData(context.ELEMENT_ARRAY_BUFFER, indices, context.STATIC_DRAW); + } + + var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; + var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; + + var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; + + var positions = new Float32Array(2 * numberOfPositions); + var indices = new Uint16Array(2 * ((NUM_HEIGHT_PTS * (NUM_WIDTH_PTS - 1)) + (NUM_WIDTH_PTS * (NUM_HEIGHT_PTS - 1)))); + + var positionsIndex = 0; + var indicesIndex = 0; + var length; + + for (var j = 0; j < NUM_WIDTH_PTS; ++j) + { + positions[positionsIndex++] = j /(NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = 0.0; + + if (j>=1) + { + length = positionsIndex / 2; + indices[indicesIndex++] = length - 2; + indices[indicesIndex++] = length - 1; + } + } + + for (var i = 0; i < HEIGHT_DIVISIONS; ++i) + { + var v = (i + 1) / (NUM_HEIGHT_PTS - 1); + positions[positionsIndex++] = 0.0; + positions[positionsIndex++] = v; + + length = (positionsIndex / 2); + indices[indicesIndex++] = length - 1; + indices[indicesIndex++] = length - 1 - NUM_WIDTH_PTS; + + for (var k = 0; k < WIDTH_DIVISIONS; ++k) + { + positions[positionsIndex++] = (k + 1) / (NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = v; + + length = positionsIndex / 2; + var new_pt = length - 1; + indices[indicesIndex++] = new_pt - 1; // Previous side + indices[indicesIndex++] = new_pt; + + indices[indicesIndex++] = new_pt - NUM_WIDTH_PTS; // Previous bottom + indices[indicesIndex++] = new_pt; + } + } + + uploadMesh(positions, heights, indices); + numberOfIndices = indices.length; + })(); + + + (function animate(){ + /////////////////////////////////////////////////////////////////////////// + // Update + + var model = mat4.create(); + mat4.identity(model); + mat4.translate(model, [-0.5, -0.5, 0.0]); + var mv = mat4.create(); + mat4.multiply(view, model, mv); + var mvp = mat4.create(); + mat4.multiply(persp, mv, mvp); + //delta += 0.0009; + // context.uniform1f(u_time, delta); + + + + + /////////////////////////////////////////////////////////////////////////// + // Render + context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); + + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); + + window.requestAnimFrame(animate); + })(); + +}()); diff --git a/part2/noise3D.js b/part2/River_with_banks/noise3D.js similarity index 97% rename from part2/noise3D.js rename to part2/River_with_banks/noise3D.js index d519f47..2d4ffd2 100644 --- a/part2/noise3D.js +++ b/part2/River_with_banks/noise3D.js @@ -1,316 +1,316 @@ -(function(exports) { - "use strict"; - /*global window,vec3*/ - - exports = exports || window; - - function step(edge, x) { - return [ - (x[0] < edge[0]) ? 0.0 : 1.0, - (x[1] < edge[1]) ? 0.0 : 1.0, - (x[2] < edge[2]) ? 0.0 : 1.0 - ]; - } - - function step_vec4(edge, x) { - return [ - (x[0] < edge[0]) ? 0.0 : 1.0, - (x[1] < edge[1]) ? 0.0 : 1.0, - (x[2] < edge[2]) ? 0.0 : 1.0, - (x[3] < edge[3]) ? 0.0 : 1.0 - ]; - } - - function min(x, y) { - return [ - y[0] < x[0] ? y[0] : x[0], - y[1] < x[1] ? y[1] : x[1], - y[2] < x[2] ? y[2] : x[2] - ]; - } - - function max(x, y) { - return [ - y[0] > x[0] ? y[0] : x[0], - y[1] > x[1] ? y[1] : x[1], - y[2] > x[2] ? y[2] : x[2] - ]; - } - - function max_vec4(x, y) { - return [ - y[0] > x[0] ? y[0] : x[0], - y[1] > x[1] ? y[1] : x[1], - y[2] > x[2] ? y[2] : x[2], - y[3] > x[3] ? y[3] : x[3] - ]; - } - - function vec4_dot(left, right) { - return left[0] * right[0] + - left[1] * right[1] + - left[2] * right[2] + - left[3] * right[3]; - } - - // - // Description : Array and textureless GLSL 2D/3D/4D simplex - // noise functions. - // Author : Ian McEwan, Ashima Arts. - // Maintainer : ijm - // Lastmod : 20110822 (ijm) - // License : Copyright (C) 2011 Ashima Arts. All rights reserved. - // Distributed under the MIT License. See LICENSE file. - // https://github.com/ashima/webgl-noise - // - function mod289_vec3(x) { - var temp = (1.0 / 289.0); - return [ - x[0] - Math.floor(x[0] * temp) * 289.0, - x[1] - Math.floor(x[1] * temp) * 289.0, - x[2] - Math.floor(x[2] * temp) * 289.0 - ]; - } - - function mod289_vec4(x) { - var temp = (1.0 / 289.0); - return [ - x[0] - Math.floor(x[0] * temp) * 289.0, - x[1] - Math.floor(x[1] * temp) * 289.0, - x[2] - Math.floor(x[2] * temp) * 289.0, - x[3] - Math.floor(x[3] * temp) * 289.0 - ]; - } - - function permute_vec4(x) { - return mod289_vec4([ - ((x[0]*34.0)+1.0)*x[0], - ((x[1]*34.0)+1.0)*x[1], - ((x[2]*34.0)+1.0)*x[2], - ((x[3]*34.0)+1.0)*x[3] - ]); - } - - function taylorInvSqrt_vec4(r) { - return [ - 1.79284291400159 - 0.85373472095314 * r[0], - 1.79284291400159 - 0.85373472095314 * r[1], - 1.79284291400159 - 0.85373472095314 * r[2], - 1.79284291400159 - 0.85373472095314 * r[3] - ]; - } - - exports.snoise = function(v) { - // const vec2 C = vec2(1.0f/6.0f, 1.0f/3.0f) ; - // const vec4 D = vec4(0.0f, 0.5f, 1.0f, 2.0f); - var C = [1.0/6.0, 1.0/3.0]; - var D = [0.0, 0.5, 1.0, 2.0]; - - // vec3 i = floor(v + dot(v, vec3(C.y, C.y, C.y)) ); - // vec3 x0 = v - i + dot(i, vec3(C.x, C.x, C.x) ); - var temp0 = vec3.create(); - var temp3 = vec3.dot(v, [C[1], C[1], C[1]]); - vec3.add(v, [temp3, temp3, temp3], temp0); - var i = [Math.floor(temp0[0]), Math.floor(temp0[1]), Math.floor(temp0[2])]; - var temp1 = vec3.create(); - vec3.subtract(v, i, temp1); - var temp2 = vec3.dot(i, [C[0], C[0], C[0]]); - var x0 = vec3.create(); - vec3.add(temp1, [temp2, temp2, temp2], x0); - - // vec3 g = step(vec3(x0.y, x0.z, x0.x), vec3(x0.x, x0.y, x0.z)); - // vec3 l = 1.0f - g; - // vec3 i1 = min( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); - // vec3 i2 = max( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); - var g = step([x0[1], x0[2], x0[0]], [x0[0], x0[1], x0[2]]); - var l = [1.0 - g[0], 1.0 - g[1], 1.0 - g[2]]; - var i1 = min([g[0], g[1], g[2]], [l[2], l[0], l[1]]); - var i2 = max([g[0], g[1], g[2]], [l[2], l[0], l[1]]); - - // vec3 x1 = x0 - i1 + vec3(C.x, C.x, C.x); - // vec3 x2 = x0 - i2 + vec3(C.y, C.y, C.y); // 2.0*C.x = 1/3 = C.y - // vec3 x3 = x0 - vec3(D.y, D.y, D.y); // -1.0+3.0*C.x = -0.5 = -D.y - var temp4 = vec3.create(); - vec3.subtract(x0, i1, temp4); - var x1 = vec3.create(); - vec3.add(temp4, [C[0], C[0], C[0]], x1); - var temp5 = vec3.create(); - vec3.subtract(x0, i2, temp5); - var x2 = vec3.create(); - vec3.add(temp5, [C[1], C[1], C[1]], x2); - var x3 = vec3.create(); - vec3.subtract(x0, [D[1], D[1], D[1]], x3); - - // i = mod289(i); - // vec4 p = permute( permute( permute( - // i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - // + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) - // + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); - i = mod289_vec3(i); - var p = permute_vec4([i[2] + 0.0, i[2] + i1[2], i[2] + i2[2], i[2] + 1.0]); - p[0] += i[1] + 0.0; - p[1] += i[1] + i1[1]; - p[2] += i[1] + i2[1]; - p[3] += i[1] + 1.0; - p = permute_vec4(p); - p[0] += i[0] + 0.0; - p[1] += i[0] + i1[0]; - p[2] += i[0] + i2[0]; - p[3] += i[0] + 1.0; - p = permute_vec4(p); - - // float n_ = 0.142857142857f; // 1.0/7.0 - // vec3 ns = n_ * vec3(D.w, D.y, D.z) - vec3(D.x, D.z, D.x); -// var n_ = 0.142857142857; // 1.0/7.0 -// var ns = [ -// n_ * D[3] - D[0], -// n_ * D[1] - D[2], -// n_ * D[2] - D[0] -// ]; - var ns = [ - 0.28571430, - -0.92857140, - 0.14285715 - ]; - - // vec4 j = p - 49.0f * floor(p * ns.z * ns.z); // mod(p,7*7) - var j = [ - p[0] - 49.0 * Math.floor(p[0] * ns[2] * ns[2]), - p[1] - 49.0 * Math.floor(p[1] * ns[2] * ns[2]), - p[2] - 49.0 * Math.floor(p[2] * ns[2] * ns[2]), - p[3] - 49.0 * Math.floor(p[3] * ns[2] * ns[2]) - ]; - - // vec4 x_ = floor(j * ns.z); - // vec4 y_ = floor(j - 7.0f * x_ ); // mod(j,N) - var x_ = [ - Math.floor(j[0] * ns[2]), - Math.floor(j[1] * ns[2]), - Math.floor(j[2] * ns[2]), - Math.floor(j[3] * ns[2]) - ]; - var y_ = [ - Math.floor(j[0] - 7.0 * x_[0] ), - Math.floor(j[1] - 7.0 * x_[1] ), - Math.floor(j[2] - 7.0 * x_[2] ), - Math.floor(j[3] - 7.0 * x_[3] ) - ]; - - // vec4 x = x_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); - // vec4 y = y_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); - // vec4 h = 1.0f - abs(x) - abs(y); - var x = [ - x_[0] *ns[0] + ns[1], - x_[1] *ns[0] + ns[1], - x_[2] *ns[0] + ns[1], - x_[3] *ns[0] + ns[1] - ]; - var y = [ - y_[0] *ns[0] + ns[1], - y_[1] *ns[0] + ns[1], - y_[2] *ns[0] + ns[1], - y_[3] *ns[0] + ns[1] - ]; - var h = [ - 1.0 - Math.abs(x[0]) - Math.abs(y[0]), - 1.0 - Math.abs(x[1]) - Math.abs(y[1]), - 1.0 - Math.abs(x[2]) - Math.abs(y[2]), - 1.0 - Math.abs(x[3]) - Math.abs(y[3]) - ]; - - // vec4 b0 = vec4( vec2(x.x, x.y), vec2(y.x, y.y) ); - // vec4 b1 = vec4( vec2(x.z, x.w), vec2(y.z, y.w) ); - var b0 = [x[0], x[1], y[0], y[1]]; - var b1 = [x[2], x[3], y[2], y[3]]; - - // vec4 s0 = floor(b0)*2.0f + 1.0f; - // vec4 s1 = floor(b1)*2.0f + 1.0f; - // vec4 sh = -step(h, vec4(0.0)); - - var s0 = [ - Math.floor(b0[0])*2.0 + 1.0, - Math.floor(b0[1])*2.0 + 1.0, - Math.floor(b0[2])*2.0 + 1.0, - Math.floor(b0[3])*2.0 + 1.0 - ]; - var s1 = [ - Math.floor(b1[0])*2.0 + 1.0, - Math.floor(b1[1])*2.0 + 1.0, - Math.floor(b1[2])*2.0 + 1.0, - Math.floor(b1[3])*2.0 + 1.0 - ]; - var sh = step_vec4(h, [0.0, 0.0, 0.0, 0.0]); - sh[0] = -sh[0]; - sh[1] = -sh[1]; - sh[2] = -sh[2]; - sh[3] = -sh[3]; - - // vec4 a0 = vec4(b0.x, b0.z, b0.y, b0.w) + vec4(s0.x, s0.z, s0.y, s0.w) * vec4(sh.x, sh.x, sh.y, sh.y) ; - // vec4 a1 = vec4(b1.x, b1.z, b1.y, b1.w) + vec4(s1.x, s1.z, s1.y, s1.w) * vec4(sh.z, sh.z, sh.w, sh.w) ; - var a0 = [ - b0[0] + s0[0] * sh[0], - b0[2] + s0[2] * sh[0], - b0[1] + s0[1] * sh[1], - b0[3] + s0[3] * sh[1] - ]; - var a1 = [ - b1[0] + s1[0] * sh[2], - b1[2] + s1[2] * sh[2], - b1[1] + s1[1] * sh[3], - b1[3] + s1[3] * sh[3] - ]; - - // vec3 p0 = vec3(a0.x, a0.y, h.x); - // vec3 p1 = vec3(a0.z, a0.w, h.y); - // vec3 p2 = vec3(a1.x, a1.y, h.z); - // vec3 p3 = vec3(a1.z, a1.w, h.w); - var p0 = [a0[0], a0[1], h[0]]; - var p1 = [a0[2], a0[3], h[1]]; - var p2 = [a1[0], a1[1], h[2]]; - var p3 = [a1[2], a1[3], h[3]]; - - // vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - // p0 *= norm.x; - // p1 *= norm.y; - // p2 *= norm.z; - // p3 *= norm.w; - var norm = taylorInvSqrt_vec4([vec3.dot(p0,p0), vec3.dot(p1,p1), vec3.dot(p2, p2), vec3.dot(p3,p3)]); - p0 = [p0[0]*norm[0], p0[1]*norm[0], p0[2]*norm[0]]; - p1 = [p1[0]*norm[1], p1[1]*norm[1], p1[2]*norm[1]]; - p2 = [p2[0]*norm[2], p2[1]*norm[2], p2[2]*norm[2]]; - p3 = [p3[0]*norm[3], p3[1]*norm[3], p3[2]*norm[3]]; - - // vec4 m = max(0.6f - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); - // m = m * m; - var m = max_vec4([ - 0.6 - vec3.dot(x0,x0), - 0.6 - vec3.dot(x1,x1), - 0.6 - vec3.dot(x2,x2), - 0.6 - vec3.dot(x3,x3) - ], [ - 0.0, - 0.0, - 0.0, - 0.0 - ]); - m[0] *= m[0]; - m[1] *= m[1]; - m[2] *= m[2]; - m[3] *= m[3]; - - // return 42.0f * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), - // dot(p2,x2), dot(p3,x3) ) ); - return 42.0 * vec4_dot([ - m[0] * m[0], - m[1] * m[1], - m[2] * m[2], - m[3] * m[3] - ], [ - vec3.dot(p0,x0), - vec3.dot(p1,x1), - vec3.dot(p2,x2), - vec3.dot(p3,x3) - ]); - }; - -}()); +(function(exports) { + "use strict"; + /*global window,vec3*/ + + exports = exports || window; + + function step(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0 + ]; + } + + function step_vec4(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0, + (x[3] < edge[3]) ? 0.0 : 1.0 + ]; + } + + function min(x, y) { + return [ + y[0] < x[0] ? y[0] : x[0], + y[1] < x[1] ? y[1] : x[1], + y[2] < x[2] ? y[2] : x[2] + ]; + } + + function max(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2] + ]; + } + + function max_vec4(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2], + y[3] > x[3] ? y[3] : x[3] + ]; + } + + function vec4_dot(left, right) { + return left[0] * right[0] + + left[1] * right[1] + + left[2] * right[2] + + left[3] * right[3]; + } + + // + // Description : Array and textureless GLSL 2D/3D/4D simplex + // noise functions. + // Author : Ian McEwan, Ashima Arts. + // Maintainer : ijm + // Lastmod : 20110822 (ijm) + // License : Copyright (C) 2011 Ashima Arts. All rights reserved. + // Distributed under the MIT License. See LICENSE file. + // https://github.com/ashima/webgl-noise + // + function mod289_vec3(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0 + ]; + } + + function mod289_vec4(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0, + x[3] - Math.floor(x[3] * temp) * 289.0 + ]; + } + + function permute_vec4(x) { + return mod289_vec4([ + ((x[0]*34.0)+1.0)*x[0], + ((x[1]*34.0)+1.0)*x[1], + ((x[2]*34.0)+1.0)*x[2], + ((x[3]*34.0)+1.0)*x[3] + ]); + } + + function taylorInvSqrt_vec4(r) { + return [ + 1.79284291400159 - 0.85373472095314 * r[0], + 1.79284291400159 - 0.85373472095314 * r[1], + 1.79284291400159 - 0.85373472095314 * r[2], + 1.79284291400159 - 0.85373472095314 * r[3] + ]; + } + + exports.snoise = function(v) { + // const vec2 C = vec2(1.0f/6.0f, 1.0f/3.0f) ; + // const vec4 D = vec4(0.0f, 0.5f, 1.0f, 2.0f); + var C = [1.0/6.0, 1.0/3.0]; + var D = [0.0, 0.5, 1.0, 2.0]; + + // vec3 i = floor(v + dot(v, vec3(C.y, C.y, C.y)) ); + // vec3 x0 = v - i + dot(i, vec3(C.x, C.x, C.x) ); + var temp0 = vec3.create(); + var temp3 = vec3.dot(v, [C[1], C[1], C[1]]); + vec3.add(v, [temp3, temp3, temp3], temp0); + var i = [Math.floor(temp0[0]), Math.floor(temp0[1]), Math.floor(temp0[2])]; + var temp1 = vec3.create(); + vec3.subtract(v, i, temp1); + var temp2 = vec3.dot(i, [C[0], C[0], C[0]]); + var x0 = vec3.create(); + vec3.add(temp1, [temp2, temp2, temp2], x0); + + // vec3 g = step(vec3(x0.y, x0.z, x0.x), vec3(x0.x, x0.y, x0.z)); + // vec3 l = 1.0f - g; + // vec3 i1 = min( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + // vec3 i2 = max( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + var g = step([x0[1], x0[2], x0[0]], [x0[0], x0[1], x0[2]]); + var l = [1.0 - g[0], 1.0 - g[1], 1.0 - g[2]]; + var i1 = min([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + var i2 = max([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + + // vec3 x1 = x0 - i1 + vec3(C.x, C.x, C.x); + // vec3 x2 = x0 - i2 + vec3(C.y, C.y, C.y); // 2.0*C.x = 1/3 = C.y + // vec3 x3 = x0 - vec3(D.y, D.y, D.y); // -1.0+3.0*C.x = -0.5 = -D.y + var temp4 = vec3.create(); + vec3.subtract(x0, i1, temp4); + var x1 = vec3.create(); + vec3.add(temp4, [C[0], C[0], C[0]], x1); + var temp5 = vec3.create(); + vec3.subtract(x0, i2, temp5); + var x2 = vec3.create(); + vec3.add(temp5, [C[1], C[1], C[1]], x2); + var x3 = vec3.create(); + vec3.subtract(x0, [D[1], D[1], D[1]], x3); + + // i = mod289(i); + // vec4 p = permute( permute( permute( + // i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + // + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + // + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + i = mod289_vec3(i); + var p = permute_vec4([i[2] + 0.0, i[2] + i1[2], i[2] + i2[2], i[2] + 1.0]); + p[0] += i[1] + 0.0; + p[1] += i[1] + i1[1]; + p[2] += i[1] + i2[1]; + p[3] += i[1] + 1.0; + p = permute_vec4(p); + p[0] += i[0] + 0.0; + p[1] += i[0] + i1[0]; + p[2] += i[0] + i2[0]; + p[3] += i[0] + 1.0; + p = permute_vec4(p); + + // float n_ = 0.142857142857f; // 1.0/7.0 + // vec3 ns = n_ * vec3(D.w, D.y, D.z) - vec3(D.x, D.z, D.x); +// var n_ = 0.142857142857; // 1.0/7.0 +// var ns = [ +// n_ * D[3] - D[0], +// n_ * D[1] - D[2], +// n_ * D[2] - D[0] +// ]; + var ns = [ + 0.28571430, + -0.92857140, + 0.14285715 + ]; + + // vec4 j = p - 49.0f * floor(p * ns.z * ns.z); // mod(p,7*7) + var j = [ + p[0] - 49.0 * Math.floor(p[0] * ns[2] * ns[2]), + p[1] - 49.0 * Math.floor(p[1] * ns[2] * ns[2]), + p[2] - 49.0 * Math.floor(p[2] * ns[2] * ns[2]), + p[3] - 49.0 * Math.floor(p[3] * ns[2] * ns[2]) + ]; + + // vec4 x_ = floor(j * ns.z); + // vec4 y_ = floor(j - 7.0f * x_ ); // mod(j,N) + var x_ = [ + Math.floor(j[0] * ns[2]), + Math.floor(j[1] * ns[2]), + Math.floor(j[2] * ns[2]), + Math.floor(j[3] * ns[2]) + ]; + var y_ = [ + Math.floor(j[0] - 7.0 * x_[0] ), + Math.floor(j[1] - 7.0 * x_[1] ), + Math.floor(j[2] - 7.0 * x_[2] ), + Math.floor(j[3] - 7.0 * x_[3] ) + ]; + + // vec4 x = x_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 y = y_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 h = 1.0f - abs(x) - abs(y); + var x = [ + x_[0] *ns[0] + ns[1], + x_[1] *ns[0] + ns[1], + x_[2] *ns[0] + ns[1], + x_[3] *ns[0] + ns[1] + ]; + var y = [ + y_[0] *ns[0] + ns[1], + y_[1] *ns[0] + ns[1], + y_[2] *ns[0] + ns[1], + y_[3] *ns[0] + ns[1] + ]; + var h = [ + 1.0 - Math.abs(x[0]) - Math.abs(y[0]), + 1.0 - Math.abs(x[1]) - Math.abs(y[1]), + 1.0 - Math.abs(x[2]) - Math.abs(y[2]), + 1.0 - Math.abs(x[3]) - Math.abs(y[3]) + ]; + + // vec4 b0 = vec4( vec2(x.x, x.y), vec2(y.x, y.y) ); + // vec4 b1 = vec4( vec2(x.z, x.w), vec2(y.z, y.w) ); + var b0 = [x[0], x[1], y[0], y[1]]; + var b1 = [x[2], x[3], y[2], y[3]]; + + // vec4 s0 = floor(b0)*2.0f + 1.0f; + // vec4 s1 = floor(b1)*2.0f + 1.0f; + // vec4 sh = -step(h, vec4(0.0)); + + var s0 = [ + Math.floor(b0[0])*2.0 + 1.0, + Math.floor(b0[1])*2.0 + 1.0, + Math.floor(b0[2])*2.0 + 1.0, + Math.floor(b0[3])*2.0 + 1.0 + ]; + var s1 = [ + Math.floor(b1[0])*2.0 + 1.0, + Math.floor(b1[1])*2.0 + 1.0, + Math.floor(b1[2])*2.0 + 1.0, + Math.floor(b1[3])*2.0 + 1.0 + ]; + var sh = step_vec4(h, [0.0, 0.0, 0.0, 0.0]); + sh[0] = -sh[0]; + sh[1] = -sh[1]; + sh[2] = -sh[2]; + sh[3] = -sh[3]; + + // vec4 a0 = vec4(b0.x, b0.z, b0.y, b0.w) + vec4(s0.x, s0.z, s0.y, s0.w) * vec4(sh.x, sh.x, sh.y, sh.y) ; + // vec4 a1 = vec4(b1.x, b1.z, b1.y, b1.w) + vec4(s1.x, s1.z, s1.y, s1.w) * vec4(sh.z, sh.z, sh.w, sh.w) ; + var a0 = [ + b0[0] + s0[0] * sh[0], + b0[2] + s0[2] * sh[0], + b0[1] + s0[1] * sh[1], + b0[3] + s0[3] * sh[1] + ]; + var a1 = [ + b1[0] + s1[0] * sh[2], + b1[2] + s1[2] * sh[2], + b1[1] + s1[1] * sh[3], + b1[3] + s1[3] * sh[3] + ]; + + // vec3 p0 = vec3(a0.x, a0.y, h.x); + // vec3 p1 = vec3(a0.z, a0.w, h.y); + // vec3 p2 = vec3(a1.x, a1.y, h.z); + // vec3 p3 = vec3(a1.z, a1.w, h.w); + var p0 = [a0[0], a0[1], h[0]]; + var p1 = [a0[2], a0[3], h[1]]; + var p2 = [a1[0], a1[1], h[2]]; + var p3 = [a1[2], a1[3], h[3]]; + + // vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + // p0 *= norm.x; + // p1 *= norm.y; + // p2 *= norm.z; + // p3 *= norm.w; + var norm = taylorInvSqrt_vec4([vec3.dot(p0,p0), vec3.dot(p1,p1), vec3.dot(p2, p2), vec3.dot(p3,p3)]); + p0 = [p0[0]*norm[0], p0[1]*norm[0], p0[2]*norm[0]]; + p1 = [p1[0]*norm[1], p1[1]*norm[1], p1[2]*norm[1]]; + p2 = [p2[0]*norm[2], p2[1]*norm[2], p2[2]*norm[2]]; + p3 = [p3[0]*norm[3], p3[1]*norm[3], p3[2]*norm[3]]; + + // vec4 m = max(0.6f - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + // m = m * m; + var m = max_vec4([ + 0.6 - vec3.dot(x0,x0), + 0.6 - vec3.dot(x1,x1), + 0.6 - vec3.dot(x2,x2), + 0.6 - vec3.dot(x3,x3) + ], [ + 0.0, + 0.0, + 0.0, + 0.0 + ]); + m[0] *= m[0]; + m[1] *= m[1]; + m[2] *= m[2]; + m[3] *= m[3]; + + // return 42.0f * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + // dot(p2,x2), dot(p3,x3) ) ); + return 42.0 * vec4_dot([ + m[0] * m[0], + m[1] * m[1], + m[2] * m[2], + m[3] * m[3] + ], [ + vec3.dot(p0,x0), + vec3.dot(p1,x1), + vec3.dot(p2,x2), + vec3.dot(p3,x3) + ]); + }; + +}()); diff --git a/part2/simplex.vert b/part2/River_with_banks/simplex.vert similarity index 96% rename from part2/simplex.vert rename to part2/River_with_banks/simplex.vert index 13dd1ca..e1ff07a 100644 --- a/part2/simplex.vert +++ b/part2/River_with_banks/simplex.vert @@ -1,39 +1,39 @@ -vec3 permute(vec3 x) { - x = ((x*34.0)+1.0)*x; - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -float simplexNoise(vec2 v) - { - const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); - - vec2 i = floor(v + dot(v, C.yy) ); - vec2 x0 = v - i + dot(i, C.xx); - - vec2 i1; - i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); - - vec4 x12 = x0.xyxy + C.xxzz; - x12.xy -= i1; - - i = i - floor(i * (1.0 / 289.0)) * 289.0; - - vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) - + i.x + vec3(0.0, i1.x, 1.0 )); - - vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); - m = m*m ; - m = m*m ; - - vec3 x = 2.0 * fract(p * C.www) - 1.0; - vec3 h = abs(x) - 0.5; - vec3 ox = floor(x + 0.5); - vec3 a0 = x - ox; - - m *= inversesqrt( a0*a0 + h*h ); - - vec3 g; - g.x = a0.x * x0.x + h.x * x0.y; - g.yz = a0.yz * x12.xz + h.yz * x12.yw; - return 130.0 * dot(m, g); +vec3 permute(vec3 x) { + x = ((x*34.0)+1.0)*x; + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +float simplexNoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = i - floor(i * (1.0 / 289.0)) * 289.0; + + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= inversesqrt( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); } \ No newline at end of file diff --git a/part2/webGLUtility.js b/part2/River_with_banks/webGLUtility.js similarity index 97% rename from part2/webGLUtility.js rename to part2/River_with_banks/webGLUtility.js index ffc2665..c9de391 100644 --- a/part2/webGLUtility.js +++ b/part2/River_with_banks/webGLUtility.js @@ -1,97 +1,97 @@ -(function(exports) { - "use strict"; - /*global window*/ - - exports = exports || window; - - /////////////////////////////////////////////////////////////////////////// - // Shim from http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - - exports.requestAnimFrame = - window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function( callback ){ - window.setTimeout(callback, 1000 / 60); - }; - - /////////////////////////////////////////////////////////////////////////// - // getShader based on http://learningwebgl.com/cookbook/index.php/Loading_shaders_from_HTML_script_tags - - exports.getShaderSource = function(script) { - var str = ""; - var k = script.firstChild; - while (k) { - if (k.nodeType == 3) { - str += k.textContent; - } - k = k.nextSibling; - } - - return str; - }; - - /////////////////////////////////////////////////////////////////////////// - - exports.createWebGLContext = function(canvas, message) { - if (!window.WebGLRenderingContext) { - message.innerText = "The browser does not support WebGL. Visit http://get.webgl.org."; - return undefined; - } - - var context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); - - if (!context && message) { - message.innerText = "The browser supports WebGL, but initialization failed."; - } - - return context; - }; - - exports.createProgram = function(context, vertexShaderSource, fragmentShaderSource, message) { - var program = context.createProgram(); - var vs = context.createShader(context.VERTEX_SHADER); - var fs = context.createShader(context.FRAGMENT_SHADER); - - context.attachShader(program, vs); - context.attachShader(program, fs); - - // Mark shader for deletion when the program is deleted - context.deleteShader(vs); - context.deleteShader(fs); - - context.shaderSource(vs, vertexShaderSource); - context.compileShader(vs); - if (!context.getShaderParameter(vs, context.COMPILE_STATUS)) { - if (message) { - message.innerText += context.getShaderInfoLog(vs) + "\n"; - } - context.deleteProgram(program); - return; - } - - context.shaderSource(fs, fragmentShaderSource); - context.compileShader(fs); - if (!context.getShaderParameter(fs, context.COMPILE_STATUS)) { - if (message) { - message.innerText += context.getShaderInfoLog(fs) + "\n"; - } - context.deleteProgram(program); - return; - } - - context.linkProgram(program); - if (!context.getProgramParameter(program, context.LINK_STATUS)) { - if (message) { - message.innerText += context.getProgramInfoLog(program) + "\n"; - } - context.deleteProgram(program); - return; - } - - return program; - }; - -}()); +(function(exports) { + "use strict"; + /*global window*/ + + exports = exports || window; + + /////////////////////////////////////////////////////////////////////////// + // Shim from http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + + exports.requestAnimFrame = + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function( callback ){ + window.setTimeout(callback, 1000 / 60); + }; + + /////////////////////////////////////////////////////////////////////////// + // getShader based on http://learningwebgl.com/cookbook/index.php/Loading_shaders_from_HTML_script_tags + + exports.getShaderSource = function(script) { + var str = ""; + var k = script.firstChild; + while (k) { + if (k.nodeType == 3) { + str += k.textContent; + } + k = k.nextSibling; + } + + return str; + }; + + /////////////////////////////////////////////////////////////////////////// + + exports.createWebGLContext = function(canvas, message) { + if (!window.WebGLRenderingContext) { + message.innerText = "The browser does not support WebGL. Visit http://get.webgl.org."; + return undefined; + } + + var context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + + if (!context && message) { + message.innerText = "The browser supports WebGL, but initialization failed."; + } + + return context; + }; + + exports.createProgram = function(context, vertexShaderSource, fragmentShaderSource, message) { + var program = context.createProgram(); + var vs = context.createShader(context.VERTEX_SHADER); + var fs = context.createShader(context.FRAGMENT_SHADER); + + context.attachShader(program, vs); + context.attachShader(program, fs); + + // Mark shader for deletion when the program is deleted + context.deleteShader(vs); + context.deleteShader(fs); + + context.shaderSource(vs, vertexShaderSource); + context.compileShader(vs); + if (!context.getShaderParameter(vs, context.COMPILE_STATUS)) { + if (message) { + message.innerText += context.getShaderInfoLog(vs) + "\n"; + } + context.deleteProgram(program); + return; + } + + context.shaderSource(fs, fragmentShaderSource); + context.compileShader(fs); + if (!context.getShaderParameter(fs, context.COMPILE_STATUS)) { + if (message) { + message.innerText += context.getShaderInfoLog(fs) + "\n"; + } + context.deleteProgram(program); + return; + } + + context.linkProgram(program); + if (!context.getProgramParameter(program, context.LINK_STATUS)) { + if (message) { + message.innerText += context.getProgramInfoLog(program) + "\n"; + } + context.deleteProgram(program); + return; + } + + return program; + }; + +}()); diff --git a/part2/Simplex/gl-matrix.js b/part2/Simplex/gl-matrix.js new file mode 100644 index 0000000..2e1bdb9 --- /dev/null +++ b/part2/Simplex/gl-matrix.js @@ -0,0 +1,1909 @@ +/** + * @fileOverview gl-matrix - High performance matrix and vector operations for WebGL + * @author Brandon Jones + * @version 1.2.3 + */ + +/* + * Copyright (c) 2011 Brandon Jones + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +"use strict"; + +// Type declarations +(function() { + // account for CommonJS environments + var _global = (typeof(exports) != 'undefined') ? global : window; + _global.glMatrixArrayType = _global.MatrixArray = null; + + /** + * @class 3 Dimensional Vector + * @name vec3 + */ + _global.vec3 = {}; + + /** + * @class 3x3 Matrix + * @name mat3 + */ + _global.mat3 = {}; + + /** + * @class 4x4 Matrix + * @name mat4 + */ + _global.mat4 = {}; + + /** + * @class Quaternion + * @name quat4 + */ + _global.quat4 = {}; + + // explicitly sets and returns the type of array to use within glMatrix + _global.setMatrixArrayType = function(type) { + return glMatrixArrayType = MatrixArray = type; + }; + + // auto-detects and returns the best type of array to use within glMatrix, falling + // back to Array if typed arrays are unsupported + _global.determineMatrixArrayType = function() { + return setMatrixArrayType((typeof Float32Array !== 'undefined') ? Float32Array : Array); + }; + + determineMatrixArrayType(); +})(); + +/* + * vec3 + */ + +/** + * Creates a new instance of a vec3 using the default array type + * Any javascript array-like objects containing at least 3 numeric elements can serve as a vec3 + * + * @param {vec3} [vec] vec3 containing values to initialize with + * + * @returns {vec3} New vec3 + */ +vec3.create = function (vec) { + var dest = new MatrixArray(3); + + if (vec) { + dest[0] = vec[0]; + dest[1] = vec[1]; + dest[2] = vec[2]; + } else { + dest[0] = dest[1] = dest[2] = 0; + } + + return dest; +}; + +/** + * Copies the values of one vec3 to another + * + * @param {vec3} vec vec3 containing values to copy + * @param {vec3} dest vec3 receiving copied values + * + * @returns {vec3} dest + */ +vec3.set = function (vec, dest) { + dest[0] = vec[0]; + dest[1] = vec[1]; + dest[2] = vec[2]; + + return dest; +}; + +/** + * Performs a vector addition + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.add = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] += vec2[0]; + vec[1] += vec2[1]; + vec[2] += vec2[2]; + return vec; + } + + dest[0] = vec[0] + vec2[0]; + dest[1] = vec[1] + vec2[1]; + dest[2] = vec[2] + vec2[2]; + return dest; +}; + +/** + * Performs a vector subtraction + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.subtract = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] -= vec2[0]; + vec[1] -= vec2[1]; + vec[2] -= vec2[2]; + return vec; + } + + dest[0] = vec[0] - vec2[0]; + dest[1] = vec[1] - vec2[1]; + dest[2] = vec[2] - vec2[2]; + return dest; +}; + +/** + * Performs a vector multiplication + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.multiply = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] *= vec2[0]; + vec[1] *= vec2[1]; + vec[2] *= vec2[2]; + return vec; + } + + dest[0] = vec[0] * vec2[0]; + dest[1] = vec[1] * vec2[1]; + dest[2] = vec[2] * vec2[2]; + return dest; +}; + +/** + * Negates the components of a vec3 + * + * @param {vec3} vec vec3 to negate + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.negate = function (vec, dest) { + if (!dest) { dest = vec; } + + dest[0] = -vec[0]; + dest[1] = -vec[1]; + dest[2] = -vec[2]; + return dest; +}; + +/** + * Multiplies the components of a vec3 by a scalar value + * + * @param {vec3} vec vec3 to scale + * @param {number} val Value to scale by + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.scale = function (vec, val, dest) { + if (!dest || vec === dest) { + vec[0] *= val; + vec[1] *= val; + vec[2] *= val; + return vec; + } + + dest[0] = vec[0] * val; + dest[1] = vec[1] * val; + dest[2] = vec[2] * val; + return dest; +}; + +/** + * Generates a unit vector of the same direction as the provided vec3 + * If vector length is 0, returns [0, 0, 0] + * + * @param {vec3} vec vec3 to normalize + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.normalize = function (vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + len = Math.sqrt(x * x + y * y + z * z); + + if (!len) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + return dest; + } else if (len === 1) { + dest[0] = x; + dest[1] = y; + dest[2] = z; + return dest; + } + + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + return dest; +}; + +/** + * Generates the cross product of two vec3s + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.cross = function (vec, vec2, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + x2 = vec2[0], y2 = vec2[1], z2 = vec2[2]; + + dest[0] = y * z2 - z * y2; + dest[1] = z * x2 - x * z2; + dest[2] = x * y2 - y * x2; + return dest; +}; + +/** + * Caclulates the length of a vec3 + * + * @param {vec3} vec vec3 to calculate length of + * + * @returns {number} Length of vec + */ +vec3.length = function (vec) { + var x = vec[0], y = vec[1], z = vec[2]; + return Math.sqrt(x * x + y * y + z * z); +}; + +/** + * Caclulates the dot product of two vec3s + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * + * @returns {number} Dot product of vec and vec2 + */ +vec3.dot = function (vec, vec2) { + return vec[0] * vec2[0] + vec[1] * vec2[1] + vec[2] * vec2[2]; +}; + +/** + * Generates a unit vector pointing from one vector to another + * + * @param {vec3} vec Origin vec3 + * @param {vec3} vec2 vec3 to point to + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.direction = function (vec, vec2, dest) { + if (!dest) { dest = vec; } + + var x = vec[0] - vec2[0], + y = vec[1] - vec2[1], + z = vec[2] - vec2[2], + len = Math.sqrt(x * x + y * y + z * z); + + if (!len) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + return dest; + } + + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + return dest; +}; + +/** + * Performs a linear interpolation between two vec3 + * + * @param {vec3} vec First vector + * @param {vec3} vec2 Second vector + * @param {number} lerp Interpolation amount between the two inputs + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.lerp = function (vec, vec2, lerp, dest) { + if (!dest) { dest = vec; } + + dest[0] = vec[0] + lerp * (vec2[0] - vec[0]); + dest[1] = vec[1] + lerp * (vec2[1] - vec[1]); + dest[2] = vec[2] + lerp * (vec2[2] - vec[2]); + + return dest; +}; + +/** + * Calculates the euclidian distance between two vec3 + * + * Params: + * @param {vec3} vec First vector + * @param {vec3} vec2 Second vector + * + * @returns {number} Distance between vec and vec2 + */ +vec3.dist = function (vec, vec2) { + var x = vec2[0] - vec[0], + y = vec2[1] - vec[1], + z = vec2[2] - vec[2]; + + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Projects the specified vec3 from screen space into object space + * Based on the Mesa gluUnProject implementation + * + * @param {vec3} vec Screen-space vector to project + * @param {mat4} view View matrix + * @param {mat4} proj Projection matrix + * @param {vec4} viewport Viewport as given to gl.viewport [x, y, width, height] + * @param {vec3} [dest] vec3 receiving unprojected result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.unproject = function (vec, view, proj, viewport, dest) { + if (!dest) { dest = vec; } + + var m = mat4.create(); + var v = new MatrixArray(4); + + v[0] = (vec[0] - viewport[0]) * 2.0 / viewport[2] - 1.0; + v[1] = (vec[1] - viewport[1]) * 2.0 / viewport[3] - 1.0; + v[2] = 2.0 * vec[2] - 1.0; + v[3] = 1.0; + + mat4.multiply(proj, view, m); + if(!mat4.inverse(m)) { return null; } + + mat4.multiplyVec4(m, v); + if(v[3] === 0.0) { return null; } + + dest[0] = v[0] / v[3]; + dest[1] = v[1] / v[3]; + dest[2] = v[2] / v[3]; + + return dest; +}; + +/** + * Returns a string representation of a vector + * + * @param {vec3} vec Vector to represent as a string + * + * @returns {string} String representation of vec + */ +vec3.str = function (vec) { + return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']'; +}; + +/* + * mat3 + */ + +/** + * Creates a new instance of a mat3 using the default array type + * Any javascript array-like object containing at least 9 numeric elements can serve as a mat3 + * + * @param {mat3} [mat] mat3 containing values to initialize with + * + * @returns {mat3} New mat3 + */ +mat3.create = function (mat) { + var dest = new MatrixArray(9); + + if (mat) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + } + + return dest; +}; + +/** + * Copies the values of one mat3 to another + * + * @param {mat3} mat mat3 containing values to copy + * @param {mat3} dest mat3 receiving copied values + * + * @returns {mat3} dest + */ +mat3.set = function (mat, dest) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + return dest; +}; + +/** + * Sets a mat3 to an identity matrix + * + * @param {mat3} dest mat3 to set + * + * @returns dest if specified, otherwise a new mat3 + */ +mat3.identity = function (dest) { + if (!dest) { dest = mat3.create(); } + dest[0] = 1; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 1; + dest[5] = 0; + dest[6] = 0; + dest[7] = 0; + dest[8] = 1; + return dest; +}; + +/** + * Transposes a mat3 (flips the values over the diagonal) + * + * Params: + * @param {mat3} mat mat3 to transpose + * @param {mat3} [dest] mat3 receiving transposed values. If not specified result is written to mat + * + * @returns {mat3} dest is specified, mat otherwise + */ +mat3.transpose = function (mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +}; + +/** + * Copies the elements of a mat3 into the upper 3x3 elements of a mat4 + * + * @param {mat3} mat mat3 containing values to copy + * @param {mat4} [dest] mat4 receiving copied values + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat3.toMat4 = function (mat, dest) { + if (!dest) { dest = mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +}; + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat mat3 to represent as a string + * + * @param {string} String representation of mat + */ +mat3.str = function (mat) { + return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + + ', ' + mat[3] + ', ' + mat[4] + ', ' + mat[5] + + ', ' + mat[6] + ', ' + mat[7] + ', ' + mat[8] + ']'; +}; + +/* + * mat4 + */ + +/** + * Creates a new instance of a mat4 using the default array type + * Any javascript array-like object containing at least 16 numeric elements can serve as a mat4 + * + * @param {mat4} [mat] mat4 containing values to initialize with + * + * @returns {mat4} New mat4 + */ +mat4.create = function (mat) { + var dest = new MatrixArray(16); + + if (mat) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + return dest; +}; + +/** + * Copies the values of one mat4 to another + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat4} dest mat4 receiving copied values + * + * @returns {mat4} dest + */ +mat4.set = function (mat, dest) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Sets a mat4 to an identity matrix + * + * @param {mat4} dest mat4 to set + * + * @returns {mat4} dest + */ +mat4.identity = function (dest) { + if (!dest) { dest = mat4.create(); } + dest[0] = 1; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = 1; + dest[6] = 0; + dest[7] = 0; + dest[8] = 0; + dest[9] = 0; + dest[10] = 1; + dest[11] = 0; + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + return dest; +}; + +/** + * Transposes a mat4 (flips the values over the diagonal) + * + * @param {mat4} mat mat4 to transpose + * @param {mat4} [dest] mat4 receiving transposed values. If not specified result is written to mat + * + * @param {mat4} dest is specified, mat otherwise + */ +mat4.transpose = function (mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} mat mat4 to calculate determinant of + * + * @returns {number} determinant of mat + */ +mat4.determinant = function (mat) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + return (a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + + a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + + a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + + a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + + a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + + a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33); +}; + +/** + * Calculates the inverse matrix of a mat4 + * + * @param {mat4} mat mat4 to calculate inverse of + * @param {mat4} [dest] mat4 receiving inverse matrix. If not specified result is written to mat + * + * @param {mat4} dest is specified, mat otherwise, null if matrix cannot be inverted + */ +mat4.inverse = function (mat, dest) { + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06), + invDet; + + // Calculate the determinant + if (!d) { return null; } + invDet = 1 / d; + + dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; + dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; + dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; + dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; + dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; + dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; + dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; + dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; + dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; + dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; + dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; + dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; + dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; + dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; + dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; + dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; + + return dest; +}; + +/** + * Copies the upper 3x3 elements of a mat4 into another mat4 + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat4} [dest] mat4 receiving copied values + * + * @returns {mat4} dest is specified, a new mat4 otherwise + */ +mat4.toRotationMat = function (mat, dest) { + if (!dest) { dest = mat4.create(); } + + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + + return dest; +}; + +/** + * Copies the upper 3x3 elements of a mat4 into a mat3 + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat3} [dest] mat3 receiving copied values + * + * @returns {mat3} dest is specified, a new mat3 otherwise + */ +mat4.toMat3 = function (mat, dest) { + if (!dest) { dest = mat3.create(); } + + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[4]; + dest[4] = mat[5]; + dest[5] = mat[6]; + dest[6] = mat[8]; + dest[7] = mat[9]; + dest[8] = mat[10]; + + return dest; +}; + +/** + * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3 + * The resulting matrix is useful for calculating transformed normals + * + * Params: + * @param {mat4} mat mat4 containing values to invert and copy + * @param {mat3} [dest] mat3 receiving values + * + * @returns {mat3} dest is specified, a new mat3 otherwise, null if the matrix cannot be inverted + */ +mat4.toInverseMat3 = function (mat, dest) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[4], a11 = mat[5], a12 = mat[6], + a20 = mat[8], a21 = mat[9], a22 = mat[10], + + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, + + d = a00 * b01 + a01 * b11 + a02 * b21, + id; + + if (!d) { return null; } + id = 1 / d; + + if (!dest) { dest = mat3.create(); } + + dest[0] = b01 * id; + dest[1] = (-a22 * a01 + a02 * a21) * id; + dest[2] = (a12 * a01 - a02 * a11) * id; + dest[3] = b11 * id; + dest[4] = (a22 * a00 - a02 * a20) * id; + dest[5] = (-a12 * a00 + a02 * a10) * id; + dest[6] = b21 * id; + dest[7] = (-a21 * a00 + a01 * a20) * id; + dest[8] = (a11 * a00 - a01 * a10) * id; + + return dest; +}; + +/** + * Performs a matrix multiplication + * + * @param {mat4} mat First operand + * @param {mat4} mat2 Second operand + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.multiply = function (mat, mat2, dest) { + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3], + b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7], + b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11], + b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; + + return dest; +}; + +/** + * Transforms a vec3 with the given matrix + * 4th vector component is implicitly '1' + * + * @param {mat4} mat mat4 to transform the vector with + * @param {vec3} vec vec3 to transform + * @paran {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +mat4.multiplyVec3 = function (mat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2]; + + dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + + return dest; +}; + +/** + * Transforms a vec4 with the given matrix + * + * @param {mat4} mat mat4 to transform the vector with + * @param {vec4} vec vec4 to transform + * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vec + * + * @returns {vec4} dest if specified, vec otherwise + */ +mat4.multiplyVec4 = function (mat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; + + dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12] * w; + dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13] * w; + dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14] * w; + dest[3] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15] * w; + + return dest; +}; + +/** + * Translates a matrix by the given vector + * + * @param {mat4} mat mat4 to translate + * @param {vec3} vec vec3 specifying the translation + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.translate = function (mat, vec, dest) { + var x = vec[0], y = vec[1], z = vec[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; + + if (!dest || mat === dest) { + mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15]; + return mat; + } + + a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; + a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; + a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; + + dest[0] = a00; dest[1] = a01; dest[2] = a02; dest[3] = a03; + dest[4] = a10; dest[5] = a11; dest[6] = a12; dest[7] = a13; + dest[8] = a20; dest[9] = a21; dest[10] = a22; dest[11] = a23; + + dest[12] = a00 * x + a10 * y + a20 * z + mat[12]; + dest[13] = a01 * x + a11 * y + a21 * z + mat[13]; + dest[14] = a02 * x + a12 * y + a22 * z + mat[14]; + dest[15] = a03 * x + a13 * y + a23 * z + mat[15]; + return dest; +}; + +/** + * Scales a matrix by the given vector + * + * @param {mat4} mat mat4 to scale + * @param {vec3} vec vec3 specifying the scale for each axis + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @param {mat4} dest if specified, mat otherwise + */ +mat4.scale = function (mat, vec, dest) { + var x = vec[0], y = vec[1], z = vec[2]; + + if (!dest || mat === dest) { + mat[0] *= x; + mat[1] *= x; + mat[2] *= x; + mat[3] *= x; + mat[4] *= y; + mat[5] *= y; + mat[6] *= y; + mat[7] *= y; + mat[8] *= z; + mat[9] *= z; + mat[10] *= z; + mat[11] *= z; + return mat; + } + + dest[0] = mat[0] * x; + dest[1] = mat[1] * x; + dest[2] = mat[2] * x; + dest[3] = mat[3] * x; + dest[4] = mat[4] * y; + dest[5] = mat[5] * y; + dest[6] = mat[6] * y; + dest[7] = mat[7] * y; + dest[8] = mat[8] * z; + dest[9] = mat[9] * z; + dest[10] = mat[10] * z; + dest[11] = mat[11] * z; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the specified axis + * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {vec3} axis vec3 representing the axis to rotate around + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotate = function (mat, angle, axis, dest) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; + + if (!len) { return null; } + if (len !== 1) { + len = 1 / len; + x *= len; + y *= len; + z *= len; + } + + s = Math.sin(angle); + c = Math.cos(angle); + t = 1 - c; + + a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; + a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; + a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform rotation-specific matrix multiplication + dest[0] = a00 * b00 + a10 * b01 + a20 * b02; + dest[1] = a01 * b00 + a11 * b01 + a21 * b02; + dest[2] = a02 * b00 + a12 * b01 + a22 * b02; + dest[3] = a03 * b00 + a13 * b01 + a23 * b02; + + dest[4] = a00 * b10 + a10 * b11 + a20 * b12; + dest[5] = a01 * b10 + a11 * b11 + a21 * b12; + dest[6] = a02 * b10 + a12 * b11 + a22 * b12; + dest[7] = a03 * b10 + a13 * b11 + a23 * b12; + + dest[8] = a00 * b20 + a10 * b21 + a20 * b22; + dest[9] = a01 * b20 + a11 * b21 + a21 * b22; + dest[10] = a02 * b20 + a12 * b21 + a22 * b22; + dest[11] = a03 * b20 + a13 * b21 + a23 * b22; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateX = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a10 = mat[4], + a11 = mat[5], + a12 = mat[6], + a13 = mat[7], + a20 = mat[8], + a21 = mat[9], + a22 = mat[10], + a23 = mat[11]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[4] = a10 * c + a20 * s; + dest[5] = a11 * c + a21 * s; + dest[6] = a12 * c + a22 * s; + dest[7] = a13 * c + a23 * s; + + dest[8] = a10 * -s + a20 * c; + dest[9] = a11 * -s + a21 * c; + dest[10] = a12 * -s + a22 * c; + dest[11] = a13 * -s + a23 * c; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateY = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a00 = mat[0], + a01 = mat[1], + a02 = mat[2], + a03 = mat[3], + a20 = mat[8], + a21 = mat[9], + a22 = mat[10], + a23 = mat[11]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[0] = a00 * c + a20 * -s; + dest[1] = a01 * c + a21 * -s; + dest[2] = a02 * c + a22 * -s; + dest[3] = a03 * c + a23 * -s; + + dest[8] = a00 * s + a20 * c; + dest[9] = a01 * s + a21 * c; + dest[10] = a02 * s + a22 * c; + dest[11] = a03 * s + a23 * c; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateZ = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a00 = mat[0], + a01 = mat[1], + a02 = mat[2], + a03 = mat[3], + a10 = mat[4], + a11 = mat[5], + a12 = mat[6], + a13 = mat[7]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[0] = a00 * c + a10 * s; + dest[1] = a01 * c + a11 * s; + dest[2] = a02 * c + a12 * s; + dest[3] = a03 * c + a13 * s; + + dest[4] = a00 * -s + a10 * c; + dest[5] = a01 * -s + a11 * c; + dest[6] = a02 * -s + a12 * c; + dest[7] = a03 * -s + a13 * c; + + return dest; +}; + +/** + * Generates a frustum matrix with the given bounds + * + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.frustum = function (left, right, bottom, top, near, far, dest) { + if (!dest) { dest = mat4.create(); } + var rl = (right - left), + tb = (top - bottom), + fn = (far - near); + dest[0] = (near * 2) / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = (near * 2) / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = (right + left) / rl; + dest[9] = (top + bottom) / tb; + dest[10] = -(far + near) / fn; + dest[11] = -1; + dest[12] = 0; + dest[13] = 0; + dest[14] = -(far * near * 2) / fn; + dest[15] = 0; + return dest; +}; + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {number} fovy Vertical field of view + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.perspective = function (fovy, aspect, near, far, dest) { + var top = near * Math.tan(fovy * Math.PI / 360.0), + right = top * aspect; + return mat4.frustum(-right, right, -top, top, near, far, dest); +}; + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.ortho = function (left, right, bottom, top, near, far, dest) { + if (!dest) { dest = mat4.create(); } + var rl = (right - left), + tb = (top - bottom), + fn = (far - near); + dest[0] = 2 / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = 2 / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = 0; + dest[9] = 0; + dest[10] = -2 / fn; + dest[11] = 0; + dest[12] = -(left + right) / rl; + dest[13] = -(top + bottom) / tb; + dest[14] = -(far + near) / fn; + dest[15] = 1; + return dest; +}; + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing "up" + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.lookAt = function (eye, center, up, dest) { + if (!dest) { dest = mat4.create(); } + + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; + + if (eyex === centerx && eyey === centery && eyez === centerz) { + return mat4.identity(dest); + } + + //vec3.direction(eye, center, z); + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + // normalize (no check needed for 0 because of early return) + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + //vec3.normalize(vec3.cross(up, z, x)); + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + //vec3.normalize(vec3.cross(z, x, y)); + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + dest[0] = x0; + dest[1] = y0; + dest[2] = z0; + dest[3] = 0; + dest[4] = x1; + dest[5] = y1; + dest[6] = z1; + dest[7] = 0; + dest[8] = x2; + dest[9] = y2; + dest[10] = z2; + dest[11] = 0; + dest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + dest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + dest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + dest[15] = 1; + + return dest; +}; + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {quat4} quat Rotation quaternion + * @param {vec3} vec Translation vector + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to a new mat4 + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.fromRotationTranslation = function (quat, vec, dest) { + if (!dest) { dest = mat4.create(); } + + // Quaternion math + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + dest[3] = 0; + dest[4] = xy - wz; + dest[5] = 1 - (xx + zz); + dest[6] = yz + wx; + dest[7] = 0; + dest[8] = xz + wy; + dest[9] = yz - wx; + dest[10] = 1 - (xx + yy); + dest[11] = 0; + dest[12] = vec[0]; + dest[13] = vec[1]; + dest[14] = vec[2]; + dest[15] = 1; + + return dest; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat mat4 to represent as a string + * + * @returns {string} String representation of mat + */ +mat4.str = function (mat) { + return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] + + ', ' + mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] + + ', ' + mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] + + ', ' + mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']'; +}; + +/* + * quat4 + */ + +/** + * Creates a new instance of a quat4 using the default array type + * Any javascript array containing at least 4 numeric elements can serve as a quat4 + * + * @param {quat4} [quat] quat4 containing values to initialize with + * + * @returns {quat4} New quat4 + */ +quat4.create = function (quat) { + var dest = new MatrixArray(4); + + if (quat) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + } + + return dest; +}; + +/** + * Copies the values of one quat4 to another + * + * @param {quat4} quat quat4 containing values to copy + * @param {quat4} dest quat4 receiving copied values + * + * @returns {quat4} dest + */ +quat4.set = function (quat, dest) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + + return dest; +}; + +/** + * Calculates the W component of a quat4 from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat4} quat quat4 to calculate W component of + * @param {quat4} [dest] quat4 receiving calculated values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.calculateW = function (quat, dest) { + var x = quat[0], y = quat[1], z = quat[2]; + + if (!dest || quat === dest) { + quat[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return quat; + } + dest[0] = x; + dest[1] = y; + dest[2] = z; + dest[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return dest; +}; + +/** + * Calculates the dot product of two quaternions + * + * @param {quat4} quat First operand + * @param {quat4} quat2 Second operand + * + * @return {number} Dot product of quat and quat2 + */ +quat4.dot = function(quat, quat2){ + return quat[0]*quat2[0] + quat[1]*quat2[1] + quat[2]*quat2[2] + quat[3]*quat2[3]; +}; + +/** + * Calculates the inverse of a quat4 + * + * @param {quat4} quat quat4 to calculate inverse of + * @param {quat4} [dest] quat4 receiving inverse values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.inverse = function(quat, dest) { + var q0 = quat[0], q1 = quat[1], q2 = quat[2], q3 = quat[3], + dot = q0*q0 + q1*q1 + q2*q2 + q3*q3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + if(!dest || quat === dest) { + quat[0] *= -invDot; + quat[1] *= -invDot; + quat[2] *= -invDot; + quat[3] *= invDot; + return quat; + } + dest[0] = -quat[0]*invDot; + dest[1] = -quat[1]*invDot; + dest[2] = -quat[2]*invDot; + dest[3] = quat[3]*invDot; + return dest; +}; + + +/** + * Calculates the conjugate of a quat4 + * If the quaternion is normalized, this function is faster than quat4.inverse and produces the same result. + * + * @param {quat4} quat quat4 to calculate conjugate of + * @param {quat4} [dest] quat4 receiving conjugate values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.conjugate = function (quat, dest) { + if (!dest || quat === dest) { + quat[0] *= -1; + quat[1] *= -1; + quat[2] *= -1; + return quat; + } + dest[0] = -quat[0]; + dest[1] = -quat[1]; + dest[2] = -quat[2]; + dest[3] = quat[3]; + return dest; +}; + +/** + * Calculates the length of a quat4 + * + * Params: + * @param {quat4} quat quat4 to calculate length of + * + * @returns Length of quat + */ +quat4.length = function (quat) { + var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; + return Math.sqrt(x * x + y * y + z * z + w * w); +}; + +/** + * Generates a unit quaternion of the same direction as the provided quat4 + * If quaternion length is 0, returns [0, 0, 0, 0] + * + * @param {quat4} quat quat4 to normalize + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.normalize = function (quat, dest) { + if (!dest) { dest = quat; } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + len = Math.sqrt(x * x + y * y + z * z + w * w); + if (len === 0) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + return dest; + } + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + dest[3] = w * len; + + return dest; +}; + +/** + * Performs a quaternion multiplication + * + * @param {quat4} quat First operand + * @param {quat4} quat2 Second operand + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.multiply = function (quat, quat2, dest) { + if (!dest) { dest = quat; } + + var qax = quat[0], qay = quat[1], qaz = quat[2], qaw = quat[3], + qbx = quat2[0], qby = quat2[1], qbz = quat2[2], qbw = quat2[3]; + + dest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + dest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + dest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + dest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + return dest; +}; + +/** + * Transforms a vec3 with the given quaternion + * + * @param {quat4} quat quat4 to transform the vector with + * @param {vec3} vec vec3 to transform + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns dest if specified, vec otherwise + */ +quat4.multiplyVec3 = function (quat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return dest; +}; + +/** + * Calculates a 3x3 matrix from the given quat4 + * + * @param {quat4} quat quat4 to create matrix from + * @param {mat3} [dest] mat3 receiving operation result + * + * @returns {mat3} dest if specified, a new mat3 otherwise + */ +quat4.toMat3 = function (quat, dest) { + if (!dest) { dest = mat3.create(); } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + + dest[3] = xy - wz; + dest[4] = 1 - (xx + zz); + dest[5] = yz + wx; + + dest[6] = xz + wy; + dest[7] = yz - wx; + dest[8] = 1 - (xx + yy); + + return dest; +}; + +/** + * Calculates a 4x4 matrix from the given quat4 + * + * @param {quat4} quat quat4 to create matrix from + * @param {mat4} [dest] mat4 receiving operation result + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +quat4.toMat4 = function (quat, dest) { + if (!dest) { dest = mat4.create(); } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + dest[3] = 0; + + dest[4] = xy - wz; + dest[5] = 1 - (xx + zz); + dest[6] = yz + wx; + dest[7] = 0; + + dest[8] = xz + wy; + dest[9] = yz - wx; + dest[10] = 1 - (xx + yy); + dest[11] = 0; + + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + + return dest; +}; + +/** + * Performs a spherical linear interpolation between two quat4 + * + * @param {quat4} quat First quaternion + * @param {quat4} quat2 Second quaternion + * @param {number} slerp Interpolation amount between the two inputs + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.slerp = function (quat, quat2, slerp, dest) { + if (!dest) { dest = quat; } + + var cosHalfTheta = quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3], + halfTheta, + sinHalfTheta, + ratioA, + ratioB; + + if (Math.abs(cosHalfTheta) >= 1.0) { + if (dest !== quat) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + } + return dest; + } + + halfTheta = Math.acos(cosHalfTheta); + sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + + if (Math.abs(sinHalfTheta) < 0.001) { + dest[0] = (quat[0] * 0.5 + quat2[0] * 0.5); + dest[1] = (quat[1] * 0.5 + quat2[1] * 0.5); + dest[2] = (quat[2] * 0.5 + quat2[2] * 0.5); + dest[3] = (quat[3] * 0.5 + quat2[3] * 0.5); + return dest; + } + + ratioA = Math.sin((1 - slerp) * halfTheta) / sinHalfTheta; + ratioB = Math.sin(slerp * halfTheta) / sinHalfTheta; + + dest[0] = (quat[0] * ratioA + quat2[0] * ratioB); + dest[1] = (quat[1] * ratioA + quat2[1] * ratioB); + dest[2] = (quat[2] * ratioA + quat2[2] * ratioB); + dest[3] = (quat[3] * ratioA + quat2[3] * ratioB); + + return dest; +}; + +/** + * Returns a string representation of a quaternion + * + * @param {quat4} quat quat4 to represent as a string + * + * @returns {string} String representation of quat + */ +quat4.str = function (quat) { + return '[' + quat[0] + ', ' + quat[1] + ', ' + quat[2] + ', ' + quat[3] + ']'; +}; + diff --git a/part2/Simplex/index _simplex.html b/part2/Simplex/index _simplex.html new file mode 100644 index 0000000..74f2767 --- /dev/null +++ b/part2/Simplex/index _simplex.html @@ -0,0 +1,89 @@ + + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/part2/Simplex/index.js b/part2/Simplex/index.js new file mode 100644 index 0000000..b8bc058 --- /dev/null +++ b/part2/Simplex/index.js @@ -0,0 +1,160 @@ +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + var NUM_WIDTH_PTS = 32; + var NUM_HEIGHT_PTS = 32; + + var message = document.getElementById("message"); + var canvas = document.getElementById("canvas"); + var context = createWebGLContext(canvas, message); + if (!context) { + return; + } + + /////////////////////////////////////////////////////////////////////////// + + context.viewport(0, 0, canvas.width, canvas.height); + context.clearColor(1.0, 1.0, 1.0, 1.0); + context.enable(context.GL_DEPTH_TEST); + + var persp = mat4.create(); + mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); + + var eye = [2.0, 1.0, 3.0]; + var center = [0.0, 0.0, 0.0]; + var up = [0.0, 0.0, 1.0]; + var view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + var positionLocation = 0; + var heightLocation = 1; + var u_modelViewPerspectiveLocation; + //var u_time; + //var delta=0.0; + + (function initializeShader() { + var program; + var vs = getShaderSource(document.getElementById("vs")); + var fs = getShaderSource(document.getElementById("fs")); + + var program = createProgram(context, vs, fs, message); + context.bindAttribLocation(program, positionLocation, "position"); + u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + // utime=context.getUniformLocation(program,"u_time"); + + context.useProgram(program); + })(); + + var heights; + var numberOfIndices; + + (function initializeGrid() { + function uploadMesh(positions, heights, indices) { + // Positions + var positionsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, positionsName); + context.bufferData(context.ARRAY_BUFFER, positions, context.STATIC_DRAW); + context.vertexAttribPointer(positionLocation, 2, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(positionLocation); + + if (heights) + { + // Heights + var heightsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, heightsName); + context.bufferData(context.ARRAY_BUFFER, heights.length * heights.BYTES_PER_ELEMENT, context.STREAM_DRAW); + context.vertexAttribPointer(heightLocation, 1, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(heightLocation); + } + + // Indices + var indicesName = context.createBuffer(); + context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indicesName); + context.bufferData(context.ELEMENT_ARRAY_BUFFER, indices, context.STATIC_DRAW); + } + + var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; + var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; + + var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; + + var positions = new Float32Array(2 * numberOfPositions); + var indices = new Uint16Array(2 * ((NUM_HEIGHT_PTS * (NUM_WIDTH_PTS - 1)) + (NUM_WIDTH_PTS * (NUM_HEIGHT_PTS - 1)))); + + var positionsIndex = 0; + var indicesIndex = 0; + var length; + + for (var j = 0; j < NUM_WIDTH_PTS; ++j) + { + positions[positionsIndex++] = j /(NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = 0.0; + + if (j>=1) + { + length = positionsIndex / 2; + indices[indicesIndex++] = length - 2; + indices[indicesIndex++] = length - 1; + } + } + + for (var i = 0; i < HEIGHT_DIVISIONS; ++i) + { + var v = (i + 1) / (NUM_HEIGHT_PTS - 1); + positions[positionsIndex++] = 0.0; + positions[positionsIndex++] = v; + + length = (positionsIndex / 2); + indices[indicesIndex++] = length - 1; + indices[indicesIndex++] = length - 1 - NUM_WIDTH_PTS; + + for (var k = 0; k < WIDTH_DIVISIONS; ++k) + { + positions[positionsIndex++] = (k + 1) / (NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = v; + + length = positionsIndex / 2; + var new_pt = length - 1; + indices[indicesIndex++] = new_pt - 1; // Previous side + indices[indicesIndex++] = new_pt; + + indices[indicesIndex++] = new_pt - NUM_WIDTH_PTS; // Previous bottom + indices[indicesIndex++] = new_pt; + } + } + + uploadMesh(positions, heights, indices); + numberOfIndices = indices.length; + })(); + + + (function animate(){ + /////////////////////////////////////////////////////////////////////////// + // Update + + var model = mat4.create(); + mat4.identity(model); + mat4.translate(model, [-0.5, -0.5, 0.0]); + var mv = mat4.create(); + mat4.multiply(view, model, mv); + var mvp = mat4.create(); + mat4.multiply(persp, mv, mvp); + //delta += 0.0009; + // context.uniform1f(u_time, delta); + + + + + /////////////////////////////////////////////////////////////////////////// + // Render + context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); + + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); + + window.requestAnimFrame(animate); + })(); + +}()); diff --git a/part2/Simplex/noise3D.js b/part2/Simplex/noise3D.js new file mode 100644 index 0000000..2d4ffd2 --- /dev/null +++ b/part2/Simplex/noise3D.js @@ -0,0 +1,316 @@ +(function(exports) { + "use strict"; + /*global window,vec3*/ + + exports = exports || window; + + function step(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0 + ]; + } + + function step_vec4(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0, + (x[3] < edge[3]) ? 0.0 : 1.0 + ]; + } + + function min(x, y) { + return [ + y[0] < x[0] ? y[0] : x[0], + y[1] < x[1] ? y[1] : x[1], + y[2] < x[2] ? y[2] : x[2] + ]; + } + + function max(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2] + ]; + } + + function max_vec4(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2], + y[3] > x[3] ? y[3] : x[3] + ]; + } + + function vec4_dot(left, right) { + return left[0] * right[0] + + left[1] * right[1] + + left[2] * right[2] + + left[3] * right[3]; + } + + // + // Description : Array and textureless GLSL 2D/3D/4D simplex + // noise functions. + // Author : Ian McEwan, Ashima Arts. + // Maintainer : ijm + // Lastmod : 20110822 (ijm) + // License : Copyright (C) 2011 Ashima Arts. All rights reserved. + // Distributed under the MIT License. See LICENSE file. + // https://github.com/ashima/webgl-noise + // + function mod289_vec3(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0 + ]; + } + + function mod289_vec4(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0, + x[3] - Math.floor(x[3] * temp) * 289.0 + ]; + } + + function permute_vec4(x) { + return mod289_vec4([ + ((x[0]*34.0)+1.0)*x[0], + ((x[1]*34.0)+1.0)*x[1], + ((x[2]*34.0)+1.0)*x[2], + ((x[3]*34.0)+1.0)*x[3] + ]); + } + + function taylorInvSqrt_vec4(r) { + return [ + 1.79284291400159 - 0.85373472095314 * r[0], + 1.79284291400159 - 0.85373472095314 * r[1], + 1.79284291400159 - 0.85373472095314 * r[2], + 1.79284291400159 - 0.85373472095314 * r[3] + ]; + } + + exports.snoise = function(v) { + // const vec2 C = vec2(1.0f/6.0f, 1.0f/3.0f) ; + // const vec4 D = vec4(0.0f, 0.5f, 1.0f, 2.0f); + var C = [1.0/6.0, 1.0/3.0]; + var D = [0.0, 0.5, 1.0, 2.0]; + + // vec3 i = floor(v + dot(v, vec3(C.y, C.y, C.y)) ); + // vec3 x0 = v - i + dot(i, vec3(C.x, C.x, C.x) ); + var temp0 = vec3.create(); + var temp3 = vec3.dot(v, [C[1], C[1], C[1]]); + vec3.add(v, [temp3, temp3, temp3], temp0); + var i = [Math.floor(temp0[0]), Math.floor(temp0[1]), Math.floor(temp0[2])]; + var temp1 = vec3.create(); + vec3.subtract(v, i, temp1); + var temp2 = vec3.dot(i, [C[0], C[0], C[0]]); + var x0 = vec3.create(); + vec3.add(temp1, [temp2, temp2, temp2], x0); + + // vec3 g = step(vec3(x0.y, x0.z, x0.x), vec3(x0.x, x0.y, x0.z)); + // vec3 l = 1.0f - g; + // vec3 i1 = min( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + // vec3 i2 = max( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + var g = step([x0[1], x0[2], x0[0]], [x0[0], x0[1], x0[2]]); + var l = [1.0 - g[0], 1.0 - g[1], 1.0 - g[2]]; + var i1 = min([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + var i2 = max([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + + // vec3 x1 = x0 - i1 + vec3(C.x, C.x, C.x); + // vec3 x2 = x0 - i2 + vec3(C.y, C.y, C.y); // 2.0*C.x = 1/3 = C.y + // vec3 x3 = x0 - vec3(D.y, D.y, D.y); // -1.0+3.0*C.x = -0.5 = -D.y + var temp4 = vec3.create(); + vec3.subtract(x0, i1, temp4); + var x1 = vec3.create(); + vec3.add(temp4, [C[0], C[0], C[0]], x1); + var temp5 = vec3.create(); + vec3.subtract(x0, i2, temp5); + var x2 = vec3.create(); + vec3.add(temp5, [C[1], C[1], C[1]], x2); + var x3 = vec3.create(); + vec3.subtract(x0, [D[1], D[1], D[1]], x3); + + // i = mod289(i); + // vec4 p = permute( permute( permute( + // i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + // + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + // + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + i = mod289_vec3(i); + var p = permute_vec4([i[2] + 0.0, i[2] + i1[2], i[2] + i2[2], i[2] + 1.0]); + p[0] += i[1] + 0.0; + p[1] += i[1] + i1[1]; + p[2] += i[1] + i2[1]; + p[3] += i[1] + 1.0; + p = permute_vec4(p); + p[0] += i[0] + 0.0; + p[1] += i[0] + i1[0]; + p[2] += i[0] + i2[0]; + p[3] += i[0] + 1.0; + p = permute_vec4(p); + + // float n_ = 0.142857142857f; // 1.0/7.0 + // vec3 ns = n_ * vec3(D.w, D.y, D.z) - vec3(D.x, D.z, D.x); +// var n_ = 0.142857142857; // 1.0/7.0 +// var ns = [ +// n_ * D[3] - D[0], +// n_ * D[1] - D[2], +// n_ * D[2] - D[0] +// ]; + var ns = [ + 0.28571430, + -0.92857140, + 0.14285715 + ]; + + // vec4 j = p - 49.0f * floor(p * ns.z * ns.z); // mod(p,7*7) + var j = [ + p[0] - 49.0 * Math.floor(p[0] * ns[2] * ns[2]), + p[1] - 49.0 * Math.floor(p[1] * ns[2] * ns[2]), + p[2] - 49.0 * Math.floor(p[2] * ns[2] * ns[2]), + p[3] - 49.0 * Math.floor(p[3] * ns[2] * ns[2]) + ]; + + // vec4 x_ = floor(j * ns.z); + // vec4 y_ = floor(j - 7.0f * x_ ); // mod(j,N) + var x_ = [ + Math.floor(j[0] * ns[2]), + Math.floor(j[1] * ns[2]), + Math.floor(j[2] * ns[2]), + Math.floor(j[3] * ns[2]) + ]; + var y_ = [ + Math.floor(j[0] - 7.0 * x_[0] ), + Math.floor(j[1] - 7.0 * x_[1] ), + Math.floor(j[2] - 7.0 * x_[2] ), + Math.floor(j[3] - 7.0 * x_[3] ) + ]; + + // vec4 x = x_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 y = y_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 h = 1.0f - abs(x) - abs(y); + var x = [ + x_[0] *ns[0] + ns[1], + x_[1] *ns[0] + ns[1], + x_[2] *ns[0] + ns[1], + x_[3] *ns[0] + ns[1] + ]; + var y = [ + y_[0] *ns[0] + ns[1], + y_[1] *ns[0] + ns[1], + y_[2] *ns[0] + ns[1], + y_[3] *ns[0] + ns[1] + ]; + var h = [ + 1.0 - Math.abs(x[0]) - Math.abs(y[0]), + 1.0 - Math.abs(x[1]) - Math.abs(y[1]), + 1.0 - Math.abs(x[2]) - Math.abs(y[2]), + 1.0 - Math.abs(x[3]) - Math.abs(y[3]) + ]; + + // vec4 b0 = vec4( vec2(x.x, x.y), vec2(y.x, y.y) ); + // vec4 b1 = vec4( vec2(x.z, x.w), vec2(y.z, y.w) ); + var b0 = [x[0], x[1], y[0], y[1]]; + var b1 = [x[2], x[3], y[2], y[3]]; + + // vec4 s0 = floor(b0)*2.0f + 1.0f; + // vec4 s1 = floor(b1)*2.0f + 1.0f; + // vec4 sh = -step(h, vec4(0.0)); + + var s0 = [ + Math.floor(b0[0])*2.0 + 1.0, + Math.floor(b0[1])*2.0 + 1.0, + Math.floor(b0[2])*2.0 + 1.0, + Math.floor(b0[3])*2.0 + 1.0 + ]; + var s1 = [ + Math.floor(b1[0])*2.0 + 1.0, + Math.floor(b1[1])*2.0 + 1.0, + Math.floor(b1[2])*2.0 + 1.0, + Math.floor(b1[3])*2.0 + 1.0 + ]; + var sh = step_vec4(h, [0.0, 0.0, 0.0, 0.0]); + sh[0] = -sh[0]; + sh[1] = -sh[1]; + sh[2] = -sh[2]; + sh[3] = -sh[3]; + + // vec4 a0 = vec4(b0.x, b0.z, b0.y, b0.w) + vec4(s0.x, s0.z, s0.y, s0.w) * vec4(sh.x, sh.x, sh.y, sh.y) ; + // vec4 a1 = vec4(b1.x, b1.z, b1.y, b1.w) + vec4(s1.x, s1.z, s1.y, s1.w) * vec4(sh.z, sh.z, sh.w, sh.w) ; + var a0 = [ + b0[0] + s0[0] * sh[0], + b0[2] + s0[2] * sh[0], + b0[1] + s0[1] * sh[1], + b0[3] + s0[3] * sh[1] + ]; + var a1 = [ + b1[0] + s1[0] * sh[2], + b1[2] + s1[2] * sh[2], + b1[1] + s1[1] * sh[3], + b1[3] + s1[3] * sh[3] + ]; + + // vec3 p0 = vec3(a0.x, a0.y, h.x); + // vec3 p1 = vec3(a0.z, a0.w, h.y); + // vec3 p2 = vec3(a1.x, a1.y, h.z); + // vec3 p3 = vec3(a1.z, a1.w, h.w); + var p0 = [a0[0], a0[1], h[0]]; + var p1 = [a0[2], a0[3], h[1]]; + var p2 = [a1[0], a1[1], h[2]]; + var p3 = [a1[2], a1[3], h[3]]; + + // vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + // p0 *= norm.x; + // p1 *= norm.y; + // p2 *= norm.z; + // p3 *= norm.w; + var norm = taylorInvSqrt_vec4([vec3.dot(p0,p0), vec3.dot(p1,p1), vec3.dot(p2, p2), vec3.dot(p3,p3)]); + p0 = [p0[0]*norm[0], p0[1]*norm[0], p0[2]*norm[0]]; + p1 = [p1[0]*norm[1], p1[1]*norm[1], p1[2]*norm[1]]; + p2 = [p2[0]*norm[2], p2[1]*norm[2], p2[2]*norm[2]]; + p3 = [p3[0]*norm[3], p3[1]*norm[3], p3[2]*norm[3]]; + + // vec4 m = max(0.6f - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + // m = m * m; + var m = max_vec4([ + 0.6 - vec3.dot(x0,x0), + 0.6 - vec3.dot(x1,x1), + 0.6 - vec3.dot(x2,x2), + 0.6 - vec3.dot(x3,x3) + ], [ + 0.0, + 0.0, + 0.0, + 0.0 + ]); + m[0] *= m[0]; + m[1] *= m[1]; + m[2] *= m[2]; + m[3] *= m[3]; + + // return 42.0f * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + // dot(p2,x2), dot(p3,x3) ) ); + return 42.0 * vec4_dot([ + m[0] * m[0], + m[1] * m[1], + m[2] * m[2], + m[3] * m[3] + ], [ + vec3.dot(p0,x0), + vec3.dot(p1,x1), + vec3.dot(p2,x2), + vec3.dot(p3,x3) + ]); + }; + +}()); diff --git a/part2/Simplex/simplex.vert b/part2/Simplex/simplex.vert new file mode 100644 index 0000000..e1ff07a --- /dev/null +++ b/part2/Simplex/simplex.vert @@ -0,0 +1,39 @@ +vec3 permute(vec3 x) { + x = ((x*34.0)+1.0)*x; + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +float simplexNoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = i - floor(i * (1.0 / 289.0)) * 289.0; + + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= inversesqrt( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} \ No newline at end of file diff --git a/part2/Simplex/webGLUtility.js b/part2/Simplex/webGLUtility.js new file mode 100644 index 0000000..c9de391 --- /dev/null +++ b/part2/Simplex/webGLUtility.js @@ -0,0 +1,97 @@ +(function(exports) { + "use strict"; + /*global window*/ + + exports = exports || window; + + /////////////////////////////////////////////////////////////////////////// + // Shim from http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + + exports.requestAnimFrame = + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function( callback ){ + window.setTimeout(callback, 1000 / 60); + }; + + /////////////////////////////////////////////////////////////////////////// + // getShader based on http://learningwebgl.com/cookbook/index.php/Loading_shaders_from_HTML_script_tags + + exports.getShaderSource = function(script) { + var str = ""; + var k = script.firstChild; + while (k) { + if (k.nodeType == 3) { + str += k.textContent; + } + k = k.nextSibling; + } + + return str; + }; + + /////////////////////////////////////////////////////////////////////////// + + exports.createWebGLContext = function(canvas, message) { + if (!window.WebGLRenderingContext) { + message.innerText = "The browser does not support WebGL. Visit http://get.webgl.org."; + return undefined; + } + + var context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + + if (!context && message) { + message.innerText = "The browser supports WebGL, but initialization failed."; + } + + return context; + }; + + exports.createProgram = function(context, vertexShaderSource, fragmentShaderSource, message) { + var program = context.createProgram(); + var vs = context.createShader(context.VERTEX_SHADER); + var fs = context.createShader(context.FRAGMENT_SHADER); + + context.attachShader(program, vs); + context.attachShader(program, fs); + + // Mark shader for deletion when the program is deleted + context.deleteShader(vs); + context.deleteShader(fs); + + context.shaderSource(vs, vertexShaderSource); + context.compileShader(vs); + if (!context.getShaderParameter(vs, context.COMPILE_STATUS)) { + if (message) { + message.innerText += context.getShaderInfoLog(vs) + "\n"; + } + context.deleteProgram(program); + return; + } + + context.shaderSource(fs, fragmentShaderSource); + context.compileShader(fs); + if (!context.getShaderParameter(fs, context.COMPILE_STATUS)) { + if (message) { + message.innerText += context.getShaderInfoLog(fs) + "\n"; + } + context.deleteProgram(program); + return; + } + + context.linkProgram(program); + if (!context.getProgramParameter(program, context.LINK_STATUS)) { + if (message) { + message.innerText += context.getProgramInfoLog(program) + "\n"; + } + context.deleteProgram(program); + return; + } + + return program; + }; + +}()); diff --git a/part2/Sin_COS/gl-matrix.js b/part2/Sin_COS/gl-matrix.js new file mode 100644 index 0000000..2e1bdb9 --- /dev/null +++ b/part2/Sin_COS/gl-matrix.js @@ -0,0 +1,1909 @@ +/** + * @fileOverview gl-matrix - High performance matrix and vector operations for WebGL + * @author Brandon Jones + * @version 1.2.3 + */ + +/* + * Copyright (c) 2011 Brandon Jones + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +"use strict"; + +// Type declarations +(function() { + // account for CommonJS environments + var _global = (typeof(exports) != 'undefined') ? global : window; + _global.glMatrixArrayType = _global.MatrixArray = null; + + /** + * @class 3 Dimensional Vector + * @name vec3 + */ + _global.vec3 = {}; + + /** + * @class 3x3 Matrix + * @name mat3 + */ + _global.mat3 = {}; + + /** + * @class 4x4 Matrix + * @name mat4 + */ + _global.mat4 = {}; + + /** + * @class Quaternion + * @name quat4 + */ + _global.quat4 = {}; + + // explicitly sets and returns the type of array to use within glMatrix + _global.setMatrixArrayType = function(type) { + return glMatrixArrayType = MatrixArray = type; + }; + + // auto-detects and returns the best type of array to use within glMatrix, falling + // back to Array if typed arrays are unsupported + _global.determineMatrixArrayType = function() { + return setMatrixArrayType((typeof Float32Array !== 'undefined') ? Float32Array : Array); + }; + + determineMatrixArrayType(); +})(); + +/* + * vec3 + */ + +/** + * Creates a new instance of a vec3 using the default array type + * Any javascript array-like objects containing at least 3 numeric elements can serve as a vec3 + * + * @param {vec3} [vec] vec3 containing values to initialize with + * + * @returns {vec3} New vec3 + */ +vec3.create = function (vec) { + var dest = new MatrixArray(3); + + if (vec) { + dest[0] = vec[0]; + dest[1] = vec[1]; + dest[2] = vec[2]; + } else { + dest[0] = dest[1] = dest[2] = 0; + } + + return dest; +}; + +/** + * Copies the values of one vec3 to another + * + * @param {vec3} vec vec3 containing values to copy + * @param {vec3} dest vec3 receiving copied values + * + * @returns {vec3} dest + */ +vec3.set = function (vec, dest) { + dest[0] = vec[0]; + dest[1] = vec[1]; + dest[2] = vec[2]; + + return dest; +}; + +/** + * Performs a vector addition + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.add = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] += vec2[0]; + vec[1] += vec2[1]; + vec[2] += vec2[2]; + return vec; + } + + dest[0] = vec[0] + vec2[0]; + dest[1] = vec[1] + vec2[1]; + dest[2] = vec[2] + vec2[2]; + return dest; +}; + +/** + * Performs a vector subtraction + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.subtract = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] -= vec2[0]; + vec[1] -= vec2[1]; + vec[2] -= vec2[2]; + return vec; + } + + dest[0] = vec[0] - vec2[0]; + dest[1] = vec[1] - vec2[1]; + dest[2] = vec[2] - vec2[2]; + return dest; +}; + +/** + * Performs a vector multiplication + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.multiply = function (vec, vec2, dest) { + if (!dest || vec === dest) { + vec[0] *= vec2[0]; + vec[1] *= vec2[1]; + vec[2] *= vec2[2]; + return vec; + } + + dest[0] = vec[0] * vec2[0]; + dest[1] = vec[1] * vec2[1]; + dest[2] = vec[2] * vec2[2]; + return dest; +}; + +/** + * Negates the components of a vec3 + * + * @param {vec3} vec vec3 to negate + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.negate = function (vec, dest) { + if (!dest) { dest = vec; } + + dest[0] = -vec[0]; + dest[1] = -vec[1]; + dest[2] = -vec[2]; + return dest; +}; + +/** + * Multiplies the components of a vec3 by a scalar value + * + * @param {vec3} vec vec3 to scale + * @param {number} val Value to scale by + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.scale = function (vec, val, dest) { + if (!dest || vec === dest) { + vec[0] *= val; + vec[1] *= val; + vec[2] *= val; + return vec; + } + + dest[0] = vec[0] * val; + dest[1] = vec[1] * val; + dest[2] = vec[2] * val; + return dest; +}; + +/** + * Generates a unit vector of the same direction as the provided vec3 + * If vector length is 0, returns [0, 0, 0] + * + * @param {vec3} vec vec3 to normalize + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.normalize = function (vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + len = Math.sqrt(x * x + y * y + z * z); + + if (!len) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + return dest; + } else if (len === 1) { + dest[0] = x; + dest[1] = y; + dest[2] = z; + return dest; + } + + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + return dest; +}; + +/** + * Generates the cross product of two vec3s + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.cross = function (vec, vec2, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + x2 = vec2[0], y2 = vec2[1], z2 = vec2[2]; + + dest[0] = y * z2 - z * y2; + dest[1] = z * x2 - x * z2; + dest[2] = x * y2 - y * x2; + return dest; +}; + +/** + * Caclulates the length of a vec3 + * + * @param {vec3} vec vec3 to calculate length of + * + * @returns {number} Length of vec + */ +vec3.length = function (vec) { + var x = vec[0], y = vec[1], z = vec[2]; + return Math.sqrt(x * x + y * y + z * z); +}; + +/** + * Caclulates the dot product of two vec3s + * + * @param {vec3} vec First operand + * @param {vec3} vec2 Second operand + * + * @returns {number} Dot product of vec and vec2 + */ +vec3.dot = function (vec, vec2) { + return vec[0] * vec2[0] + vec[1] * vec2[1] + vec[2] * vec2[2]; +}; + +/** + * Generates a unit vector pointing from one vector to another + * + * @param {vec3} vec Origin vec3 + * @param {vec3} vec2 vec3 to point to + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.direction = function (vec, vec2, dest) { + if (!dest) { dest = vec; } + + var x = vec[0] - vec2[0], + y = vec[1] - vec2[1], + z = vec[2] - vec2[2], + len = Math.sqrt(x * x + y * y + z * z); + + if (!len) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + return dest; + } + + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + return dest; +}; + +/** + * Performs a linear interpolation between two vec3 + * + * @param {vec3} vec First vector + * @param {vec3} vec2 Second vector + * @param {number} lerp Interpolation amount between the two inputs + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.lerp = function (vec, vec2, lerp, dest) { + if (!dest) { dest = vec; } + + dest[0] = vec[0] + lerp * (vec2[0] - vec[0]); + dest[1] = vec[1] + lerp * (vec2[1] - vec[1]); + dest[2] = vec[2] + lerp * (vec2[2] - vec[2]); + + return dest; +}; + +/** + * Calculates the euclidian distance between two vec3 + * + * Params: + * @param {vec3} vec First vector + * @param {vec3} vec2 Second vector + * + * @returns {number} Distance between vec and vec2 + */ +vec3.dist = function (vec, vec2) { + var x = vec2[0] - vec[0], + y = vec2[1] - vec[1], + z = vec2[2] - vec[2]; + + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Projects the specified vec3 from screen space into object space + * Based on the Mesa gluUnProject implementation + * + * @param {vec3} vec Screen-space vector to project + * @param {mat4} view View matrix + * @param {mat4} proj Projection matrix + * @param {vec4} viewport Viewport as given to gl.viewport [x, y, width, height] + * @param {vec3} [dest] vec3 receiving unprojected result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +vec3.unproject = function (vec, view, proj, viewport, dest) { + if (!dest) { dest = vec; } + + var m = mat4.create(); + var v = new MatrixArray(4); + + v[0] = (vec[0] - viewport[0]) * 2.0 / viewport[2] - 1.0; + v[1] = (vec[1] - viewport[1]) * 2.0 / viewport[3] - 1.0; + v[2] = 2.0 * vec[2] - 1.0; + v[3] = 1.0; + + mat4.multiply(proj, view, m); + if(!mat4.inverse(m)) { return null; } + + mat4.multiplyVec4(m, v); + if(v[3] === 0.0) { return null; } + + dest[0] = v[0] / v[3]; + dest[1] = v[1] / v[3]; + dest[2] = v[2] / v[3]; + + return dest; +}; + +/** + * Returns a string representation of a vector + * + * @param {vec3} vec Vector to represent as a string + * + * @returns {string} String representation of vec + */ +vec3.str = function (vec) { + return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']'; +}; + +/* + * mat3 + */ + +/** + * Creates a new instance of a mat3 using the default array type + * Any javascript array-like object containing at least 9 numeric elements can serve as a mat3 + * + * @param {mat3} [mat] mat3 containing values to initialize with + * + * @returns {mat3} New mat3 + */ +mat3.create = function (mat) { + var dest = new MatrixArray(9); + + if (mat) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + } + + return dest; +}; + +/** + * Copies the values of one mat3 to another + * + * @param {mat3} mat mat3 containing values to copy + * @param {mat3} dest mat3 receiving copied values + * + * @returns {mat3} dest + */ +mat3.set = function (mat, dest) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + return dest; +}; + +/** + * Sets a mat3 to an identity matrix + * + * @param {mat3} dest mat3 to set + * + * @returns dest if specified, otherwise a new mat3 + */ +mat3.identity = function (dest) { + if (!dest) { dest = mat3.create(); } + dest[0] = 1; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 1; + dest[5] = 0; + dest[6] = 0; + dest[7] = 0; + dest[8] = 1; + return dest; +}; + +/** + * Transposes a mat3 (flips the values over the diagonal) + * + * Params: + * @param {mat3} mat mat3 to transpose + * @param {mat3} [dest] mat3 receiving transposed values. If not specified result is written to mat + * + * @returns {mat3} dest is specified, mat otherwise + */ +mat3.transpose = function (mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], + a12 = mat[5]; + + mat[1] = mat[3]; + mat[2] = mat[6]; + mat[3] = a01; + mat[5] = mat[7]; + mat[6] = a02; + mat[7] = a12; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[3]; + dest[2] = mat[6]; + dest[3] = mat[1]; + dest[4] = mat[4]; + dest[5] = mat[7]; + dest[6] = mat[2]; + dest[7] = mat[5]; + dest[8] = mat[8]; + return dest; +}; + +/** + * Copies the elements of a mat3 into the upper 3x3 elements of a mat4 + * + * @param {mat3} mat mat3 containing values to copy + * @param {mat4} [dest] mat4 receiving copied values + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat3.toMat4 = function (mat, dest) { + if (!dest) { dest = mat4.create(); } + + dest[15] = 1; + dest[14] = 0; + dest[13] = 0; + dest[12] = 0; + + dest[11] = 0; + dest[10] = mat[8]; + dest[9] = mat[7]; + dest[8] = mat[6]; + + dest[7] = 0; + dest[6] = mat[5]; + dest[5] = mat[4]; + dest[4] = mat[3]; + + dest[3] = 0; + dest[2] = mat[2]; + dest[1] = mat[1]; + dest[0] = mat[0]; + + return dest; +}; + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat mat3 to represent as a string + * + * @param {string} String representation of mat + */ +mat3.str = function (mat) { + return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + + ', ' + mat[3] + ', ' + mat[4] + ', ' + mat[5] + + ', ' + mat[6] + ', ' + mat[7] + ', ' + mat[8] + ']'; +}; + +/* + * mat4 + */ + +/** + * Creates a new instance of a mat4 using the default array type + * Any javascript array-like object containing at least 16 numeric elements can serve as a mat4 + * + * @param {mat4} [mat] mat4 containing values to initialize with + * + * @returns {mat4} New mat4 + */ +mat4.create = function (mat) { + var dest = new MatrixArray(16); + + if (mat) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + return dest; +}; + +/** + * Copies the values of one mat4 to another + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat4} dest mat4 receiving copied values + * + * @returns {mat4} dest + */ +mat4.set = function (mat, dest) { + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Sets a mat4 to an identity matrix + * + * @param {mat4} dest mat4 to set + * + * @returns {mat4} dest + */ +mat4.identity = function (dest) { + if (!dest) { dest = mat4.create(); } + dest[0] = 1; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = 1; + dest[6] = 0; + dest[7] = 0; + dest[8] = 0; + dest[9] = 0; + dest[10] = 1; + dest[11] = 0; + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + return dest; +}; + +/** + * Transposes a mat4 (flips the values over the diagonal) + * + * @param {mat4} mat mat4 to transpose + * @param {mat4} [dest] mat4 receiving transposed values. If not specified result is written to mat + * + * @param {mat4} dest is specified, mat otherwise + */ +mat4.transpose = function (mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (!dest || mat === dest) { + var a01 = mat[1], a02 = mat[2], a03 = mat[3], + a12 = mat[6], a13 = mat[7], + a23 = mat[11]; + + mat[1] = mat[4]; + mat[2] = mat[8]; + mat[3] = mat[12]; + mat[4] = a01; + mat[6] = mat[9]; + mat[7] = mat[13]; + mat[8] = a02; + mat[9] = a12; + mat[11] = mat[14]; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = mat[4]; + dest[2] = mat[8]; + dest[3] = mat[12]; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = mat[9]; + dest[7] = mat[13]; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = mat[14]; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} mat mat4 to calculate determinant of + * + * @returns {number} determinant of mat + */ +mat4.determinant = function (mat) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + return (a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + + a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + + a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + + a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + + a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + + a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33); +}; + +/** + * Calculates the inverse matrix of a mat4 + * + * @param {mat4} mat mat4 to calculate inverse of + * @param {mat4} [dest] mat4 receiving inverse matrix. If not specified result is written to mat + * + * @param {mat4} dest is specified, mat otherwise, null if matrix cannot be inverted + */ +mat4.inverse = function (mat, dest) { + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06), + invDet; + + // Calculate the determinant + if (!d) { return null; } + invDet = 1 / d; + + dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; + dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; + dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; + dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; + dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; + dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; + dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; + dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; + dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; + dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; + dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; + dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; + dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; + dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; + dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; + dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; + + return dest; +}; + +/** + * Copies the upper 3x3 elements of a mat4 into another mat4 + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat4} [dest] mat4 receiving copied values + * + * @returns {mat4} dest is specified, a new mat4 otherwise + */ +mat4.toRotationMat = function (mat, dest) { + if (!dest) { dest = mat4.create(); } + + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + + return dest; +}; + +/** + * Copies the upper 3x3 elements of a mat4 into a mat3 + * + * @param {mat4} mat mat4 containing values to copy + * @param {mat3} [dest] mat3 receiving copied values + * + * @returns {mat3} dest is specified, a new mat3 otherwise + */ +mat4.toMat3 = function (mat, dest) { + if (!dest) { dest = mat3.create(); } + + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[4]; + dest[4] = mat[5]; + dest[5] = mat[6]; + dest[6] = mat[8]; + dest[7] = mat[9]; + dest[8] = mat[10]; + + return dest; +}; + +/** + * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3 + * The resulting matrix is useful for calculating transformed normals + * + * Params: + * @param {mat4} mat mat4 containing values to invert and copy + * @param {mat3} [dest] mat3 receiving values + * + * @returns {mat3} dest is specified, a new mat3 otherwise, null if the matrix cannot be inverted + */ +mat4.toInverseMat3 = function (mat, dest) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], + a10 = mat[4], a11 = mat[5], a12 = mat[6], + a20 = mat[8], a21 = mat[9], a22 = mat[10], + + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, + + d = a00 * b01 + a01 * b11 + a02 * b21, + id; + + if (!d) { return null; } + id = 1 / d; + + if (!dest) { dest = mat3.create(); } + + dest[0] = b01 * id; + dest[1] = (-a22 * a01 + a02 * a21) * id; + dest[2] = (a12 * a01 - a02 * a11) * id; + dest[3] = b11 * id; + dest[4] = (a22 * a00 - a02 * a20) * id; + dest[5] = (-a12 * a00 + a02 * a10) * id; + dest[6] = b21 * id; + dest[7] = (-a21 * a00 + a01 * a20) * id; + dest[8] = (a11 * a00 - a01 * a10) * id; + + return dest; +}; + +/** + * Performs a matrix multiplication + * + * @param {mat4} mat First operand + * @param {mat4} mat2 Second operand + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.multiply = function (mat, mat2, dest) { + if (!dest) { dest = mat; } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3], + a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7], + a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11], + a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15], + + b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3], + b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7], + b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11], + b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; + + return dest; +}; + +/** + * Transforms a vec3 with the given matrix + * 4th vector component is implicitly '1' + * + * @param {mat4} mat mat4 to transform the vector with + * @param {vec3} vec vec3 to transform + * @paran {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns {vec3} dest if specified, vec otherwise + */ +mat4.multiplyVec3 = function (mat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2]; + + dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + + return dest; +}; + +/** + * Transforms a vec4 with the given matrix + * + * @param {mat4} mat mat4 to transform the vector with + * @param {vec4} vec vec4 to transform + * @param {vec4} [dest] vec4 receiving operation result. If not specified result is written to vec + * + * @returns {vec4} dest if specified, vec otherwise + */ +mat4.multiplyVec4 = function (mat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; + + dest[0] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12] * w; + dest[1] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13] * w; + dest[2] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14] * w; + dest[3] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15] * w; + + return dest; +}; + +/** + * Translates a matrix by the given vector + * + * @param {mat4} mat mat4 to translate + * @param {vec3} vec vec3 specifying the translation + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.translate = function (mat, vec, dest) { + var x = vec[0], y = vec[1], z = vec[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; + + if (!dest || mat === dest) { + mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15]; + return mat; + } + + a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; + a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; + a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; + + dest[0] = a00; dest[1] = a01; dest[2] = a02; dest[3] = a03; + dest[4] = a10; dest[5] = a11; dest[6] = a12; dest[7] = a13; + dest[8] = a20; dest[9] = a21; dest[10] = a22; dest[11] = a23; + + dest[12] = a00 * x + a10 * y + a20 * z + mat[12]; + dest[13] = a01 * x + a11 * y + a21 * z + mat[13]; + dest[14] = a02 * x + a12 * y + a22 * z + mat[14]; + dest[15] = a03 * x + a13 * y + a23 * z + mat[15]; + return dest; +}; + +/** + * Scales a matrix by the given vector + * + * @param {mat4} mat mat4 to scale + * @param {vec3} vec vec3 specifying the scale for each axis + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @param {mat4} dest if specified, mat otherwise + */ +mat4.scale = function (mat, vec, dest) { + var x = vec[0], y = vec[1], z = vec[2]; + + if (!dest || mat === dest) { + mat[0] *= x; + mat[1] *= x; + mat[2] *= x; + mat[3] *= x; + mat[4] *= y; + mat[5] *= y; + mat[6] *= y; + mat[7] *= y; + mat[8] *= z; + mat[9] *= z; + mat[10] *= z; + mat[11] *= z; + return mat; + } + + dest[0] = mat[0] * x; + dest[1] = mat[1] * x; + dest[2] = mat[2] * x; + dest[3] = mat[3] * x; + dest[4] = mat[4] * y; + dest[5] = mat[5] * y; + dest[6] = mat[6] * y; + dest[7] = mat[7] * y; + dest[8] = mat[8] * z; + dest[9] = mat[9] * z; + dest[10] = mat[10] * z; + dest[11] = mat[11] * z; + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the specified axis + * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {vec3} axis vec3 representing the axis to rotate around + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotate = function (mat, angle, axis, dest) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; + + if (!len) { return null; } + if (len !== 1) { + len = 1 / len; + x *= len; + y *= len; + z *= len; + } + + s = Math.sin(angle); + c = Math.cos(angle); + t = 1 - c; + + a00 = mat[0]; a01 = mat[1]; a02 = mat[2]; a03 = mat[3]; + a10 = mat[4]; a11 = mat[5]; a12 = mat[6]; a13 = mat[7]; + a20 = mat[8]; a21 = mat[9]; a22 = mat[10]; a23 = mat[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform rotation-specific matrix multiplication + dest[0] = a00 * b00 + a10 * b01 + a20 * b02; + dest[1] = a01 * b00 + a11 * b01 + a21 * b02; + dest[2] = a02 * b00 + a12 * b01 + a22 * b02; + dest[3] = a03 * b00 + a13 * b01 + a23 * b02; + + dest[4] = a00 * b10 + a10 * b11 + a20 * b12; + dest[5] = a01 * b10 + a11 * b11 + a21 * b12; + dest[6] = a02 * b10 + a12 * b11 + a22 * b12; + dest[7] = a03 * b10 + a13 * b11 + a23 * b12; + + dest[8] = a00 * b20 + a10 * b21 + a20 * b22; + dest[9] = a01 * b20 + a11 * b21 + a21 * b22; + dest[10] = a02 * b20 + a12 * b21 + a22 * b22; + dest[11] = a03 * b20 + a13 * b21 + a23 * b22; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateX = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a10 = mat[4], + a11 = mat[5], + a12 = mat[6], + a13 = mat[7], + a20 = mat[8], + a21 = mat[9], + a22 = mat[10], + a23 = mat[11]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows + dest[0] = mat[0]; + dest[1] = mat[1]; + dest[2] = mat[2]; + dest[3] = mat[3]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[4] = a10 * c + a20 * s; + dest[5] = a11 * c + a21 * s; + dest[6] = a12 * c + a22 * s; + dest[7] = a13 * c + a23 * s; + + dest[8] = a10 * -s + a20 * c; + dest[9] = a11 * -s + a21 * c; + dest[10] = a12 * -s + a22 * c; + dest[11] = a13 * -s + a23 * c; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateY = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a00 = mat[0], + a01 = mat[1], + a02 = mat[2], + a03 = mat[3], + a20 = mat[8], + a21 = mat[9], + a22 = mat[10], + a23 = mat[11]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged rows + dest[4] = mat[4]; + dest[5] = mat[5]; + dest[6] = mat[6]; + dest[7] = mat[7]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[0] = a00 * c + a20 * -s; + dest[1] = a01 * c + a21 * -s; + dest[2] = a02 * c + a22 * -s; + dest[3] = a03 * c + a23 * -s; + + dest[8] = a00 * s + a20 * c; + dest[9] = a01 * s + a21 * c; + dest[10] = a02 * s + a22 * c; + dest[11] = a03 * s + a23 * c; + return dest; +}; + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} mat mat4 to rotate + * @param {number} angle Angle (in radians) to rotate + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to mat + * + * @returns {mat4} dest if specified, mat otherwise + */ +mat4.rotateZ = function (mat, angle, dest) { + var s = Math.sin(angle), + c = Math.cos(angle), + a00 = mat[0], + a01 = mat[1], + a02 = mat[2], + a03 = mat[3], + a10 = mat[4], + a11 = mat[5], + a12 = mat[6], + a13 = mat[7]; + + if (!dest) { + dest = mat; + } else if (mat !== dest) { // If the source and destination differ, copy the unchanged last row + dest[8] = mat[8]; + dest[9] = mat[9]; + dest[10] = mat[10]; + dest[11] = mat[11]; + + dest[12] = mat[12]; + dest[13] = mat[13]; + dest[14] = mat[14]; + dest[15] = mat[15]; + } + + // Perform axis-specific matrix multiplication + dest[0] = a00 * c + a10 * s; + dest[1] = a01 * c + a11 * s; + dest[2] = a02 * c + a12 * s; + dest[3] = a03 * c + a13 * s; + + dest[4] = a00 * -s + a10 * c; + dest[5] = a01 * -s + a11 * c; + dest[6] = a02 * -s + a12 * c; + dest[7] = a03 * -s + a13 * c; + + return dest; +}; + +/** + * Generates a frustum matrix with the given bounds + * + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.frustum = function (left, right, bottom, top, near, far, dest) { + if (!dest) { dest = mat4.create(); } + var rl = (right - left), + tb = (top - bottom), + fn = (far - near); + dest[0] = (near * 2) / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = (near * 2) / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = (right + left) / rl; + dest[9] = (top + bottom) / tb; + dest[10] = -(far + near) / fn; + dest[11] = -1; + dest[12] = 0; + dest[13] = 0; + dest[14] = -(far * near * 2) / fn; + dest[15] = 0; + return dest; +}; + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {number} fovy Vertical field of view + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.perspective = function (fovy, aspect, near, far, dest) { + var top = near * Math.tan(fovy * Math.PI / 360.0), + right = top * aspect; + return mat4.frustum(-right, right, -top, top, near, far, dest); +}; + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.ortho = function (left, right, bottom, top, near, far, dest) { + if (!dest) { dest = mat4.create(); } + var rl = (right - left), + tb = (top - bottom), + fn = (far - near); + dest[0] = 2 / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = 2 / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = 0; + dest[9] = 0; + dest[10] = -2 / fn; + dest[11] = 0; + dest[12] = -(left + right) / rl; + dest[13] = -(top + bottom) / tb; + dest[14] = -(far + near) / fn; + dest[15] = 1; + return dest; +}; + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing "up" + * @param {mat4} [dest] mat4 frustum matrix will be written into + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.lookAt = function (eye, center, up, dest) { + if (!dest) { dest = mat4.create(); } + + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; + + if (eyex === centerx && eyey === centery && eyez === centerz) { + return mat4.identity(dest); + } + + //vec3.direction(eye, center, z); + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + // normalize (no check needed for 0 because of early return) + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + //vec3.normalize(vec3.cross(up, z, x)); + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + //vec3.normalize(vec3.cross(z, x, y)); + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + dest[0] = x0; + dest[1] = y0; + dest[2] = z0; + dest[3] = 0; + dest[4] = x1; + dest[5] = y1; + dest[6] = z1; + dest[7] = 0; + dest[8] = x2; + dest[9] = y2; + dest[10] = z2; + dest[11] = 0; + dest[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + dest[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + dest[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + dest[15] = 1; + + return dest; +}; + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {quat4} quat Rotation quaternion + * @param {vec3} vec Translation vector + * @param {mat4} [dest] mat4 receiving operation result. If not specified result is written to a new mat4 + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +mat4.fromRotationTranslation = function (quat, vec, dest) { + if (!dest) { dest = mat4.create(); } + + // Quaternion math + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + dest[3] = 0; + dest[4] = xy - wz; + dest[5] = 1 - (xx + zz); + dest[6] = yz + wx; + dest[7] = 0; + dest[8] = xz + wy; + dest[9] = yz - wx; + dest[10] = 1 - (xx + yy); + dest[11] = 0; + dest[12] = vec[0]; + dest[13] = vec[1]; + dest[14] = vec[2]; + dest[15] = 1; + + return dest; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat mat4 to represent as a string + * + * @returns {string} String representation of mat + */ +mat4.str = function (mat) { + return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] + + ', ' + mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] + + ', ' + mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] + + ', ' + mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']'; +}; + +/* + * quat4 + */ + +/** + * Creates a new instance of a quat4 using the default array type + * Any javascript array containing at least 4 numeric elements can serve as a quat4 + * + * @param {quat4} [quat] quat4 containing values to initialize with + * + * @returns {quat4} New quat4 + */ +quat4.create = function (quat) { + var dest = new MatrixArray(4); + + if (quat) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + } + + return dest; +}; + +/** + * Copies the values of one quat4 to another + * + * @param {quat4} quat quat4 containing values to copy + * @param {quat4} dest quat4 receiving copied values + * + * @returns {quat4} dest + */ +quat4.set = function (quat, dest) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + + return dest; +}; + +/** + * Calculates the W component of a quat4 from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat4} quat quat4 to calculate W component of + * @param {quat4} [dest] quat4 receiving calculated values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.calculateW = function (quat, dest) { + var x = quat[0], y = quat[1], z = quat[2]; + + if (!dest || quat === dest) { + quat[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return quat; + } + dest[0] = x; + dest[1] = y; + dest[2] = z; + dest[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return dest; +}; + +/** + * Calculates the dot product of two quaternions + * + * @param {quat4} quat First operand + * @param {quat4} quat2 Second operand + * + * @return {number} Dot product of quat and quat2 + */ +quat4.dot = function(quat, quat2){ + return quat[0]*quat2[0] + quat[1]*quat2[1] + quat[2]*quat2[2] + quat[3]*quat2[3]; +}; + +/** + * Calculates the inverse of a quat4 + * + * @param {quat4} quat quat4 to calculate inverse of + * @param {quat4} [dest] quat4 receiving inverse values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.inverse = function(quat, dest) { + var q0 = quat[0], q1 = quat[1], q2 = quat[2], q3 = quat[3], + dot = q0*q0 + q1*q1 + q2*q2 + q3*q3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + if(!dest || quat === dest) { + quat[0] *= -invDot; + quat[1] *= -invDot; + quat[2] *= -invDot; + quat[3] *= invDot; + return quat; + } + dest[0] = -quat[0]*invDot; + dest[1] = -quat[1]*invDot; + dest[2] = -quat[2]*invDot; + dest[3] = quat[3]*invDot; + return dest; +}; + + +/** + * Calculates the conjugate of a quat4 + * If the quaternion is normalized, this function is faster than quat4.inverse and produces the same result. + * + * @param {quat4} quat quat4 to calculate conjugate of + * @param {quat4} [dest] quat4 receiving conjugate values. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.conjugate = function (quat, dest) { + if (!dest || quat === dest) { + quat[0] *= -1; + quat[1] *= -1; + quat[2] *= -1; + return quat; + } + dest[0] = -quat[0]; + dest[1] = -quat[1]; + dest[2] = -quat[2]; + dest[3] = quat[3]; + return dest; +}; + +/** + * Calculates the length of a quat4 + * + * Params: + * @param {quat4} quat quat4 to calculate length of + * + * @returns Length of quat + */ +quat4.length = function (quat) { + var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; + return Math.sqrt(x * x + y * y + z * z + w * w); +}; + +/** + * Generates a unit quaternion of the same direction as the provided quat4 + * If quaternion length is 0, returns [0, 0, 0, 0] + * + * @param {quat4} quat quat4 to normalize + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.normalize = function (quat, dest) { + if (!dest) { dest = quat; } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + len = Math.sqrt(x * x + y * y + z * z + w * w); + if (len === 0) { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + return dest; + } + len = 1 / len; + dest[0] = x * len; + dest[1] = y * len; + dest[2] = z * len; + dest[3] = w * len; + + return dest; +}; + +/** + * Performs a quaternion multiplication + * + * @param {quat4} quat First operand + * @param {quat4} quat2 Second operand + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.multiply = function (quat, quat2, dest) { + if (!dest) { dest = quat; } + + var qax = quat[0], qay = quat[1], qaz = quat[2], qaw = quat[3], + qbx = quat2[0], qby = quat2[1], qbz = quat2[2], qbw = quat2[3]; + + dest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + dest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + dest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + dest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + return dest; +}; + +/** + * Transforms a vec3 with the given quaternion + * + * @param {quat4} quat quat4 to transform the vector with + * @param {vec3} vec vec3 to transform + * @param {vec3} [dest] vec3 receiving operation result. If not specified result is written to vec + * + * @returns dest if specified, vec otherwise + */ +quat4.multiplyVec3 = function (quat, vec, dest) { + if (!dest) { dest = vec; } + + var x = vec[0], y = vec[1], z = vec[2], + qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return dest; +}; + +/** + * Calculates a 3x3 matrix from the given quat4 + * + * @param {quat4} quat quat4 to create matrix from + * @param {mat3} [dest] mat3 receiving operation result + * + * @returns {mat3} dest if specified, a new mat3 otherwise + */ +quat4.toMat3 = function (quat, dest) { + if (!dest) { dest = mat3.create(); } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + + dest[3] = xy - wz; + dest[4] = 1 - (xx + zz); + dest[5] = yz + wx; + + dest[6] = xz + wy; + dest[7] = yz - wx; + dest[8] = 1 - (xx + yy); + + return dest; +}; + +/** + * Calculates a 4x4 matrix from the given quat4 + * + * @param {quat4} quat quat4 to create matrix from + * @param {mat4} [dest] mat4 receiving operation result + * + * @returns {mat4} dest if specified, a new mat4 otherwise + */ +quat4.toMat4 = function (quat, dest) { + if (!dest) { dest = mat4.create(); } + + var x = quat[0], y = quat[1], z = quat[2], w = quat[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + dest[0] = 1 - (yy + zz); + dest[1] = xy + wz; + dest[2] = xz - wy; + dest[3] = 0; + + dest[4] = xy - wz; + dest[5] = 1 - (xx + zz); + dest[6] = yz + wx; + dest[7] = 0; + + dest[8] = xz + wy; + dest[9] = yz - wx; + dest[10] = 1 - (xx + yy); + dest[11] = 0; + + dest[12] = 0; + dest[13] = 0; + dest[14] = 0; + dest[15] = 1; + + return dest; +}; + +/** + * Performs a spherical linear interpolation between two quat4 + * + * @param {quat4} quat First quaternion + * @param {quat4} quat2 Second quaternion + * @param {number} slerp Interpolation amount between the two inputs + * @param {quat4} [dest] quat4 receiving operation result. If not specified result is written to quat + * + * @returns {quat4} dest if specified, quat otherwise + */ +quat4.slerp = function (quat, quat2, slerp, dest) { + if (!dest) { dest = quat; } + + var cosHalfTheta = quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3], + halfTheta, + sinHalfTheta, + ratioA, + ratioB; + + if (Math.abs(cosHalfTheta) >= 1.0) { + if (dest !== quat) { + dest[0] = quat[0]; + dest[1] = quat[1]; + dest[2] = quat[2]; + dest[3] = quat[3]; + } + return dest; + } + + halfTheta = Math.acos(cosHalfTheta); + sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + + if (Math.abs(sinHalfTheta) < 0.001) { + dest[0] = (quat[0] * 0.5 + quat2[0] * 0.5); + dest[1] = (quat[1] * 0.5 + quat2[1] * 0.5); + dest[2] = (quat[2] * 0.5 + quat2[2] * 0.5); + dest[3] = (quat[3] * 0.5 + quat2[3] * 0.5); + return dest; + } + + ratioA = Math.sin((1 - slerp) * halfTheta) / sinHalfTheta; + ratioB = Math.sin(slerp * halfTheta) / sinHalfTheta; + + dest[0] = (quat[0] * ratioA + quat2[0] * ratioB); + dest[1] = (quat[1] * ratioA + quat2[1] * ratioB); + dest[2] = (quat[2] * ratioA + quat2[2] * ratioB); + dest[3] = (quat[3] * ratioA + quat2[3] * ratioB); + + return dest; +}; + +/** + * Returns a string representation of a quaternion + * + * @param {quat4} quat quat4 to represent as a string + * + * @returns {string} String representation of quat + */ +quat4.str = function (quat) { + return '[' + quat[0] + ', ' + quat[1] + ', ' + quat[2] + ', ' + quat[3] + ']'; +}; + diff --git a/part2/index.html b/part2/Sin_COS/index.html similarity index 69% rename from part2/index.html rename to part2/Sin_COS/index.html index 1e3f7e2..fb153ab 100644 --- a/part2/index.html +++ b/part2/Sin_COS/index.html @@ -1,40 +1,47 @@ - - - - -Vertex Wave - - - - - -
- - - - - - - - - - - + + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/part2/index.js b/part2/Sin_COS/index.js similarity index 94% rename from part2/index.js rename to part2/Sin_COS/index.js index b5df3fb..71acb4f 100644 --- a/part2/index.js +++ b/part2/Sin_COS/index.js @@ -1,151 +1,156 @@ -(function() { - "use strict"; - /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ - /*global getShaderSource,createWebGLContext,createProgram*/ - - var NUM_WIDTH_PTS = 32; - var NUM_HEIGHT_PTS = 32; - - var message = document.getElementById("message"); - var canvas = document.getElementById("canvas"); - var context = createWebGLContext(canvas, message); - if (!context) { - return; - } - - /////////////////////////////////////////////////////////////////////////// - - context.viewport(0, 0, canvas.width, canvas.height); - context.clearColor(1.0, 1.0, 1.0, 1.0); - context.enable(context.GL_DEPTH_TEST); - - var persp = mat4.create(); - mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); - - var eye = [2.0, 1.0, 3.0]; - var center = [0.0, 0.0, 0.0]; - var up = [0.0, 0.0, 1.0]; - var view = mat4.create(); - mat4.lookAt(eye, center, up, view); - - var positionLocation = 0; - var heightLocation = 1; - var u_modelViewPerspectiveLocation; - - (function initializeShader() { - var program; - var vs = getShaderSource(document.getElementById("vs")); - var fs = getShaderSource(document.getElementById("fs")); - - var program = createProgram(context, vs, fs, message); - context.bindAttribLocation(program, positionLocation, "position"); - u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); - - context.useProgram(program); - })(); - - var heights; - var numberOfIndices; - - (function initializeGrid() { - function uploadMesh(positions, heights, indices) { - // Positions - var positionsName = context.createBuffer(); - context.bindBuffer(context.ARRAY_BUFFER, positionsName); - context.bufferData(context.ARRAY_BUFFER, positions, context.STATIC_DRAW); - context.vertexAttribPointer(positionLocation, 2, context.FLOAT, false, 0, 0); - context.enableVertexAttribArray(positionLocation); - - if (heights) - { - // Heights - var heightsName = context.createBuffer(); - context.bindBuffer(context.ARRAY_BUFFER, heightsName); - context.bufferData(context.ARRAY_BUFFER, heights.length * heights.BYTES_PER_ELEMENT, context.STREAM_DRAW); - context.vertexAttribPointer(heightLocation, 1, context.FLOAT, false, 0, 0); - context.enableVertexAttribArray(heightLocation); - } - - // Indices - var indicesName = context.createBuffer(); - context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indicesName); - context.bufferData(context.ELEMENT_ARRAY_BUFFER, indices, context.STATIC_DRAW); - } - - var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; - var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; - - var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; - - var positions = new Float32Array(2 * numberOfPositions); - var indices = new Uint16Array(2 * ((NUM_HEIGHT_PTS * (NUM_WIDTH_PTS - 1)) + (NUM_WIDTH_PTS * (NUM_HEIGHT_PTS - 1)))); - - var positionsIndex = 0; - var indicesIndex = 0; - var length; - - for (var j = 0; j < NUM_WIDTH_PTS; ++j) - { - positions[positionsIndex++] = j /(NUM_WIDTH_PTS - 1); - positions[positionsIndex++] = 0.0; - - if (j>=1) - { - length = positionsIndex / 2; - indices[indicesIndex++] = length - 2; - indices[indicesIndex++] = length - 1; - } - } - - for (var i = 0; i < HEIGHT_DIVISIONS; ++i) - { - var v = (i + 1) / (NUM_HEIGHT_PTS - 1); - positions[positionsIndex++] = 0.0; - positions[positionsIndex++] = v; - - length = (positionsIndex / 2); - indices[indicesIndex++] = length - 1; - indices[indicesIndex++] = length - 1 - NUM_WIDTH_PTS; - - for (var k = 0; k < WIDTH_DIVISIONS; ++k) - { - positions[positionsIndex++] = (k + 1) / (NUM_WIDTH_PTS - 1); - positions[positionsIndex++] = v; - - length = positionsIndex / 2; - var new_pt = length - 1; - indices[indicesIndex++] = new_pt - 1; // Previous side - indices[indicesIndex++] = new_pt; - - indices[indicesIndex++] = new_pt - NUM_WIDTH_PTS; // Previous bottom - indices[indicesIndex++] = new_pt; - } - } - - uploadMesh(positions, heights, indices); - numberOfIndices = indices.length; - })(); - - (function animate(){ - /////////////////////////////////////////////////////////////////////////// - // Update - - var model = mat4.create(); - mat4.identity(model); - mat4.translate(model, [-0.5, -0.5, 0.0]); - var mv = mat4.create(); - mat4.multiply(view, model, mv); - var mvp = mat4.create(); - mat4.multiply(persp, mv, mvp); - - /////////////////////////////////////////////////////////////////////////// - // Render - context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); - - context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); - context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); - - window.requestAnimFrame(animate); - })(); - -}()); +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + var NUM_WIDTH_PTS = 32; + var NUM_HEIGHT_PTS = 32; + + var message = document.getElementById("message"); + var canvas = document.getElementById("canvas"); + var context = createWebGLContext(canvas, message); + if (!context) { + return; + } + + /////////////////////////////////////////////////////////////////////////// + + context.viewport(0, 0, canvas.width, canvas.height); + context.clearColor(1.0, 1.0, 1.0, 1.0); + context.enable(context.GL_DEPTH_TEST); + + var persp = mat4.create(); + mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); + + var eye = [2.0, 1.0, 3.0]; + var center = [0.0, 0.0, 0.0]; + var up = [0.0, 0.0, 1.0]; + var view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + var positionLocation = 0; + var heightLocation = 1; + var u_modelViewPerspectiveLocation; + var u_time; + + + (function initializeShader() { + var program; + var vs = getShaderSource(document.getElementById("vs")); + var fs = getShaderSource(document.getElementById("fs")); + + var program = createProgram(context, vs, fs, message); + context.bindAttribLocation(program, positionLocation, "position"); + u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + u_time=context.getUniformLocation(program,"u_time"); + + context.useProgram(program); + })(); + + var heights; + var numberOfIndices; + + (function initializeGrid() { + function uploadMesh(positions, heights, indices) { + // Positions + var positionsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, positionsName); + context.bufferData(context.ARRAY_BUFFER, positions, context.STATIC_DRAW); + context.vertexAttribPointer(positionLocation, 2, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(positionLocation); + + if (heights) + { + // Heights + var heightsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, heightsName); + context.bufferData(context.ARRAY_BUFFER, heights.length * heights.BYTES_PER_ELEMENT, context.STREAM_DRAW); + context.vertexAttribPointer(heightLocation, 1, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(heightLocation); + } + + // Indices + var indicesName = context.createBuffer(); + context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indicesName); + context.bufferData(context.ELEMENT_ARRAY_BUFFER, indices, context.STATIC_DRAW); + } + + var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; + var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; + + var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; + + var positions = new Float32Array(2 * numberOfPositions); + var indices = new Uint16Array(2 * ((NUM_HEIGHT_PTS * (NUM_WIDTH_PTS - 1)) + (NUM_WIDTH_PTS * (NUM_HEIGHT_PTS - 1)))); + + var positionsIndex = 0; + var indicesIndex = 0; + var length; + + for (var j = 0; j < NUM_WIDTH_PTS; ++j) + { + positions[positionsIndex++] = j /(NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = 0.0; + + if (j>=1) + { + length = positionsIndex / 2; + indices[indicesIndex++] = length - 2; + indices[indicesIndex++] = length - 1; + } + } + + for (var i = 0; i < HEIGHT_DIVISIONS; ++i) + { + var v = (i + 1) / (NUM_HEIGHT_PTS - 1); + positions[positionsIndex++] = 0.0; + positions[positionsIndex++] = v; + + length = (positionsIndex / 2); + indices[indicesIndex++] = length - 1; + indices[indicesIndex++] = length - 1 - NUM_WIDTH_PTS; + + for (var k = 0; k < WIDTH_DIVISIONS; ++k) + { + positions[positionsIndex++] = (k + 1) / (NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = v; + + length = positionsIndex / 2; + var new_pt = length - 1; + indices[indicesIndex++] = new_pt - 1; // Previous side + indices[indicesIndex++] = new_pt; + + indices[indicesIndex++] = new_pt - NUM_WIDTH_PTS; // Previous bottom + indices[indicesIndex++] = new_pt; + } + } + + uploadMesh(positions, heights, indices); + numberOfIndices = indices.length; + })(); + +var delta=0.0; + (function animate(){ + /////////////////////////////////////////////////////////////////////////// + // Update + + var model = mat4.create(); + mat4.identity(model); + mat4.translate(model, [-0.5, -0.5, 0.0]); + var mv = mat4.create(); + mat4.multiply(view, model, mv); + var mvp = mat4.create(); + mat4.multiply(persp, mv, mvp); + + /////////////////////////////////////////////////////////////////////////// + // Render + context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); + + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); + delta += 0.01; + context.uniform1f(u_time, delta); + window.requestAnimFrame(animate); + })(); + +}()); diff --git a/part2/Sin_COS/noise3D.js b/part2/Sin_COS/noise3D.js new file mode 100644 index 0000000..2d4ffd2 --- /dev/null +++ b/part2/Sin_COS/noise3D.js @@ -0,0 +1,316 @@ +(function(exports) { + "use strict"; + /*global window,vec3*/ + + exports = exports || window; + + function step(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0 + ]; + } + + function step_vec4(edge, x) { + return [ + (x[0] < edge[0]) ? 0.0 : 1.0, + (x[1] < edge[1]) ? 0.0 : 1.0, + (x[2] < edge[2]) ? 0.0 : 1.0, + (x[3] < edge[3]) ? 0.0 : 1.0 + ]; + } + + function min(x, y) { + return [ + y[0] < x[0] ? y[0] : x[0], + y[1] < x[1] ? y[1] : x[1], + y[2] < x[2] ? y[2] : x[2] + ]; + } + + function max(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2] + ]; + } + + function max_vec4(x, y) { + return [ + y[0] > x[0] ? y[0] : x[0], + y[1] > x[1] ? y[1] : x[1], + y[2] > x[2] ? y[2] : x[2], + y[3] > x[3] ? y[3] : x[3] + ]; + } + + function vec4_dot(left, right) { + return left[0] * right[0] + + left[1] * right[1] + + left[2] * right[2] + + left[3] * right[3]; + } + + // + // Description : Array and textureless GLSL 2D/3D/4D simplex + // noise functions. + // Author : Ian McEwan, Ashima Arts. + // Maintainer : ijm + // Lastmod : 20110822 (ijm) + // License : Copyright (C) 2011 Ashima Arts. All rights reserved. + // Distributed under the MIT License. See LICENSE file. + // https://github.com/ashima/webgl-noise + // + function mod289_vec3(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0 + ]; + } + + function mod289_vec4(x) { + var temp = (1.0 / 289.0); + return [ + x[0] - Math.floor(x[0] * temp) * 289.0, + x[1] - Math.floor(x[1] * temp) * 289.0, + x[2] - Math.floor(x[2] * temp) * 289.0, + x[3] - Math.floor(x[3] * temp) * 289.0 + ]; + } + + function permute_vec4(x) { + return mod289_vec4([ + ((x[0]*34.0)+1.0)*x[0], + ((x[1]*34.0)+1.0)*x[1], + ((x[2]*34.0)+1.0)*x[2], + ((x[3]*34.0)+1.0)*x[3] + ]); + } + + function taylorInvSqrt_vec4(r) { + return [ + 1.79284291400159 - 0.85373472095314 * r[0], + 1.79284291400159 - 0.85373472095314 * r[1], + 1.79284291400159 - 0.85373472095314 * r[2], + 1.79284291400159 - 0.85373472095314 * r[3] + ]; + } + + exports.snoise = function(v) { + // const vec2 C = vec2(1.0f/6.0f, 1.0f/3.0f) ; + // const vec4 D = vec4(0.0f, 0.5f, 1.0f, 2.0f); + var C = [1.0/6.0, 1.0/3.0]; + var D = [0.0, 0.5, 1.0, 2.0]; + + // vec3 i = floor(v + dot(v, vec3(C.y, C.y, C.y)) ); + // vec3 x0 = v - i + dot(i, vec3(C.x, C.x, C.x) ); + var temp0 = vec3.create(); + var temp3 = vec3.dot(v, [C[1], C[1], C[1]]); + vec3.add(v, [temp3, temp3, temp3], temp0); + var i = [Math.floor(temp0[0]), Math.floor(temp0[1]), Math.floor(temp0[2])]; + var temp1 = vec3.create(); + vec3.subtract(v, i, temp1); + var temp2 = vec3.dot(i, [C[0], C[0], C[0]]); + var x0 = vec3.create(); + vec3.add(temp1, [temp2, temp2, temp2], x0); + + // vec3 g = step(vec3(x0.y, x0.z, x0.x), vec3(x0.x, x0.y, x0.z)); + // vec3 l = 1.0f - g; + // vec3 i1 = min( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + // vec3 i2 = max( vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y) ); + var g = step([x0[1], x0[2], x0[0]], [x0[0], x0[1], x0[2]]); + var l = [1.0 - g[0], 1.0 - g[1], 1.0 - g[2]]; + var i1 = min([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + var i2 = max([g[0], g[1], g[2]], [l[2], l[0], l[1]]); + + // vec3 x1 = x0 - i1 + vec3(C.x, C.x, C.x); + // vec3 x2 = x0 - i2 + vec3(C.y, C.y, C.y); // 2.0*C.x = 1/3 = C.y + // vec3 x3 = x0 - vec3(D.y, D.y, D.y); // -1.0+3.0*C.x = -0.5 = -D.y + var temp4 = vec3.create(); + vec3.subtract(x0, i1, temp4); + var x1 = vec3.create(); + vec3.add(temp4, [C[0], C[0], C[0]], x1); + var temp5 = vec3.create(); + vec3.subtract(x0, i2, temp5); + var x2 = vec3.create(); + vec3.add(temp5, [C[1], C[1], C[1]], x2); + var x3 = vec3.create(); + vec3.subtract(x0, [D[1], D[1], D[1]], x3); + + // i = mod289(i); + // vec4 p = permute( permute( permute( + // i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + // + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + // + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + i = mod289_vec3(i); + var p = permute_vec4([i[2] + 0.0, i[2] + i1[2], i[2] + i2[2], i[2] + 1.0]); + p[0] += i[1] + 0.0; + p[1] += i[1] + i1[1]; + p[2] += i[1] + i2[1]; + p[3] += i[1] + 1.0; + p = permute_vec4(p); + p[0] += i[0] + 0.0; + p[1] += i[0] + i1[0]; + p[2] += i[0] + i2[0]; + p[3] += i[0] + 1.0; + p = permute_vec4(p); + + // float n_ = 0.142857142857f; // 1.0/7.0 + // vec3 ns = n_ * vec3(D.w, D.y, D.z) - vec3(D.x, D.z, D.x); +// var n_ = 0.142857142857; // 1.0/7.0 +// var ns = [ +// n_ * D[3] - D[0], +// n_ * D[1] - D[2], +// n_ * D[2] - D[0] +// ]; + var ns = [ + 0.28571430, + -0.92857140, + 0.14285715 + ]; + + // vec4 j = p - 49.0f * floor(p * ns.z * ns.z); // mod(p,7*7) + var j = [ + p[0] - 49.0 * Math.floor(p[0] * ns[2] * ns[2]), + p[1] - 49.0 * Math.floor(p[1] * ns[2] * ns[2]), + p[2] - 49.0 * Math.floor(p[2] * ns[2] * ns[2]), + p[3] - 49.0 * Math.floor(p[3] * ns[2] * ns[2]) + ]; + + // vec4 x_ = floor(j * ns.z); + // vec4 y_ = floor(j - 7.0f * x_ ); // mod(j,N) + var x_ = [ + Math.floor(j[0] * ns[2]), + Math.floor(j[1] * ns[2]), + Math.floor(j[2] * ns[2]), + Math.floor(j[3] * ns[2]) + ]; + var y_ = [ + Math.floor(j[0] - 7.0 * x_[0] ), + Math.floor(j[1] - 7.0 * x_[1] ), + Math.floor(j[2] - 7.0 * x_[2] ), + Math.floor(j[3] - 7.0 * x_[3] ) + ]; + + // vec4 x = x_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 y = y_ *ns.x + vec4(ns.y, ns.y, ns.y, ns.y); + // vec4 h = 1.0f - abs(x) - abs(y); + var x = [ + x_[0] *ns[0] + ns[1], + x_[1] *ns[0] + ns[1], + x_[2] *ns[0] + ns[1], + x_[3] *ns[0] + ns[1] + ]; + var y = [ + y_[0] *ns[0] + ns[1], + y_[1] *ns[0] + ns[1], + y_[2] *ns[0] + ns[1], + y_[3] *ns[0] + ns[1] + ]; + var h = [ + 1.0 - Math.abs(x[0]) - Math.abs(y[0]), + 1.0 - Math.abs(x[1]) - Math.abs(y[1]), + 1.0 - Math.abs(x[2]) - Math.abs(y[2]), + 1.0 - Math.abs(x[3]) - Math.abs(y[3]) + ]; + + // vec4 b0 = vec4( vec2(x.x, x.y), vec2(y.x, y.y) ); + // vec4 b1 = vec4( vec2(x.z, x.w), vec2(y.z, y.w) ); + var b0 = [x[0], x[1], y[0], y[1]]; + var b1 = [x[2], x[3], y[2], y[3]]; + + // vec4 s0 = floor(b0)*2.0f + 1.0f; + // vec4 s1 = floor(b1)*2.0f + 1.0f; + // vec4 sh = -step(h, vec4(0.0)); + + var s0 = [ + Math.floor(b0[0])*2.0 + 1.0, + Math.floor(b0[1])*2.0 + 1.0, + Math.floor(b0[2])*2.0 + 1.0, + Math.floor(b0[3])*2.0 + 1.0 + ]; + var s1 = [ + Math.floor(b1[0])*2.0 + 1.0, + Math.floor(b1[1])*2.0 + 1.0, + Math.floor(b1[2])*2.0 + 1.0, + Math.floor(b1[3])*2.0 + 1.0 + ]; + var sh = step_vec4(h, [0.0, 0.0, 0.0, 0.0]); + sh[0] = -sh[0]; + sh[1] = -sh[1]; + sh[2] = -sh[2]; + sh[3] = -sh[3]; + + // vec4 a0 = vec4(b0.x, b0.z, b0.y, b0.w) + vec4(s0.x, s0.z, s0.y, s0.w) * vec4(sh.x, sh.x, sh.y, sh.y) ; + // vec4 a1 = vec4(b1.x, b1.z, b1.y, b1.w) + vec4(s1.x, s1.z, s1.y, s1.w) * vec4(sh.z, sh.z, sh.w, sh.w) ; + var a0 = [ + b0[0] + s0[0] * sh[0], + b0[2] + s0[2] * sh[0], + b0[1] + s0[1] * sh[1], + b0[3] + s0[3] * sh[1] + ]; + var a1 = [ + b1[0] + s1[0] * sh[2], + b1[2] + s1[2] * sh[2], + b1[1] + s1[1] * sh[3], + b1[3] + s1[3] * sh[3] + ]; + + // vec3 p0 = vec3(a0.x, a0.y, h.x); + // vec3 p1 = vec3(a0.z, a0.w, h.y); + // vec3 p2 = vec3(a1.x, a1.y, h.z); + // vec3 p3 = vec3(a1.z, a1.w, h.w); + var p0 = [a0[0], a0[1], h[0]]; + var p1 = [a0[2], a0[3], h[1]]; + var p2 = [a1[0], a1[1], h[2]]; + var p3 = [a1[2], a1[3], h[3]]; + + // vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + // p0 *= norm.x; + // p1 *= norm.y; + // p2 *= norm.z; + // p3 *= norm.w; + var norm = taylorInvSqrt_vec4([vec3.dot(p0,p0), vec3.dot(p1,p1), vec3.dot(p2, p2), vec3.dot(p3,p3)]); + p0 = [p0[0]*norm[0], p0[1]*norm[0], p0[2]*norm[0]]; + p1 = [p1[0]*norm[1], p1[1]*norm[1], p1[2]*norm[1]]; + p2 = [p2[0]*norm[2], p2[1]*norm[2], p2[2]*norm[2]]; + p3 = [p3[0]*norm[3], p3[1]*norm[3], p3[2]*norm[3]]; + + // vec4 m = max(0.6f - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + // m = m * m; + var m = max_vec4([ + 0.6 - vec3.dot(x0,x0), + 0.6 - vec3.dot(x1,x1), + 0.6 - vec3.dot(x2,x2), + 0.6 - vec3.dot(x3,x3) + ], [ + 0.0, + 0.0, + 0.0, + 0.0 + ]); + m[0] *= m[0]; + m[1] *= m[1]; + m[2] *= m[2]; + m[3] *= m[3]; + + // return 42.0f * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + // dot(p2,x2), dot(p3,x3) ) ); + return 42.0 * vec4_dot([ + m[0] * m[0], + m[1] * m[1], + m[2] * m[2], + m[3] * m[3] + ], [ + vec3.dot(p0,x0), + vec3.dot(p1,x1), + vec3.dot(p2,x2), + vec3.dot(p3,x3) + ]); + }; + +}()); diff --git a/part2/Sin_COS/simplex.vert b/part2/Sin_COS/simplex.vert new file mode 100644 index 0000000..e1ff07a --- /dev/null +++ b/part2/Sin_COS/simplex.vert @@ -0,0 +1,39 @@ +vec3 permute(vec3 x) { + x = ((x*34.0)+1.0)*x; + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +float simplexNoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = i - floor(i * (1.0 / 289.0)) * 289.0; + + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= inversesqrt( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} \ No newline at end of file diff --git a/part2/Sin_COS/webGLUtility.js b/part2/Sin_COS/webGLUtility.js new file mode 100644 index 0000000..c9de391 --- /dev/null +++ b/part2/Sin_COS/webGLUtility.js @@ -0,0 +1,97 @@ +(function(exports) { + "use strict"; + /*global window*/ + + exports = exports || window; + + /////////////////////////////////////////////////////////////////////////// + // Shim from http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + + exports.requestAnimFrame = + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function( callback ){ + window.setTimeout(callback, 1000 / 60); + }; + + /////////////////////////////////////////////////////////////////////////// + // getShader based on http://learningwebgl.com/cookbook/index.php/Loading_shaders_from_HTML_script_tags + + exports.getShaderSource = function(script) { + var str = ""; + var k = script.firstChild; + while (k) { + if (k.nodeType == 3) { + str += k.textContent; + } + k = k.nextSibling; + } + + return str; + }; + + /////////////////////////////////////////////////////////////////////////// + + exports.createWebGLContext = function(canvas, message) { + if (!window.WebGLRenderingContext) { + message.innerText = "The browser does not support WebGL. Visit http://get.webgl.org."; + return undefined; + } + + var context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + + if (!context && message) { + message.innerText = "The browser supports WebGL, but initialization failed."; + } + + return context; + }; + + exports.createProgram = function(context, vertexShaderSource, fragmentShaderSource, message) { + var program = context.createProgram(); + var vs = context.createShader(context.VERTEX_SHADER); + var fs = context.createShader(context.FRAGMENT_SHADER); + + context.attachShader(program, vs); + context.attachShader(program, fs); + + // Mark shader for deletion when the program is deleted + context.deleteShader(vs); + context.deleteShader(fs); + + context.shaderSource(vs, vertexShaderSource); + context.compileShader(vs); + if (!context.getShaderParameter(vs, context.COMPILE_STATUS)) { + if (message) { + message.innerText += context.getShaderInfoLog(vs) + "\n"; + } + context.deleteProgram(program); + return; + } + + context.shaderSource(fs, fragmentShaderSource); + context.compileShader(fs); + if (!context.getShaderParameter(fs, context.COMPILE_STATUS)) { + if (message) { + message.innerText += context.getShaderInfoLog(fs) + "\n"; + } + context.deleteProgram(program); + return; + } + + context.linkProgram(program); + if (!context.getProgramParameter(program, context.LINK_STATUS)) { + if (message) { + message.innerText += context.getProgramInfoLog(program) + "\n"; + } + context.deleteProgram(program); + return; + } + + return program; + }; + +}());