Skip to content

Instantly share code, notes, and snippets.

@nanjizal
Created August 3, 2017 18:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanjizal/d98fb126a9bb90d2cded92353144bfec to your computer and use it in GitHub Desktop.
Save nanjizal/d98fb126a9bb90d2cded92353144bfec to your computer and use it in GitHub Desktop.
package;
import js.html.Float32Array;
import js.html.CanvasElement;
import js.html.webgl.RenderingContext;
import js.html.webgl.Program;
import js.html.webgl.Shader;
import js.html.webgl.Texture;
import js.html.webgl.Framebuffer;
import js.Browser;
import js.html.Uint16Array;
import js.html.StyleElement;
import js.html.ImageElement;
import js.html.Image;
import HaxeLogo;
import khaMath.Matrix4;
import justTriangles.Triangle;
import justTriangles.Draw;
import justTriangles.Point;
import justTriangles.PathContext;
import justTriangles.ShapePoints;
import justTriangles.QuickPaths;
import htmlHelper.tools.CSSEnterFrame;
import justTriangles.SvgPath;
import justTriangles.PathContextTrace;
using Test;
@:enum
abstract RainbowColors( Int ) to Int from Int {
var Violet = 0x9400D3;
var Indigo = 0x4b0082;
var Blue = 0x0000FF;
var Green = 0x00ff00;
var Yellow = 0xFFFF00;
var Orange = 0xFF7F00;
var Red = 0xFF0000;
var Black = 0x000000;
}
class TriangleGradient extends Triangle {
public var gradCorner: Int; // 0, 1, 2
public var colorID2: Int;
public function new( id_: Int
, outline_: Bool
, A_: Point, B_: Point, C_: Point
, depth_: Float
, colorID_: Int
, colorID2_: Int
, gradCorner_: Int
){
super( id_, outline_, A_, B_, C_, depth_, colorID_ );
// switch gradCorner if corner is 1 or 2 and the winding adjusted.
switch( gradCorner_ ){
case 0:
gradCorner = 0;
case 1:
if( Triangle.adjustWinding( A_, B_, C_ ) ) {
gradCorner = 2;
} else {
gradCorner = 1;
}
case 2:
if( Triangle.adjustWinding( A_, B_, C_ ) ){
gradCorner = 1;
} else {
gradCorner = 2;
}
}
colorID2 = colorID2_;
}
}
class QuadGradient{
public function new( id_: Int
, outline_: Bool
, pos_: Point, dim_: Point
, depth_: Float
, colorID_: Int
, colorID2_: Int ){
// A B
// D C
var A_ = pos_;
var B_ = { x: pos_.x + dim_.x, y: pos_.y };
var C_ = { x: pos_.x + dim_.x, y: pos_.y + dim_.y };
var D_ = { x: pos_.x, y: pos_.y + dim_.y };
Triangle.triangles.push( cast new TriangleGradient( id_, outline_, A_, B_, D_, depth_, colorID_, colorID2_, 1 ) );
Triangle.triangles.push( cast new TriangleGradient( id_, outline_, B_, C_, D_, depth_, colorID2_, colorID_, 2 ) );
}
}
@:access(justTriangles.PathContext.reverseEntries)
class Test {
var rainbow = [ Black, Red, Orange, Yellow, Green, Blue, Indigo, Violet ];
public static inline var vertexString0: String =
'attribute vec3 pos;' +
'attribute vec4 color;' +
'varying vec4 vcol;' +
'uniform mat4 modelViewProjection;' +
'void main(void) {' +
' gl_Position = vec4(pos, 1.0);'+
/* ' gl_Position = modelViewProjection * vec4(pos, 1.0);' +*/
' vcol = color;' +
'}';
public static inline var fragmentString0: String =
'precision mediump float;'+
'varying vec4 vcol;' +
'void main(void) {' +
' gl_FragColor = vcol;' +
'}';
public static inline var vertexString: String =
'attribute vec3 pos;' +
'attribute vec2 aTexture;' +
'varying vec2 texture;' +
'uniform mat4 modelViewProjection;' +
'void main(void) {' +
' gl_Position = modelViewProjection * vec4( pos, 1.0);' +
' texture = vec2( aTexture.x , 1.-aTexture.y );' +
'}';
public static inline var fragmentString: String =
'precision mediump float;' +
'uniform sampler2D image;' +
'varying vec2 texture;' +
'void main(void) {' +
'float bound = step( texture.s, 1. ) *' +
'step( texture.t, 1. ) *' +
' ( 1. - step( texture.s, 0. ) ) * '+
' ( 1. - step( texture.t, 0. ) );'+
'gl_FragColor = bound * texture2D( image, vec2( texture.s, texture.t ) );'+
'}';
public static inline function ident(): Array<Float> {
return [ 1.0, 0.0, 0.0, 0.0,
0.0, 1.1, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
];
}
// converts from our internal representation of a matrix to the Float32Array that webgl uses.
public static inline function transferM4_arr32( arr: Float32Array, m: Matrix4 ) {
arr.set([ m._00, m._10, m._20, m._30, m._01, m._11, m._21, m._31, m._02, m._12, m._22, m._32, m._03, m._13, m._23, m._33 ]);
}
static function main(){
Draw.drawTri = Triangle.drawTri;
new Test();
}
public static inline var width: Int = 800;
public static inline var height: Int = 800;
var canvas: CanvasElement;
var gl: RenderingContext;
var program1: Program;
var program0: Program;
var vertices = new Array<Float>();
var texturePos = new Array<Float>();
var indices = new Array<Int>();
var theta = 0.0; // Angle in radians
var modelViewProjection = Matrix4.identity(); // external matrix controlling global 3d position
var matrix32Array = new Float32Array( ident() ); // internal matrix passed to shader
//
var image: Image;
var colors = new Array<Float>();
//
public function new(){
gl = createWebGl( width, height );
// 'using' allows us to put gl in front of the function making the code more descriptive
program0 = gl.createShaderProgram( gl.vertex( vertexString0 ), gl.fragment( fragmentString0 ) );
program1 = gl.createShaderProgram( gl.vertex( vertexString ), gl.fragment( fragmentString ) );
loadImage( HaxeLogo.gif ); // MUST BE SAME DOMAIN!!!
}
function drawGradientOutlines(){
var ctx = new PathContext( 1, 1000, 0, 0 );
var step = 250;
var p1 = ctx.pt( step, 2000 );
for( i in 0...6 ){
var p0 = ctx.pt( i*step, 0 );
new QuadGradient( 10, false, p0, p1, 0, i+1, i+2 );
}
}
function drawVectorOutlines(){
var thick = 4;
var ctx = new PathContext( 1, 1000, 0, 0 );
ctx.setColor( 2, 2 );
ctx.setThickness( thick*5 );
ctx.lineType = TriangleJoinCurve; // - default
var pathTrace = new PathContextTrace();
var p = new SvgPath( ctx );
p.parse( bird_d, 0, 0, 3, 3 );
ctx.render( thick, false );
ctx.setThickness( thick );
var x0: Float = 0.;
var y0: Float = 0.;
for( i in 0...Std.int( 2000/30 ) ){
ctx.moveTo( x0, y0 );
ctx.lineTo( 2000., y0 );
y0+=30;
}
ctx.render( thick, false );
}
static inline function vertex( gl: RenderingContext, str: String ){
return gl.createShaderFromString( RenderingContext.VERTEX_SHADER, str );
}
static inline function fragment( gl: RenderingContext, str: String ){
return gl.createShaderFromString( RenderingContext.FRAGMENT_SHADER, str );
}
function reset( gl: RenderingContext ): RenderingContext {
var numAttribs = gl.getParameter( RenderingContext.MAX_VERTEX_ATTRIBS );
var tmp = gl.createBuffer();
gl.bindBuffer( RenderingContext.ARRAY_BUFFER, tmp );
for( ii in 0...numAttribs ){
gl.disableVertexAttribArray( ii );
gl.vertexAttribPointer(ii, 4, RenderingContext.FLOAT, false, 0, 0 );
gl.vertexAttrib1f( ii, 0 );
}
gl.deleteBuffer( tmp );
var numTextureUnits = gl.getParameter( RenderingContext.MAX_TEXTURE_IMAGE_UNITS );
for( ii in 0...numTextureUnits ){
gl.activeTexture( RenderingContext.TEXTURE0 + ii );
gl.bindTexture( RenderingContext.TEXTURE_CUBE_MAP, null );
gl.bindTexture( RenderingContext.TEXTURE_2D, null );
}
gl.activeTexture( RenderingContext.TEXTURE0 );
gl.useProgram( null );
gl.bindBuffer( RenderingContext.ARRAY_BUFFER, null );
gl.bindBuffer( RenderingContext.ELEMENT_ARRAY_BUFFER, null );
gl.bindFramebuffer( RenderingContext.FRAMEBUFFER, null );
gl.bindRenderbuffer( RenderingContext.RENDERBUFFER, null );
gl.disable( RenderingContext.BLEND );
gl.disable( RenderingContext.CULL_FACE );
gl.disable( RenderingContext.DEPTH_TEST );
gl.disable( RenderingContext.DITHER );
gl.disable( RenderingContext.SCISSOR_TEST );
gl.blendColor( 0, 0, 0, 0 );
gl.blendEquation( RenderingContext.FUNC_ADD );
gl.blendFunc( RenderingContext.ONE, RenderingContext.ZERO );
gl.clearColor( 0, 0, 0, 0 );
gl.clearDepth( 1 );
gl.clearStencil( -1 );
gl.colorMask( true, true, true, true );
gl.cullFace( RenderingContext.BACK );
gl.depthFunc( RenderingContext.LESS );
gl.depthMask( true );
gl.depthRange( 0, 1 );
gl.frontFace( RenderingContext.CCW );
gl.hint( RenderingContext.GENERATE_MIPMAP_HINT, RenderingContext.DONT_CARE );
gl.lineWidth( 1 );
gl.pixelStorei( RenderingContext.PACK_ALIGNMENT, 4 );
gl.pixelStorei( RenderingContext.UNPACK_ALIGNMENT, 4 );
gl.pixelStorei( RenderingContext.UNPACK_FLIP_Y_WEBGL, 0 );// false?
gl.pixelStorei( RenderingContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0 );// false?
gl.polygonOffset( 0, 0 );
gl.sampleCoverage( 1, false );
gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
gl.stencilFunc( RenderingContext.ALWAYS, 0, 0xFFFFFFFF );
gl.stencilMask( 0xFFFFFFFF );
gl.stencilOp( RenderingContext.KEEP, RenderingContext.KEEP, RenderingContext.KEEP );
gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
//gl.clear( RenderingContext.COLOR_BUFFER_BIT | RenderingContext.DEPTH_BUFFER_BIT | RenderingContext.STENCIL_BUFFER_BIT );
return gl;
}
function loadImage( imgStr: String ){
var img: Image = untyped __js__( "new Image()" );
img.style.left = '0px';
img.style.top = '0px';
img.onload = store.bind( img );
img.style.position = "absolute";
img.src = imgStr;
}
function store( img: Image, e ){
//Browser.document.body.appendChild( img );
// creatingTriangles( Triangle.triangles, img );
//drawVectorOutlines();
//drawGradientOutlines();
setTriangleImage( Triangle.triangles, img );
image = img;
render();
//injectCSSenterFrame();
}
// rather ugly way to inject add a css enterframe loop for animation into the head of document.
function injectCSSenterFrame(){
var s = Browser.document.createStyleElement();
s.innerHTML = "@keyframes spin { from { transform:rotate( 0deg ); } to { transform:rotate( 360deg ); } }";
Browser.document.getElementsByTagName("head")[0].appendChild( s );
(cast s).animation = "spin 1s linear infinite";
loop( 60.0 );
}
function loop( tim: Float ): Bool {
Browser.window.requestAnimationFrame( loop );
onFrame();
return true;
}
// called every frame, sets transform and redraws
function onFrame(){
// we can multiply two rotations to get an interesting movement of the static 2D triangles.
modelViewProjection = Matrix4.identity();
modelViewProjection = Matrix4.rotationZ( theta += Math.PI/100 ).multmat( Matrix4.rotationY( theta ) ); // Remove this line to stop 3D rotation
render();
}
function createWebGl( width_: Int, height_: Int ): RenderingContext {
canvas = Browser.document.createCanvasElement();
canvas.width = width;
canvas.height = height;
var dom = cast canvas;
var style = dom.style;
style.paddingLeft = "0px";
style.paddingTop = "0px";
style.left = '0px';
style.top = '0px';
style.position = "absolute";
Browser.document.body.appendChild( cast canvas );
var gl = canvas.getContextWebGL( { 'antialias': true } );
return gl;
}
static inline function createShaderProgram( gl: RenderingContext, vertex: Shader, fragment: Shader ): Program {
var program = gl.createProgram();
gl.attachShader( program, vertex );
gl.attachShader( program, fragment );
gl.linkProgram( program );
//gl.useProgram( program );
return program;
}
// used for generating fragment and vertex shaders from strings
static inline function createShaderFromString( gl: RenderingContext, shaderType: Int, shaderString: String ): Shader {
var shader = gl.createShader( shaderType );
gl.shaderSource( shader, shaderString );
gl.compileShader( shader );
return shader;
}
function createTriangleColors( triangles: Array<Triangle> ) {
var tri: TriangleGradient;
var count = 0;
for( i in 0...triangles.length ){
tri = cast triangles[ i ];
var color0 = rainbow[ tri.colorID ];
var a0 = .7;
var r0 = ((color0 >> 16) & 255) / 255;
var g0 = ((color0 >> 8) & 255) / 255;
var b0 = (color0 & 255) / 255;
var color1 = rainbow[ tri.colorID2 ];
var a1 = .7;
var r1 = ((color1 >> 16) & 255) / 255;
var g1 = ((color1 >> 8) & 255) / 255;
var b1 = (color1 & 255) / 255;
vertices.push( tri.ax );
vertices.push( tri.ay );
vertices.push( tri.depth );
vertices.push( tri.bx );
vertices.push( tri.by );
vertices.push( tri.depth );
vertices.push( tri.cx );
vertices.push( tri.cy );
vertices.push( tri.depth );
for( k in 0...3 ){
if( tri.gradCorner == k ){
colors.push( r0 );
colors.push( g0 );
colors.push( b0 );
colors.push( a0 );
indices.push( count++ );
} else {
colors.push( r1 );
colors.push( g1 );
colors.push( b1 );
colors.push( a1 );
indices.push( count++ );
}
}
}
}
function setTriangleColors( triangles: Array<Triangle> ){
createTriangleColors( triangles );
gl.passAttributeToShader( program0, 'pos', 3, vertices ); // position data
gl.passIndicesToShader( indices ); // indices data
gl.passAttributeToShader( program0, 'color', 4, colors ); // color data
}
function creatingTriangles( triangles: Array<Triangle>, image: Image ){
var tri: Triangle;
var count = 0;
for( i in 0...triangles.length ){
tri = triangles[ i ];
vertices.push( tri.ax - 0.5 );
texturePos.push( tri.ax );
vertices.push( -tri.ay + 0.5 );
texturePos.push( tri.ay );
vertices.push( tri.depth );
vertices.push( tri.bx - 0.5 );
texturePos.push( tri.bx );
vertices.push( -tri.by + 0.5 );
texturePos.push( tri.by );
vertices.push( tri.depth );
vertices.push( tri.cx - 0.5 );
texturePos.push( tri.cx );
vertices.push( -tri.cy + 0.5 );
texturePos.push( tri.cy );
vertices.push( tri.depth );
for( k in 0...3 ) indices.push( count++ );
}
}
function setTriangleImage( triangles: Array<Triangle>, image: Image ) {
creatingTriangles( triangles, image );
gl.passAttributeToShader( program1, 'pos', 3, vertices ); // position data
gl.passIndicesToShader( indices ); // indices data
gl.uploadImage( program1, image, texturePos ); // image data
}
static inline function uploadImage( gl: RenderingContext, program: Program, image: Image, texturePos: Array<Float> ){
var texture = gl.createTexture();
gl.bindingTexture( program, texture, texturePos );
gl.texImage2D( RenderingContext.TEXTURE_2D, 0, RenderingContext.RGBA, RenderingContext.RGBA, RenderingContext.UNSIGNED_BYTE, image );
}
static inline function bindingTexture( gl: RenderingContext, program: Program, texture: Texture, texturePos: Array<Float> ){
var texCoordLocation = gl.getAttribLocation( program, "aTexture");
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer( RenderingContext.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData( RenderingContext.ARRAY_BUFFER, new Float32Array( texturePos ), RenderingContext.STATIC_DRAW );
gl.enableVertexAttribArray( texCoordLocation);
gl.vertexAttribPointer( texCoordLocation, 2, RenderingContext.FLOAT, false, 0, 0 );
gl.activeTexture( RenderingContext.TEXTURE0 );
gl.bindTexture( RenderingContext.TEXTURE_2D, texture );
gl.pixelStorei( RenderingContext.UNPACK_FLIP_Y_WEBGL, 1 );
gl.texParameteri( RenderingContext.TEXTURE_2D, RenderingContext.TEXTURE_WRAP_S, RenderingContext.CLAMP_TO_EDGE );
gl.texParameteri( RenderingContext.TEXTURE_2D, RenderingContext.TEXTURE_WRAP_T, RenderingContext.CLAMP_TO_EDGE );
gl.texParameteri( RenderingContext.TEXTURE_2D, RenderingContext.TEXTURE_MIN_FILTER, RenderingContext.NEAREST );
gl.texParameteri( RenderingContext.TEXTURE_2D, RenderingContext.TEXTURE_MAG_FILTER, RenderingContext.NEAREST );
}
static inline function textureTest( gl: RenderingContext ){
var texture: Texture;
var framebuffer: Framebuffer;
texture = gl.createTexture();
gl.bindTexture( RenderingContext.TEXTURE_2D, texture );
gl.texImage2D( RenderingContext.TEXTURE_2D, 0, RenderingContext.RGBA, 1024, 1024, 0, RenderingContext.RGBA, RenderingContext.UNSIGNED_BYTE, null );
framebuffer = gl.createFramebuffer();
gl.bindFramebuffer( RenderingContext.FRAMEBUFFER, framebuffer );
gl.framebufferTexture2D( RenderingContext.FRAMEBUFFER, RenderingContext.COLOR_ATTACHMENT0, RenderingContext.TEXTURE_2D, texture, 0 );
gl.bindFramebuffer( RenderingContext.FRAMEBUFFER, null );
}
static inline function passIndicesToShader( gl: RenderingContext, indices: Array<Int> ){
var indexBuffer = gl.createBuffer(); // triangle indicies data
gl.bindBuffer( RenderingContext.ELEMENT_ARRAY_BUFFER, indexBuffer );
gl.bufferData( RenderingContext.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), RenderingContext.STATIC_DRAW );
gl.bindBuffer( RenderingContext.ELEMENT_ARRAY_BUFFER, null );
}
// generic passing attributes to shader.
static inline function passAttributeToShader( gl: RenderingContext, program: Program, name: String, att: Int, arr: Array<Float> ){
var floatBuffer = gl.createBuffer();
gl.bindBuffer( RenderingContext.ARRAY_BUFFER, floatBuffer );
gl.bufferData( RenderingContext.ARRAY_BUFFER, new Float32Array( arr ), RenderingContext.STATIC_DRAW );
var flo = gl.getAttribLocation( program, name );
gl.vertexAttribPointer( flo, att, RenderingContext.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( flo );
gl.bindBuffer( RenderingContext.ARRAY_BUFFER, null );
}
function render(){
reset( gl );
gl.useProgram( program0 );
drawGradientOutlines();
setTriangleColors( Triangle.triangles );
//textureTest( gl );
drawing( program0 );
Triangle.triangles = [];
/*
reset( gl );
drawVectorOutlines();
gl.useProgram( program1 );
if( image != null ) setTriangleImage( Triangle.triangles, image );
drawing( program1 );
*/
}
function drawing( prog: Program ){
// setup and clear
gl.clearColor( 0.5, 0.0, 0.5, 0.9 );
gl.enable( RenderingContext.DEPTH_TEST );
gl.clear( RenderingContext.COLOR_BUFFER_BIT );
gl.viewport( 0, 0, canvas.width, canvas.height );
// apply transform matrices
var modelViewProjectionID = gl.getUniformLocation( prog, 'modelViewProjection' );
transferM4_arr32( matrix32Array, modelViewProjection );
gl.uniformMatrix4fv( modelViewProjectionID, false, matrix32Array );
// draw
gl.drawArrays( RenderingContext.TRIANGLES, 0, indices.length );
}
var quadtest_d = "M200,300 Q400,50 600,300 T1000,300";
var cubictest_d = "M100,200 C100,100 250,100 250,200S400,300 400,200";
var bird_d = "M210.333,65.331C104.367,66.105-12.349,150.637,1.056,276.449c4.303,40.393,18.533,63.704,52.171,79.03c36.307,16.544,57.022,54.556,50.406,112.954c-9.935,4.88-17.405,11.031-19.132,20.015c7.531-0.17,14.943-0.312,22.59,4.341c20.333,12.375,31.296,27.363,42.979,51.72c1.714,3.572,8.192,2.849,8.312-3.078c0.17-8.467-1.856-17.454-5.226-26.933c-2.955-8.313,3.059-7.985,6.917-6.106c6.399,3.115,16.334,9.43,30.39,13.098c5.392,1.407,5.995-3.877,5.224-6.991c-1.864-7.522-11.009-10.862-24.519-19.229c-4.82-2.984-0.927-9.736,5.168-8.351l20.234,2.415c3.359,0.763,4.555-6.114,0.882-7.875c-14.198-6.804-28.897-10.098-53.864-7.799c-11.617-29.265-29.811-61.617-15.674-81.681c12.639-17.938,31.216-20.74,39.147,43.489c-5.002,3.107-11.215,5.031-11.332,13.024c7.201-2.845,11.207-1.399,14.791,0c17.912,6.998,35.462,21.826,52.982,37.309c3.739,3.303,8.413-1.718,6.991-6.034c-2.138-6.494-8.053-10.659-14.791-20.016c-3.239-4.495,5.03-7.045,10.886-6.876c13.849,0.396,22.886,8.268,35.177,11.218c4.483,1.076,9.741-1.964,6.917-6.917c-3.472-6.085-13.015-9.124-19.18-13.413c-4.357-3.029-3.025-7.132,2.697-6.602c3.905,0.361,8.478,2.271,13.908,1.767c9.946-0.925,7.717-7.169-0.883-9.566c-19.036-5.304-39.891-6.311-61.665-5.225c-43.837-8.358-31.554-84.887,0-90.363c29.571-5.132,62.966-13.339,99.928-32.156c32.668-5.429,64.835-12.446,92.939-33.85c48.106-14.469,111.903,16.113,204.241,149.695c3.926,5.681,15.819,9.94,9.524-6.351c-15.893-41.125-68.176-93.328-92.13-132.085c-24.581-39.774-14.34-61.243-39.957-91.247c-21.326-24.978-47.502-25.803-77.339-17.365c-23.461,6.634-39.234-7.117-52.98-31.273C318.42,87.525,265.838,64.927,210.333,65.331zM445.731,203.01c6.12,0,11.112,4.919,11.112,11.038c0,6.119-4.994,11.111-11.112,11.111s-11.038-4.994-11.038-11.111C434.693,207.929,439.613,203.01,445.731,203.01z";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment