# AGAL multitexture shader

Inspired by the great blog post from Devon_O on conversion of GLSL (OpenGL) shaders to AGAL shaders, I decided to pick one of the examples available on Shader Toy website and to my suprise it wasn't that hard to get it working. I wanted to put the example with code on the Wonderfl but I can't get it running over there so I decided to put it here. And while I put it here, why not add just few additional words about shaders in AGAL...

*http://sierakowski.eu/list-of-tips/113-agal-multitexture-shader.html*

So here is the shader itself. The original GLSL source is available here under the 'multitexture' name: http://www.iquilezles.org/apps/shadertoy/

As always the most difficult are the initial steps. To get started I advise to read an article from Adobe explaining what the AGAL is, what are Vertex and Fragment programs, registers, available op-codes and AGALMiniAssembler: http://www.adobe.com/devnet/flashplayer/articles/what-is-agal.html. This article is not comprehensive enough and leaves you with many questions and unfortunately I couldn't find any additional information on Adobe websites explaining AGAL in greater detail. Anyway it is good enough to get you started. Additional handy information about registers could be found here: http://www.saltgames.com/2011/agal-registers/

So now when you know all the basics and want to try creating some shaders based on one of many of the GLSL examples available on internet, read a great article from Devon_O on his blog: http://blog.onebyonedesign.com/actionscript/learning-agal-with-agalmacroassembler-and-opengl-examples/. If you read it attentively, you shouldn't have any problems understanding it as it guides you step by step how to do it.

Just to make it easier to get the whole picture of the registers and the way how to populate them from ActionScript level, take a look at the figure below. [Update: here is a pdf version]

Also take a look at these images from the Adobe article listing all available opcodes:

And here is the shader itself, I left the comments so you can easily find out how I got there (if you carefully followed instructions given by Devon).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
/* //GLSL: ///////////////////////////////////////////////////////// vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; // a rotozoom vec2 cst = vec2( cos(.5*time), sin(.5*time) ); mat2 rot = 0.5*cst.x*mat2(cst.x,-cst.y,cst.y,cst.x); vec3 col1 = texture2D(tex0,rot*p).xyz; // scroll vec3 col2 = texture2D(tex1,0.5*p+sin(0.1*time)).xyz; // blend layers vec3 col = col2*col1; gl_FragColor = vec4(col,1.0); //CONSTANTS: //////////////////////////////////////////////////// fc0 = [ 1, 1, 1, 1 ] fc1 = [ .5 * mTime, .1 * mTime, 2, 0 ] fc2 = [ sin(.5 * mTime), cos(.5 * mTime), sin(.1 * mTime), .5 ] ///////////////////////////////////////////////////////////////// */ //Step 1: ft1 = vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; mov ft1, v0 mul ft1.xy, ft1.xy, fc1.z div ft1.xy, ft1.xy, fc0.xy sub ft1.xy, ft1.xy, fc0.x //Step2: ft2 = vec2 cst = vec2( cos(.5*time), sin(.5*time) ); mov ft2.x, fc2.y mov ft2.y, fc2.x //Step3: ft3 = mat2 rot = 0.5*cst.x*mat2(cst.x,-cst.y,cst.y,cst.x); mov ft0.x, fc2.w mul ft0.x, ft0.x, ft2.x mov ft3.x, ft2.x mul ft3.x, ft3.x, ft0.x mov ft3.y, fc1.w sub ft3.y, ft3.y, ft2.y mul ft3.y, ft3.y, ft0.x mov ft3.z, ft2.y mul ft3.z, ft3.z, ft0.x mov ft3.w, ft2.x mul ft3.w, ft3.w, ft0.x //Step4: ft4 = rot * p mul ft0.x, ft3.x, ft1.x mul ft0.y, ft3.y, ft1.y mul ft0.z, ft3.z, ft1.x mul ft0.w, ft3.w, ft1.y add ft4.x, ft0.x, ft0.y add ft4.y, ft0.z, ft0.w mov ft4.zw, fc0.zw //Step5: ft5 = vec3 col1 = texture2D(tex0,rot*p).xyz; tex ft5, ft4, fs0<2d, repeat, linear, nomip> //Step6: ft6 = vec3 col2 = texture2D(tex1,0.5*p+sin(0.1*time)).xyz; mov ft0, fc0 mul ft0, ft1, fc2.w add ft0, ft0, fc2.z tex ft6, ft0, fs1<2d, repeat, linear, nomip> //Step7 ft7 = vec3 col = col2*col1; mul ft7, ft6, ft5 //Step8 gl_FragColor = vec4(col,1.0); mov oc, ft7 |

Constants are uploaded to registers in onTick method:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
if ( !mContext3d ) return; mContext3d.clear ( 0, 0, 0, 1 ); mContext3d.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 0, mMatrix, true); //fc0 = [ 1, 1, 1, 1 ] mContext3d.setProgramConstantsFromVector( Context3DProgramType.FRAGMENT, 0, Vector.<Number>( [ 1, 1, 1, 1 ]) ); //fc1 = [ .5 * mTime, .1 * mTime, 2, 0 ] mContext3d.setProgramConstantsFromVector( Context3DProgramType.FRAGMENT, 1, Vector.<Number>( [ .5 * mTime, .1 * mTime, 2, 0 ]) ); //fc2 = [ sin(.5 * mTime), cos(.5 * mTime), sin(.1 * mTime), .5 ] mContext3d.setProgramConstantsFromVector( Context3DProgramType.FRAGMENT, 2, Vector.<Number>( [ Math.sin(.5 * mTime), Math.cos(.5 * mTime), Math.sin(.1 * mTime), .5 ]) ); mContext3d.drawTriangles(mIndexBuffer); mContext3d.present(); mTime += .025; |

The full source code is available on wondefl (but doesn't work for no obvious reason): http://wonderfl.net/c/xZs3

or on the GitHub: https://github.com/wsierakowski/stage3d/blob/master/shader-multitexture/Main.as

## Comments imported from the original article @sierakowski.eu