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