1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.renderscript;
18
19
20import android.util.Log;
21
22
23/**
24 * <p>ProgramFragmentFixedFunction is a helper class that provides
25 * a way to make a simple fragment shader without writing any
26 * GLSL code. This class allows for display of constant color, interpolated
27 * color from the vertex shader, or combinations of the both
28 * blended with results of up to two texture lookups.</p
29 *
30 **/
31public class ProgramFragmentFixedFunction extends ProgramFragment {
32    ProgramFragmentFixedFunction(int id, RenderScript rs) {
33        super(id, rs);
34    }
35
36    static class InternalBuilder extends BaseProgramBuilder {
37        public InternalBuilder(RenderScript rs) {
38            super(rs);
39        }
40
41        /**
42         * Creates ProgramFragmentFixedFunction from the current state
43         * of the builder
44         *
45         * @return  ProgramFragmentFixedFunction
46         */
47        public ProgramFragmentFixedFunction create() {
48            mRS.validate();
49            int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
50            int idx = 0;
51
52            for (int i=0; i < mInputCount; i++) {
53                tmp[idx++] = ProgramParam.INPUT.mID;
54                tmp[idx++] = mInputs[i].getID();
55            }
56            for (int i=0; i < mOutputCount; i++) {
57                tmp[idx++] = ProgramParam.OUTPUT.mID;
58                tmp[idx++] = mOutputs[i].getID();
59            }
60            for (int i=0; i < mConstantCount; i++) {
61                tmp[idx++] = ProgramParam.CONSTANT.mID;
62                tmp[idx++] = mConstants[i].getID();
63            }
64            for (int i=0; i < mTextureCount; i++) {
65                tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
66                tmp[idx++] = mTextureTypes[i].mID;
67            }
68
69            int id = mRS.nProgramFragmentCreate(mShader, tmp);
70            ProgramFragmentFixedFunction pf = new ProgramFragmentFixedFunction(id, mRS);
71            initProgram(pf);
72            return pf;
73        }
74    }
75
76    public static class Builder {
77        public static final int MAX_TEXTURE = 2;
78        int mNumTextures;
79        boolean mPointSpriteEnable;
80        boolean mVaryingColorEnable;
81        String mShader;
82        RenderScript mRS;
83
84        /**
85         * EnvMode describes how textures are combined with the existing
86         * color in the fixed function fragment shader
87         *
88         **/
89        public enum EnvMode {
90            REPLACE (1),
91            MODULATE (2),
92            DECAL (3);
93
94            int mID;
95            EnvMode(int id) {
96                mID = id;
97            }
98        }
99
100        /**
101         * Format describes the pixel format of textures in the fixed
102         * function fragment shader and how they are sampled
103         *
104         **/
105        public enum Format {
106            ALPHA (1),
107            LUMINANCE_ALPHA (2),
108            RGB (3),
109            RGBA (4);
110
111            int mID;
112            Format(int id) {
113                mID = id;
114            }
115        }
116
117        private class Slot {
118            EnvMode env;
119            Format format;
120            Slot(EnvMode _env, Format _fmt) {
121                env = _env;
122                format = _fmt;
123            }
124        }
125        Slot[] mSlots;
126
127        private void buildShaderString() {
128            mShader  = "//rs_shader_internal\n";
129            mShader += "varying lowp vec4 varColor;\n";
130            mShader += "varying vec2 varTex0;\n";
131
132            mShader += "void main() {\n";
133            if (mVaryingColorEnable) {
134                mShader += "  lowp vec4 col = varColor;\n";
135            } else {
136                mShader += "  lowp vec4 col = UNI_Color;\n";
137            }
138
139            if (mNumTextures != 0) {
140                if (mPointSpriteEnable) {
141                    mShader += "  vec2 t0 = gl_PointCoord;\n";
142                } else {
143                    mShader += "  vec2 t0 = varTex0.xy;\n";
144                }
145            }
146
147            for(int i = 0; i < mNumTextures; i ++) {
148                switch(mSlots[i].env) {
149                case REPLACE:
150                    switch (mSlots[i].format) {
151                    case ALPHA:
152                        mShader += "  col.a = texture2D(UNI_Tex0, t0).a;\n";
153                        break;
154                    case LUMINANCE_ALPHA:
155                        mShader += "  col.rgba = texture2D(UNI_Tex0, t0).rgba;\n";
156                        break;
157                    case RGB:
158                        mShader += "  col.rgb = texture2D(UNI_Tex0, t0).rgb;\n";
159                        break;
160                    case RGBA:
161                        mShader += "  col.rgba = texture2D(UNI_Tex0, t0).rgba;\n";
162                        break;
163                    }
164                    break;
165                case MODULATE:
166                    switch (mSlots[i].format) {
167                    case ALPHA:
168                        mShader += "  col.a *= texture2D(UNI_Tex0, t0).a;\n";
169                        break;
170                    case LUMINANCE_ALPHA:
171                        mShader += "  col.rgba *= texture2D(UNI_Tex0, t0).rgba;\n";
172                        break;
173                    case RGB:
174                        mShader += "  col.rgb *= texture2D(UNI_Tex0, t0).rgb;\n";
175                        break;
176                    case RGBA:
177                        mShader += "  col.rgba *= texture2D(UNI_Tex0, t0).rgba;\n";
178                        break;
179                    }
180                    break;
181                case DECAL:
182                    mShader += "  col = texture2D(UNI_Tex0, t0);\n";
183                    break;
184                }
185            }
186
187            mShader += "  gl_FragColor = col;\n";
188            mShader += "}\n";
189        }
190
191        /**
192         * Creates a builder for fixed function fragment program
193         *
194         * @param rs Context to which the program will belong.
195         */
196        public Builder(RenderScript rs) {
197            mRS = rs;
198            mSlots = new Slot[MAX_TEXTURE];
199            mPointSpriteEnable = false;
200        }
201
202        /**
203         * Adds a texture to be fetched as part of the fixed function
204         * fragment program
205         *
206         * @param env specifies how the texture is combined with the
207         *            current color
208         * @param fmt specifies the format of the texture and how its
209         *            components will be used to combine with the
210         *            current color
211         * @param slot index of the texture to apply the operations on
212         *
213         * @return this
214         */
215        public Builder setTexture(EnvMode env, Format fmt, int slot)
216            throws IllegalArgumentException {
217            if((slot < 0) || (slot >= MAX_TEXTURE)) {
218                throw new IllegalArgumentException("MAX_TEXTURE exceeded.");
219            }
220            mSlots[slot] = new Slot(env, fmt);
221            return this;
222        }
223
224        /**
225         * Specifies whether the texture coordinate passed from the
226         * vertex program is replaced with an openGL internal point
227         * sprite texture coordinate
228         *
229         **/
230        public Builder setPointSpriteTexCoordinateReplacement(boolean enable) {
231            mPointSpriteEnable = enable;
232            return this;
233        }
234
235        /**
236         * Specifies whether the varying color passed from the vertex
237         * program or the constant color set on the fragment program is
238         * used in the final color calculation in the fixed function
239         * fragment shader
240         *
241         **/
242        public Builder setVaryingColor(boolean enable) {
243            mVaryingColorEnable = enable;
244            return this;
245        }
246
247        /**
248        * Creates the fixed function fragment program from the current
249        * state of the builder.
250        *
251        */
252        public ProgramFragmentFixedFunction create() {
253            InternalBuilder sb = new InternalBuilder(mRS);
254            mNumTextures = 0;
255            for(int i = 0; i < MAX_TEXTURE; i ++) {
256                if(mSlots[i] != null) {
257                    mNumTextures ++;
258                }
259            }
260            buildShaderString();
261            sb.setShader(mShader);
262
263            Type constType = null;
264            if (!mVaryingColorEnable) {
265                Element.Builder b = new Element.Builder(mRS);
266                b.add(Element.F32_4(mRS), "Color");
267                Type.Builder typeBuilder = new Type.Builder(mRS, b.create());
268                typeBuilder.setX(1);
269                constType = typeBuilder.create();
270                sb.addConstant(constType);
271            }
272            for (int i = 0; i < mNumTextures; i ++) {
273                sb.addTexture(TextureType.TEXTURE_2D);
274            }
275
276            ProgramFragmentFixedFunction pf = sb.create();
277            pf.mTextureCount = MAX_TEXTURE;
278            if (!mVaryingColorEnable) {
279                Allocation constantData = Allocation.createTyped(mRS,constType);
280                FieldPacker fp = new FieldPacker(16);
281                Float4 f4 = new Float4(1.f, 1.f, 1.f, 1.f);
282                fp.addF32(f4);
283                constantData.setFromFieldPacker(0, fp);
284                pf.bindConstants(constantData, 0);
285            }
286            return pf;
287        }
288    }
289}
290
291
292
293
294