/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package com.bc.ceres.jai.opimage;
import com.bc.ceres.compiler.CodeMapper;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
public class ExpressionCodeGenerator {
private static final String HEAD_COMMENT = "" +
"/*\n" +
" * This is machine-genereated code, DO NOT EDIT!\n" +
" * Code generated by {0}.\n" +
" */\n";
private static final String HEAD_PART = "" +
"package {0};\n" +
"\n" +
"import javax.media.jai.ImageLayout;\n" +
"import javax.media.jai.PointOpImage;\n" +
"import javax.media.jai.PixelAccessor;\n" +
"import javax.media.jai.UnpackedImageData;\n" +
"import java.awt.Rectangle;\n" +
"import java.awt.image.Raster;\n" +
"import java.awt.image.WritableRaster;\n" +
"import java.util.Vector;\n" +
"import java.util.Map;\n" +
"import static java.lang.Math.*;\n" +
"\n" +
"public final class {1} extends PointOpImage '{'\n" +
"\n" +
" public {1}(Vector sources, Map config, ImageLayout layout) '{'\n" +
" super(sources, layout, config, true);\n" +
" // Set flag to permit in-place operation.\n" +
" permitInPlaceOperation();\n" +
" '}'\n" +
"\n" +
" protected void computeRect(Raster[] srcRasters,\n" +
" WritableRaster destRaster,\n" +
" Rectangle destRectangle) '{'\n" +
"\n";
private static final String SRC_DEF_PART = "" +
" final PixelAccessor src{0}Acc = new PixelAccessor(getSourceImage({0}));\n" +
" final UnpackedImageData src{0}Pixels = src{0}Acc.getPixels(srcRasters[{0}], destRectangle, srcRasters[{0}].getSampleModel().getDataType(), false);\n" +
" final int src{0}LineStride = src{0}Pixels.lineStride;\n" +
" final int src{0}PixelStride = src{0}Pixels.pixelStride;\n" +
" int src{0}LineOffset = src{0}Pixels.bandOffsets[0];\n" +
" final {1}[] src{0}Data = src{0}Pixels.get{2}Data(0);\n" +
"\n";
private static final String DST_DEF_PART = "" +
" final PixelAccessor destAcc = new PixelAccessor(this);\n" +
" final UnpackedImageData destPixels = destAcc.getPixels(destRaster, destRectangle, getSampleModel().getDataType(), true);\n" +
" final int destLineStride = destPixels.lineStride;\n" +
" final int destPixelStride = destPixels.pixelStride;\n" +
" int destLineOffset = destPixels.bandOffsets[0];\n" +
" final {1}[] destData = destPixels.get{2}Data(0);\n" +
"\n";
private static final String Y_LOOP_PART = "" +
" final int width = destRectangle.width;\n" +
" final int height = destRectangle.height;\n" +
"\n" +
" for (int y = 0; y < height; y++) {\n" +
"";
private static final String SRC_OFFS_PART = "" +
" int src{0}PixelOffset = src{0}LineOffset;\n" +
" src{0}LineOffset += src{0}LineStride;\n" +
"\n";
private static final String X_LOOP_PART = "" +
" int destPixelOffset = destLineOffset;\n" +
" destLineOffset += destLineStride;\n" +
"\n" +
" for (int x = 0; x < width; x++) {\n";
private static final String EXPR_VAR_PART = "" +
" final {1} _{0} = src{0}Data[src{0}PixelOffset];\n";
private static final String EXPR_PART = "" +
" destData[destPixelOffset] = ({0})({1});\n" +
"\n";
private static final String SRC_PIXEL_INC_PART = "" +
" src{0}PixelOffset += src{0}PixelStride;\n";
private static final String FINAL_PART = "" +
" destPixelOffset += destPixelStride;\n" +
" } // next x\n" +
" } // next y\n" +
"\n" +
" destAcc.setPixels(destPixels);\n" +
" }\n" +
"}\n";
public static ExpressionCode generate(String packageName,
String className,
Map<String, RenderedImage> sourceMap,
int dataType,
String expression) {
MyNameMapper mapper = new MyNameMapper(sourceMap);
CodeMapper.CodeMapping codeMapping = CodeMapper.mapCode(expression, mapper);
StringBuilder codeBuilder = new StringBuilder();
codeBuilder.append(MessageFormat.format(HEAD_COMMENT, ExpressionCodeGenerator.class.getName()));
codeBuilder.append(MessageFormat.format(HEAD_PART, packageName, className));
Vector<RenderedImage> sources = mapper.sources;
for (int i = 0; i < sources.size(); i++) {
String typeName = getTypeName(sources, i);
codeBuilder.append(MessageFormat.format(SRC_DEF_PART,
String.valueOf(i),
typeName,
getCamelCase(typeName)));
}
String dstTypeName = getTypeName(dataType);
codeBuilder.append(MessageFormat.format(DST_DEF_PART,
String.valueOf(sources.size()),
dstTypeName,
getCamelCase(dstTypeName)));
codeBuilder.append(Y_LOOP_PART);
for (int i = 0; i < sources.size(); i++) {
codeBuilder.append(MessageFormat.format(SRC_OFFS_PART, String.valueOf(i)));
}
codeBuilder.append(X_LOOP_PART);
for (int i = 0; i < sources.size(); i++) {
String typeName = getTypeName(sources, i);
codeBuilder.append(MessageFormat.format(EXPR_VAR_PART, String.valueOf(i), typeName));
}
codeBuilder.append(MessageFormat.format(EXPR_PART, dstTypeName, codeMapping.getMappedCode()));
for (int i = 0; i < sources.size(); i++) {
codeBuilder.append(MessageFormat.format(SRC_PIXEL_INC_PART, String.valueOf(i)));
}
codeBuilder.append(FINAL_PART);
return new ExpressionCode(packageName + "." + className, codeBuilder.toString(), sources);
}
private static String getTypeName(Vector<RenderedImage> sources, int i) {
return getTypeName(sources.get(i).getSampleModel().getDataType());
}
static String getCamelCase(String typeName) {
return Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
}
static String getTypeName(int type) {
String typeName;
if (type == DataBuffer.TYPE_BYTE) {
typeName = "byte";
} else if (type == DataBuffer.TYPE_SHORT) {
typeName = "short";
} else if (type == DataBuffer.TYPE_USHORT) {
typeName = "short";
} else if (type == DataBuffer.TYPE_INT) {
typeName = "int";
} else if (type == DataBuffer.TYPE_FLOAT) {
typeName = "float";
} else if (type == DataBuffer.TYPE_DOUBLE) {
typeName = "double";
} else {
typeName = "double";
}
return typeName;
}
private static class MyNameMapper implements CodeMapper.NameMapper {
private final Map<String, RenderedImage> imageMap;
private final Vector<RenderedImage> sources = new Vector<RenderedImage>(16);
private final Map<String, Integer> indexMap = new HashMap<String, Integer>(16);
private int counter;
public MyNameMapper(Map<String, RenderedImage> imageMap) {
this.imageMap = imageMap;
}
public String mapName(String name) {
boolean b = imageMap.containsKey(name);
if (!b) {
return null;
}
if (!indexMap.containsKey(name)) {
indexMap.put(name, counter++);
sources.add(imageMap.get(name));
}
RenderedImage image = imageMap.get(name);
if (image.getSampleModel().getDataType() == DataBuffer.TYPE_USHORT) {
return MessageFormat.format("(_{0} & 0xffff)", indexMap.get(name));
}
return MessageFormat.format("_{0}", indexMap.get(name));
}
}
}