public LightChannel(uint flags, RGBAPixel mat, RGBAPixel amb, uint color, uint alpha)
 {
     _flags = flags;
     _matColor = mat;
     _ambColor = amb;
     _color = new LightChannelControl(color) { _parent = this };
     _alpha = new LightChannelControl(alpha) { _parent = this };
 }
        // coloralpha - 1 if color, 2 if alpha
        public string GenerateLightShader(int index, LightChannelControl chan, string lightsName, int coloralpha)
        {
            string s = "";

            string swizzle = "xyzw";
            if (coloralpha == 1) swizzle = "xyz";
            else if (coloralpha == 2) swizzle = "w";

            if (chan.Attenuation == GXAttnFn.None)
            {
                // atten disabled
                switch (chan.DiffuseFunction)
                {
                    case GXDiffuseFn.Disabled:
                        w(ref s, "lacc.{0} += {1}[{2}].{3};\n", swizzle, lightsName, index * 5, swizzle);
                        break;
                    case GXDiffuseFn.Enabled:
                    case GXDiffuseFn.Clamped:
                        w(ref s, "ldir = normalize({0}[{1} + 3].xyz - pos.xyz);\n", lightsName, index * 5);
                        w(ref s, "lacc.{0} += {1}dot(ldir, _norm0)) * {2}[{3}].{4};\n", swizzle, chan.DiffuseFunction != GXDiffuseFn.Enabled ? "max(0.0f," : "(", lightsName, index * 5, swizzle);
                        break;
                }
            }
            else
            {
                // spec and spot
                if (chan.Attenuation == GXAttnFn.Spotlight)
                {
                    // spot
                    w(ref s, "ldir = {0}[{1} + 3].xyz - pos.xyz;\n", lightsName, index * 5);
                    w(ref s, "dist2 = dot(ldir, ldir);\n" +
                            "dist = sqrt(dist2);\n" +
                            "ldir = ldir / dist;\n" +
                            "attn = max(0.0f, dot(ldir, {0}[{1} + 4].xyz));\n", lightsName, index * 5);
                    w(ref s, "attn = max(0.0f, dot({0}[{1} + 1].xyz, float3(1.0f, attn, attn*attn))) / dot({2}[{3} + 2].xyz, float3(1.0f,dist,dist2));\n", lightsName, index * 5, lightsName, index * 5);
                }
                if (chan.Attenuation == GXAttnFn.Specular)
                {
                    // specular
                    w(ref s, "ldir = normalize({0}[{1} + 3].xyz);\n", lightsName, index * 5);
                    w(ref s, "attn = (dot(_norm0, ldir) >= 0.0f) ? max(0.0f, dot(_norm0, {0}[{1} + 4].xyz)) : 0.0f;\n", lightsName, index * 5);
                    w(ref s, "attn = max(0.0f, dot({0}[{1} + 1].xyz, float3(1,attn,attn*attn))) / dot({2}[{3} + 2].xyz, float3(1,attn,attn*attn));\n", lightsName, index * 5, lightsName, index * 5);
                }

                switch (chan.DiffuseFunction)
                {
                    case GXDiffuseFn.Disabled:
                        w(ref s, "lacc.{0} += attn * {1}[{2}].{3};\n", swizzle, lightsName, index * 5, swizzle);
                        break;
                    case GXDiffuseFn.Enabled:
                    case GXDiffuseFn.Clamped:
                        w(ref s, "lacc.{0} += attn * {1}dot(ldir, _norm0)) * {2}[{3}].{4};\n",
                        swizzle,
                        chan.DiffuseFunction != GXDiffuseFn.Enabled ? "max(0.0f," : "(",
                        lightsName,
                        index * 5,
                        swizzle);
                        break;
                }
            }
            w(ref s, "\n");
            return s;
        }