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