Updated TeaVM javascript engine

This commit is contained in:
Andrea Cavalli 2018-06-12 18:35:56 +02:00
parent 41c1fc9b82
commit 638200f6bb
7 changed files with 171 additions and 205 deletions

View File

@ -35,7 +35,7 @@ import org.teavm.jso.browser.Window;
import org.warp.picalculator.Main; import org.warp.picalculator.Main;
public class StorageUtils { public class StorageUtils {
private static final String basepath; public static final String basepath;
static { static {
String fullurl = Window.current().getLocation().getFullURL(); String fullurl = Window.current().getLocation().getFullURL();
if (fullurl.charAt(fullurl.length()-1) == '/') { if (fullurl.charAt(fullurl.length()-1) == '/') {

View File

@ -516,7 +516,7 @@ public class Keyboard {
} }
} }
private synchronized static void keyReleasedRaw(int row, int col) { public synchronized static void keyReleasedRaw(int row, int col) {
// KeyboardDebugScreen.keyX = row; // KeyboardDebugScreen.keyX = row;
// KeyboardDebugScreen.keyY = col; // KeyboardDebugScreen.keyY = col;
if (row == 1 && col == 1) { if (row == 1 && col == 1) {
@ -599,7 +599,7 @@ public class Keyboard {
{ Key.NONE, Key.NONE, Key.NONE } /* 7,7 */ { Key.NONE, Key.NONE, Key.NONE } /* 7,7 */
} }; } };
static synchronized void keyPressedRaw(int row, int col) { public static synchronized void keyPressedRaw(int row, int col) {
// KeyboardDebugScreen.keyX = row; // KeyboardDebugScreen.keyX = row;
// KeyboardDebugScreen.keyY = col; // KeyboardDebugScreen.keyY = col;
final Key k = keyMap[row][col][shift ? 1 : alpha ? 2 : 0]; final Key k = keyMap[row][col][shift ? 1 : alpha ? 2 : 0];

View File

@ -258,7 +258,7 @@ public class CPUFont implements BinaryFont {
return compressIndex(originalIndex); return compressIndex(originalIndex);
} }
private int compressIndex(int originalIndex) { protected int compressIndex(int originalIndex) {
int compressedIndex = 0; int compressedIndex = 0;
for (int i = 0; i < intervals.length; i += 3) { for (int i = 0; i < intervals.length; i += 3) {
if (intervals[i] > originalIndex) { if (intervals[i] > originalIndex) {

View File

@ -42,7 +42,7 @@ public class HtmlEngine implements GraphicEngine {
private RenderingLoop renderingLoop; private RenderingLoop renderingLoop;
private HtmlRenderer renderer; private HtmlRenderer renderer;
private int width = -1, height = -1; private int width = -1, height = -1;
private final int frameTime = (int) (1000d/5d); private final int frameTime = (int) (1000d/10d);
@Override @Override
public int[] getSize() { public int[] getSize() {
@ -133,30 +133,52 @@ public class HtmlEngine implements GraphicEngine {
HTMLButtonElement button = target.cast(); HTMLButtonElement button = target.cast();
new Thread(() -> { new Thread(() -> {
try { try {
if (Keyboard.alpha && !Keyboard.shift) { if (button.hasAttribute("keycode") && button.getAttribute("keycode").contains(",")) {
if (button.hasAttribute("keycodea")) { String code = button.getAttribute("keycode");
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodea"))); String[] coordinates = code.split(",", 2);
} else { boolean removeshift = Keyboard.shift && Integer.parseInt(coordinates[0]) != 0 && Integer.parseInt(coordinates[1]) != 0;
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode"))); boolean removealpha = Keyboard.alpha && Integer.parseInt(coordinates[0]) != 0 && Integer.parseInt(coordinates[1]) != 1;
Keyboard.keyPressedRaw(Integer.parseInt(coordinates[0]), Integer.parseInt(coordinates[1]));
if (removeshift) {
Keyboard.keyPressedRaw(0,0);
} }
} else if (!Keyboard.alpha && Keyboard.shift) { if (removealpha) {
if (button.hasAttribute("keycodes")) { Keyboard.keyPressedRaw(0,1);
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodes")));
} else {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
} }
} else if (Keyboard.alpha && Keyboard.shift) { Thread.sleep(100);
if (button.hasAttribute("keycodesa")) { Keyboard.keyReleasedRaw(Integer.parseInt(coordinates[0]), Integer.parseInt(coordinates[1]));
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodesa"))); if (removeshift) {
} else { Keyboard.keyReleasedRaw(0,0);
}
if (removealpha) {
Keyboard.keyReleasedRaw(0,1);
}
} else {
if (Keyboard.alpha && !Keyboard.shift) {
if (button.hasAttribute("keycodea")) {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodea")));
} else {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
}
} else if (!Keyboard.alpha && Keyboard.shift) {
if (button.hasAttribute("keycodes")) { if (button.hasAttribute("keycodes")) {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodes"))); Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodes")));
} else { } else {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode"))); Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
} }
} else if (Keyboard.alpha && Keyboard.shift) {
if (button.hasAttribute("keycodesa")) {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodesa")));
} else {
if (button.hasAttribute("keycodes")) {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodes")));
} else {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
}
}
} else {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
} }
} else {
Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
} }
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
@ -246,7 +268,7 @@ public class HtmlEngine implements GraphicEngine {
@Override @Override
public HtmlFont loadFont(String path, String fontName) throws IOException { public HtmlFont loadFont(String path, String fontName) throws IOException {
return new HtmlFont(path, fontName); return new HtmlFont(fontName);
} }
@Override @Override

View File

@ -2,17 +2,60 @@ package org.warp.picalculator.gui.graphicengine.html;
import java.io.IOException; import java.io.IOException;
import org.teavm.jso.browser.Window;
import org.teavm.jso.canvas.CanvasRenderingContext2D;
import org.teavm.jso.dom.html.HTMLCanvasElement;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.dom.html.HTMLImageElement;
import org.teavm.jso.typedarrays.Uint8ClampedArray;
import org.warp.picalculator.StaticVars;
import org.warp.picalculator.gui.graphicengine.GraphicEngine; import org.warp.picalculator.gui.graphicengine.GraphicEngine;
import org.warp.picalculator.gui.graphicengine.cpu.CPUFont; import org.warp.picalculator.gui.graphicengine.cpu.CPUFont;
public class HtmlFont extends CPUFont { public class HtmlFont extends CPUFont {
public HTMLCanvasElement imgEl;
public CanvasRenderingContext2D imgElCtx;
public HtmlFont(String fontName) throws IOException { public HtmlFont(String fontName) throws IOException {
super(fontName); super(fontName);
} HTMLDocument doc = Window.current().getDocument();
imgEl = doc.createElement("canvas").cast();
imgEl.setClassName("hidden");
doc.getBody().appendChild(imgEl);
imgElCtx = imgEl.getContext("2d").cast();
imgEl.setWidth(this.charW);
imgEl.setHeight(this.charH * intervalsTotalSize);
public HtmlFont(String path, String fontName) throws IOException { int screenPos = 0;
super(path, fontName);
int currentInt;
int currentIntBitPosition;
int bitData;
int j;
imgElCtx.clearRect(0, 0, imgEl.getWidth(), imgEl.getHeight());
imgElCtx.setFillStyle("#000");
int minBound = 0, maxBound = intervalsTotalSize-1;
System.out.println("charIndex:"+0);
System.out.println("minBound"+minBound);
System.out.println("maxBound"+maxBound);
for (int charIndex = minBound; charIndex < maxBound; charIndex++) {
for (int dy = 0; dy < charH; dy++) {
for (int dx = 0; dx < charW; dx++) {
j = dx;
final int bit = dx + dy * charW;
currentInt = (int) (Math.floor(bit) / (HtmlFont.intBits));
currentIntBitPosition = bit - (currentInt * HtmlFont.intBits);
final int charIdx = charIndex * charIntCount + currentInt;
if (charIdx >= 0 && charIdx < chars32.length) {
bitData = (chars32[charIdx] >> currentIntBitPosition) & 1;
if (bitData == 1) {
imgElCtx.fillRect( dx, charIndex*charH+dy, 1, 1 );
}
}
}
}
}
} }
@Override @Override

View File

@ -1,6 +1,8 @@
package org.warp.picalculator.gui.graphicengine.html; package org.warp.picalculator.gui.graphicengine.html;
import org.teavm.jso.canvas.CanvasImageSource;
import org.teavm.jso.canvas.CanvasRenderingContext2D; import org.teavm.jso.canvas.CanvasRenderingContext2D;
import org.teavm.jso.dom.html.HTMLImageElement;
import org.teavm.jso.typedarrays.Uint8ClampedArray; import org.teavm.jso.typedarrays.Uint8ClampedArray;
import org.warp.picalculator.StaticVars; import org.warp.picalculator.StaticVars;
import org.warp.picalculator.gui.graphicengine.Renderer; import org.warp.picalculator.gui.graphicengine.Renderer;
@ -138,151 +140,15 @@ public class HtmlRenderer implements Renderer {
} }
y0 = 0; y0 = 0;
} }
Uint8ClampedArray oldColors = g.getImageData(x0, y0, x1-x0, y1-y0).getData(); g.drawImage(currentSkin.getImgElement(), s0, t0, s1-s0, t1-t0, x0, y0, x1-x0, y1-y0);
for (double pixelX = 0; pixelX < x1 - x0; pixelX++) {
for (double pixelY = 0; pixelY < y1 - y0; pixelY++) {
final int imgx = (int) (x0 + pixelX);
final int imgy = (int) (y0 + pixelY);
final int oldindex = (int) (((pixelX)+(pixelY*(x1-x0))) * 4);
final int index = imgx + imgy;
if (index >= 0 && index < size[0]*size[1] && pixelX < size[0]) {
final int texx = (int) (pixelX / incrementX);
final int texy = (int) (pixelY / incrementY);
int expX = 0;
int expY = 0;
if (incrementX < 1) {
expX = (int) Math.round(1d / incrementX / 2d);
}
if (incrementY < 1) {
expY = (int) Math.round(1d / incrementY / 2d);
}
if (ENABLE_SUPERSAMPLING) {
final int[] newColors = new int[(1 + expX * 2) * (1 + expY * 2)];
for (int expXi = -expX; expXi <= expX; expXi++) {
for (int expYi = -expY; expYi <= expY; expYi++) {
final int skinIndex = (int) (s0 + (texx * (flippedX ? -1d : 1d) + (flippedX ? -(s0 - s1) - 1 : 0) + expXi) + (t0 + (texy * (flippedY ? -1d : 1d) + (flippedY ? -(t0 - t1) - 1 : 0) + expYi)) * currentSkin.skinSize[0]);
final int idx = (expXi + expX) + (expYi + expY) * (1 + expY * 2);
if (idx >= 0 && idx < newColors.length) {
newColors[idx] = getSkinColorAt(currentSkin.skinData, skinIndex);
}
}
}
newColor = joinColors(newColors);
} else {
final int skinIndex = (int) (s0 + (texx * (flippedX ? -1d : 1d) + (flippedX ? -(s0 - s1) - 1 : 0)) + (t0 + (texy * (flippedY ? -1d : 1d) + (flippedY ? -(t0 - t1) - 1 : 0))) * currentSkin.skinSize[0]);
newColor = getSkinColorAt(currentSkin.skinData, skinIndex);
}
if (transparent) {
if (ENABLE_TRANSPARENCY) {
int oldColorR = oldColors.get(oldindex+0) & 0xFF;
int oldColorG = oldColors.get(oldindex+1) & 0xFF;
int oldColorB = oldColors.get(oldindex+2) & 0xFF;
int oldColorA = 0xFF;
oldColor = (oldColorA << 24) | (oldColorR << 16) | (oldColorG << 8) | (oldColorB);
final double a2 = (newColor >> 24 & 0xFF) / 255f;
final double a1 = 1f - a2;
final int r = (int) ((oldColor >> 16 & 0xFF) * a1 + (newColor >> 16 & 0xFF) * a2);
final int gg = (int) ((oldColor >> 8 & 0xFF) * a1 + (newColor >> 8 & 0xFF) * a2);
final int b = (int) ((oldColor & 0xFF) * a1 + (newColor & 0xFF) * a2);
newColor = 0xFF000000 | r << 16 | gg << 8 | b;
}
}
if (!ENABLE_TRANSPARENCY) {
if (transparent && (((newColor >> 24) & 0xFF) < 0x02)) {
g.setFillStyle(clearColor);
} else {
g.setFillStyle(toHex8(newColor));
}
} else {
g.setFillStyle(toHex8(stackColors(oldColor, newColor)));
}
g.fillRect(imgx, imgy, 1, 1 );
}
}
}
} }
private int joinColors(int[] newColors) {
double a = 0;
double r = 0;
double g = 0;
double b = 0;
for (final int newColor : newColors) {
a += newColor >> 24 & 0xFF;
r += newColor >> 16 & 0xFF;
g += newColor >> 8 & 0xFF;
b += newColor & 0xFF;
}
return (int)(a / (double)newColors.length) << 24 | (int)(r / (double)newColors.length) << 16 | (int)(g / (double)newColors.length) << 8 | (int)(b / (double)newColors.length);
}
private int getSkinColorAt(int[] skinData, int skinIndex) {
int color = hexToInt(currentColor);
int newColor = 0;
if (skinIndex >= 0 && skinIndex < skinData.length) {
newColor = skinData[skinIndex] & 0xFFFFFFFF;
final int a = (int) ((double)((newColor >> 24 & 0xFF)) * ((double) (color >> 24 & 0xFF) / (double) 0xFF));
final int r = (int) ((double)((newColor >> 16 & 0xFF)) * ((double) (color >> 16 & 0xFF) / (double) 0xFF));
final int g = (int) ((double)((newColor >> 8 & 0xFF)) * ((double) (color >> 8 & 0xFF) / (double) 0xFF));
final int b = (int) ((double)((newColor & 0xFF)) * ((double) (color & 0xFF) / (double) 0xFF));
newColor = a << 24 | r << 16 | g << 8 | b;
}
return newColor;
}
@Override @Override
public void glFillColor(float x, float y, float width, float height) { public void glFillColor(float x, float y, float width, float height) {
final int[] size = e.getSize();
int color = hexToInt(currentColor);
x += StaticVars.screenPos[0]; x += StaticVars.screenPos[0];
y += StaticVars.screenPos[1]; y += StaticVars.screenPos[1];
g.setFillStyle(currentColor);
final int ix = (int) x; g.fillRect( x, y, width, height );
final int iy = (int) y;
final int iw = (int) width;
final int ih = (int) height;
int x0 = ix;
int y0 = iy;
int x1 = ix + iw;
int y1 = iy + ih;
if (ix >= size[0] || iy >= size[1]) {
return;
}
if (x0 < 0) {
x0 = 0;
}
if (x1 >= size[0]) {
x1 = size[0];
}
if (y0 < 0) {
y0 = 0;
}
if (y1 >= size[1]) {
y1 = size[1];
}
final int sizeW = size[0];
for (int px = x0; px < x1; px++) {
for (int py = y0; py < y1; py++) {
final int idx = (px) + (py) * sizeW;
if (px < sizeW && idx >= 0 && idx < size[0]*size[1]) {
Uint8ClampedArray oldColor = g.getImageData(px, py, 1, 1).getData();
int oldColorR = oldColor.get(0) & 0xFF;
int oldColorG = oldColor.get(1) & 0xFF;
int oldColorB = oldColor.get(2) & 0xFF;
int oldColorA = 0xFF;
int oldColorARGB = (oldColorA << 24) | (oldColorR << 16) | (oldColorG << 8) | (oldColorB);
g.setFillStyle(toHex(stackColors(oldColorARGB, color)));
g.fillRect( px, py, 1, 1 );
}
}
}
} }
@Override @Override
@ -295,49 +161,18 @@ public class HtmlRenderer implements Renderer {
x += StaticVars.screenPos[0]; x += StaticVars.screenPos[0];
y += StaticVars.screenPos[1]; y += StaticVars.screenPos[1];
final int ix = (int) x; f.imgElCtx.setGlobalCompositeOperation("source-in");
final int iy = (int) y; f.imgElCtx.setFillStyle(currentColor);
f.imgElCtx.fillRect(0, 0, f.imgEl.getWidth(), f.imgEl.getHeight());
final int[] text = f.getCharIndexes(textString); final int[] text = f.getCharIndexes(textString);
final int[] screenSize = e.getSize(); final int[] screenSize = e.getSize();
final int screenLength = screenSize[0]*screenSize[1];
int screenPos = 0;
int currentInt;
int currentIntBitPosition;
int bitData;
int cpos; int cpos;
int j;
final int l = text.length; final int l = text.length;
int color = hexToInt(currentColor);
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
cpos = (i * (f.charW)); cpos = (i * (f.charW));
final int charIndex = text[i]; final int charIndex = text[i];
for (int dy = 0; dy < f.charH; dy++) { g.drawImage(f.imgEl, 0, charIndex*f.charH, f.charW, f.charH, x+cpos, y, f.charW, f.charH);
for (int dx = 0; dx < f.charW; dx++) {
j = ix + cpos + dx;
if (j > 0 & j < screenSize[0]) {
final int bit = dx + dy * f.charW;
currentInt = (int) (Math.floor(bit) / (HtmlFont.intBits));
currentIntBitPosition = bit - (currentInt * HtmlFont.intBits);
final int charIdx = charIndex * f.charIntCount + currentInt;
if (charIdx >= 0 && charIdx < f.chars32.length) {
bitData = (f.chars32[charIdx] >> currentIntBitPosition) & 1;
screenPos = ix + cpos + dx + (iy + dy) * screenSize[0];
if (bitData == 1 & screenLength > screenPos & screenPos >= 0) {
Uint8ClampedArray oldColor = g.getImageData(ix+cpos+dx, iy+dy, 1, 1).getData();
int oldColorR = oldColor.get(0) & 0xFF;
int oldColorG = oldColor.get(1) & 0xFF;
int oldColorB = oldColor.get(2) & 0xFF;
int oldColorA = 0xFF;
int oldColorARGB = (oldColorA << 24) | (oldColorR << 16) | (oldColorG << 8) | (oldColorB);
g.setFillStyle(toHex(stackColors(oldColorARGB, color)));
g.fillRect( ix+cpos+dx, iy+dy, 1, 1 );
}
}
}
}
}
} }
} }

View File

@ -1,20 +1,86 @@
package org.warp.picalculator.gui.graphicengine.html; package org.warp.picalculator.gui.graphicengine.html;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException;
import org.teavm.jso.JSObject;
import org.teavm.jso.browser.Window;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.dom.html.HTMLImageElement;
import org.warp.picalculator.deps.StorageUtils;
import org.warp.picalculator.gui.graphicengine.GraphicEngine; import org.warp.picalculator.gui.graphicengine.GraphicEngine;
import org.warp.picalculator.gui.graphicengine.cpu.CPUSkin; import org.warp.picalculator.gui.graphicengine.Skin;
public class HtmlSkin extends CPUSkin { import ar.com.hjg.pngj.PngReader;
public class HtmlSkin implements Skin {
private String url;
private int[] skinSize;
private boolean initd;
private HTMLImageElement imgEl;
public HtmlSkin(String file) throws IOException { public HtmlSkin(String file) throws IOException {
super(file); load(file);
} }
@Override
public void use(GraphicEngine d) { public void use(GraphicEngine d) {
if (d instanceof HtmlEngine) { if (d instanceof HtmlEngine) {
if (!initd)
initialize(d);
((HtmlEngine) d).getRenderer().currentSkin = this; ((HtmlEngine) d).getRenderer().currentSkin = this;
} }
} }
@Override
public void load(String file) throws IOException {
if (!file.startsWith("/"))
file = "/"+file;
url = StorageUtils.basepath+file;
try {
PngReader r = new PngReader(StorageUtils.getResourceStream(file));
skinSize = new int[] { r.imgInfo.cols, r.imgInfo.rows };
r.close();
} catch (URISyntaxException e) {
IOException ex = new IOException();
ex.initCause(e);
throw ex;
}
}
@Override
public void initialize(GraphicEngine d) {
HTMLDocument doc = Window.current().getDocument();
imgEl = doc.createElement("img").cast();
imgEl.setSrc(url);
imgEl.setClassName("hidden");
doc.getBody().appendChild(imgEl);
initd = true;
}
@Override
public boolean isInitialized() {
return initd;
}
@Override
public int getSkinWidth() {
return skinSize[0];
}
@Override
public int getSkinHeight() {
return skinSize[1];
}
public final String getUrl() {
return url;
}
public final HTMLImageElement getImgElement() {
return imgEl;
}
} }