All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jmol.g3d.Text3D Maven / Gradle / Ivy

There is a newer version: 14.31.10
Show newest version
/* $RCSfile$
 * $Author: hansonr $
 * $Date: 2011-10-11 03:09:00 +0200 (mar., 11 oct. 2011) $
 * $Revision: 16309 $
 *
 * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
 *
 * Contact: [email protected]
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package org.jmol.g3d;

import java.util.Hashtable;
import java.util.Map;

import org.jmol.api.JmolRendererInterface;


/**
 * implementation for text rendering
 *

* uses java fonts by rendering into an offscreen buffer. * strings are rasterized and stored as a bitmap in an int[]. *

* needs work * * * @author Miguel, [email protected] */ public class Text3D { /* we have a few problems here a message is probably going to vary in size with z depth a message is probably going to be repeated by more than one atom fonts? just one? a restricted number? any font? if we want to support more than one then a fontindex is probably called for in order to prevent a hashtable lookup color - can be applied by the painter rep array of booleans - uncompressed array of bits - uncompressed - i like this some type of run-length, using bytes */ private int height; // this height is just ascent + descent ... no reason for leading private int ascent; private int width; private int mapWidth; private int size; private int[] bitmap; private boolean isInvalid; public int getWidth() { return width; } public static int plot(int x, int y, int z, int argb, String text, Font3D font3d, Graphics3D g3d, JmolRendererInterface jmolRenderer, boolean antialias) { if (text.length() == 0) return 0; //System.out.println(x + " " + y + " " + text); if (text.indexOf("= 0) return plotByCharacter(x, y, z, argb, text, font3d, g3d, jmolRenderer, antialias); int offset = font3d.getAscent(); //if (antialias) //offset += offset; y -= offset; //setColix has presumably been carried out for argb, and the two //are assumed to be both the same -- translucent or not. Text3D text3d = getText3D(x, y, g3d, text, font3d, antialias); if (text3d.isInvalid) return text3d.width; //TODO: text width/height are calculated 4x correct size here when antialiased. // this is wasteful, as it requires drawing larger than necessary images if (antialias && (argb & 0xC0C0C0) == 0) { // an interesting problem with antialiasing occurs if // the label is black or almost black. argb = argb | 0x040404; } if (jmolRenderer != null || (x < 0 || x + text3d.width > g3d.width || y < 0 || y + text3d.height > g3d.height)) plotClipped(x, y, z, argb, g3d, jmolRenderer, text3d.mapWidth, text3d.height, text3d.bitmap); else plotUnclipped(x, y, z, argb, g3d, text3d.mapWidth, text3d.height, text3d.bitmap); return text3d.width; } /** * * @param x * @param y * @param z * @param image * @param g3d * @param jmolRenderer * @param antialias UNUSED * @param argbBackground * @param width * @param height */ public static void plotImage(int x, int y, int z, Object image, Graphics3D g3d, JmolRendererInterface jmolRenderer, boolean antialias, int argbBackground, int width, int height) { boolean isBackground = (x == Integer.MIN_VALUE); int bgcolor = (isBackground ? g3d.bgcolor : argbBackground); /* * this was for transparent background, which we have disabled, I think, in Jmol 12 boolean haveTranslucent = false; PixelGrabber pg1 = new PixelGrabber(image, 0, 0, width0, height0, true); if (pg1.getColorModel().hasAlpha()) try { pg1.grabPixels(); int[] buffer = (int[]) pg1.getPixels(); for (int i = 0; i < buffer.length; i++) if ((buffer[i] & 0xFF00000) != 0xFF000000) { haveTranslucent = true; break; } System.out.println(buffer.length + " " + haveTranslucent + " " + pg1.getColorModel().hasAlpha()); } catch (InterruptedException e) { // impossible? return; } */ if (isBackground) { x = 0; z = Integer.MAX_VALUE - 1; width = g3d.width; height = g3d.height; } if (x + width <= 0 || x >= g3d.width || y + height <= 0 || y >= g3d.height) return; g3d.platform.checkOffscreenSize(width, height); int[] buffer = g3d.platform.apiPlatform.drawImageToBuffer(g3d.platform.graphicForText, g3d.platform.imageForText, image, width, height, isBackground ? bgcolor : 0); if (buffer == null) return; // not supported on this platform (yet) /* int n = 0; for (int i = 0; i < buffer.length; i++) { if ((buffer[i] & 0xFF000000) != 0xFF000000) { // System.out.println("testing " + i + " " + buffer[i]); n++; } } System.out.println(n + " transparent argbBackground=" + argbBackground); */ if (jmolRenderer != null || (x < 0 || x + width > g3d.width || y < 0 || y + height > g3d.height)) plotImageClipped(x, y, z, g3d, jmolRenderer, width, height, buffer, bgcolor); else plotImageUnClipped(x, y, z, g3d, width, height, buffer, bgcolor); return; } private static void plotImageClipped(int x, int y, int z, Graphics3D g3d, JmolRendererInterface jmolRenderer, int width, int height, int[] buffer, int bgcolor) { if (jmolRenderer == null) jmolRenderer = g3d; for (int i = 0, offset = 0; i < height; i++) { for (int j = 0; j < width; j++) { int argb = buffer[offset++]; if (argb != bgcolor && (argb & 0xFF000000) == 0xFF000000) jmolRenderer.plotPixelClippedNoSlab(argb, x + j, y + i, z); else if (argb == 0 && bgcolor != 0) jmolRenderer.plotPixelClippedNoSlab(bgcolor, x + j, y + i, z); } } } private static void plotImageUnClipped(int x, int y, int z, Graphics3D g3d, int textWidth, int textHeight, int[] buffer, int bgcolor) { int[] zbuf = g3d.zbuf; int renderWidth = g3d.width; int pbufOffset = y * renderWidth + x; int i = 0; int j = 0; int offset = 0; while (i < textHeight) { while (j < textWidth) { if (z < zbuf[pbufOffset]) { int argb = buffer[offset]; if (argb != bgcolor && (argb & 0xFF000000) == 0xFF000000) g3d.addPixel(pbufOffset, z, argb); else if (argb == 0 && bgcolor != 0) g3d.addPixel(pbufOffset, z, bgcolor); } ++offset; ++j; ++pbufOffset; } ++i; j -= textWidth; pbufOffset += (renderWidth - textWidth); } } private static int plotByCharacter(int x, int y, int z, int argb, String text, Font3D font3d, Graphics3D g3d, JmolRendererInterface jmolRenderer, boolean antialias) { //int subscale = 1; //could be something less than that int w = 0; int len = text.length(); int suboffset = (int)(font3d.getHeight() * 0.25); int supoffset = -(int)(font3d.getHeight() * 0.3); for (int i = 0; i < len; i++) { if (text.charAt(i) == '<') { if (i + 4 < len && text.substring(i, i + 5).equals("")) { i += 4; y += suboffset; continue; } if (i + 4 < len && text.substring(i, i + 5).equals("")) { i += 4; y += supoffset; continue; } if (i + 5 < len && text.substring(i, i + 6).equals("")) { i += 5; y -= suboffset; continue; } if (i + 5 < len && text.substring(i, i + 6).equals("")) { i += 5; y -= supoffset; continue; } } int width = plot(x + w, y, z, argb, text.substring(i, i + 1), font3d, g3d, jmolRenderer, antialias); w += width; } //System.out.println("w=" + w); return w; } private static void plotUnclipped(int x, int y, int z, int argb, Graphics3D g3d, int textWidth, int textHeight, int[] bitmap) { int offset = 0; int shiftregister = 0; int i = 0, j = 0; int[] zbuf = g3d.zbuf; int renderWidth = g3d.width; int pbufOffset = y * renderWidth + x; while (i < textHeight) { while (j < textWidth) { if ((offset & 31) == 0) shiftregister = bitmap[offset >> 5]; if (shiftregister == 0) { int skip = 32 - (offset & 31); j += skip; offset += skip; pbufOffset += skip; continue; } if (shiftregister < 0 && z < zbuf[pbufOffset]) g3d.addPixel(pbufOffset, z, argb); shiftregister <<= 1; ++offset; ++j; ++pbufOffset; } while (j >= textWidth) { ++i; j -= textWidth; pbufOffset += (renderWidth - textWidth); } } } private static void plotClipped(int x, int y, int z, int argb, Graphics3D g3d, JmolRendererInterface jmolRenderer, int textWidth, int textHeight, int[] bitmap) { if (jmolRenderer == null) jmolRenderer = g3d; int offset = 0; int shiftregister = 0; int i = 0, j = 0; while (i < textHeight) { while (j < textWidth) { if ((offset & 31) == 0) shiftregister = bitmap[offset >> 5]; if (shiftregister == 0) { int skip = 32 - (offset & 31); j += skip; offset += skip; continue; } if (shiftregister < 0) jmolRenderer.plotPixelClippedNoSlab(argb, x + j, y + i, z); shiftregister <<= 1; ++offset; ++j; } while (j >= textWidth) { ++i; j -= textWidth; } } } /** * * @param text * @param font3d */ private Text3D(String text, Font3D font3d) { ascent = font3d.getAscent(); height = font3d.getHeight(); width = font3d.stringWidth(text); if (width == 0) return; //System.out.println(text + " " + antialias + " " + ascent + " " + height + " " + width ); mapWidth = width; size = mapWidth * height; } /** * * @param pixels * */ private void rasterize(int[] pixels) { if (pixels == null) return; int bitmapSize = (size + 31) >> 5; bitmap = new int[bitmapSize]; int offset, shifter; for (offset = shifter = 0; offset < size; ++offset, shifter <<= 1) { if ((pixels[offset] & 0x00FFFFFF) != 0) shifter |= 1; if ((offset & 31) == 31) bitmap[offset >> 5] = shifter; } if ((offset & 31) != 0) { shifter <<= 31 - (offset & 31); bitmap[offset >> 5] = shifter; } /* // error checking // shifter error checking boolean[] bits = new boolean[size]; for (int i = 0; i < size; ++i) bits[i] = (pixels[i] & 0x00FFFFFF) != 0; // for (offset = 0; offset < size; ++offset, shifter <<= 1) { if ((offset & 31) == 0) shifter = bitmap[offset >> 5]; if (shifter < 0) { if (!bits[offset]) { Logger.debug("false positive @" + offset); Logger.debug("size = " + size); } } else { if (bits[offset]) { Logger.debug("false negative @" + offset); Logger.debug("size = " + size); } } } // error checking */ } private final static Map> htFont3d = new Hashtable>(); private final static Map> htFont3dAntialias = new Hashtable>(); private static boolean working; public synchronized static void clearFontCache() { if (working) return; htFont3d.clear(); htFont3dAntialias.clear(); } // FIXME mth // we have a synchronization issue/race condition here with multiple // so only one Text3D can be generated at a time // Jmol 11.7.8: caching and rasterization only carried out if the font is // valid -- that is in the rectangle to be plotted. private synchronized static Text3D getText3D(int x, int y, Graphics3D g3d, String text, Font3D font3d, boolean antialias) { working = true; Map> ht = (antialias ? htFont3dAntialias : htFont3d); Map htForThisFont = ht.get(font3d); Text3D text3d = null; boolean newFont = false; boolean newText = false; if (htForThisFont != null) { text3d = htForThisFont.get(text); } else { htForThisFont = new Hashtable(); newFont = true; } if (text3d == null) { text3d = new Text3D(text, font3d); newText = true; } text3d.isInvalid = (text3d.width == 0 || x + text3d.width <= 0 || x >= g3d.width || y + text3d.height <= 0 || y >= g3d.height); if (text3d.isInvalid) return text3d; if (newFont) ht.put(font3d, htForThisFont); if (newText) { //System.out.println(text + " " + x + " " + text3d.width + " " + g3d.width + " " + y + " " + g3d.height); text3d.setBitmap(text, font3d, g3d); htForThisFont.put(text, text3d); } working = false; return text3d; } private void setBitmap(String text, Font3D font3d, Graphics3D g3d) { g3d.platform.checkOffscreenSize(mapWidth, height); rasterize(g3d.apiPlatform.getTextPixels(text, font3d, g3d.platform.graphicForText, g3d.platform.imageForText, mapWidth, height, ascent)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy