@awayjs/graphics
Version:
AwayJS graphics classes
205 lines (189 loc) • 6.11 kB
text/typescript
import { IMaterial, IMaterialFactory } from '@awayjs/renderer';
import { BitmapImage2D, Image2D } from '@awayjs/stage';
import { FillType } from '../data/FillType';
import { SegmentedPath } from '../data/SegmentedPath';
import { ShapeMatrix } from '../data/ShapeData';
import { ShapeStyle } from './ShapeStyle';
const IDENTITY_MATRIX: ShapeMatrix = { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 };
export class StyleUtils {
public static processStyle(style: any, isLineStyle: boolean, isMorph: boolean, factory: IMaterialFactory): ShapeStyle {
const shapeStyle: ShapeStyle = style;
if (isMorph) {
shapeStyle.morph = this.processMorphStyle(style, isLineStyle);
}
if (isLineStyle) {
shapeStyle.miterLimit = (style.miterLimitFactor || 1.5) * 2;
if (!style.color && style.hasFill) {
const fillStyle = this.processStyle(style.fillStyle, false, false, factory);
shapeStyle.type = fillStyle.type;
shapeStyle.transform = fillStyle.transform;
shapeStyle.colors = fillStyle.colors;
shapeStyle.ratios = fillStyle.ratios;
shapeStyle.focalPoint = fillStyle.focalPoint;
shapeStyle.bitmapId = fillStyle.bitmapId;
shapeStyle.material = fillStyle.material;
shapeStyle.repeat = fillStyle.repeat;
style.fillStyle = null;
return shapeStyle;
} else {
shapeStyle.type = FillType.Solid;
return shapeStyle;
}
}
if (style.type === undefined || style.type === FillType.Solid) {
return shapeStyle;
}
let scale: number = 1;
switch (style.type) {
case FillType.LinearGradient:
case FillType.RadialGradient:
case FillType.FocalRadialGradient: {
const records = style.records;
const colors = shapeStyle.colors = [];
const ratios = shapeStyle.ratios = [];
for (let i = 0; i < records.length; i++) {
const record = records[i];
if (ratios.length == 0 || ratios[ratios.length - 1] != record.ratio) {
colors.push(record.color);
ratios.push(record.ratio);
}
}
scale = 1;
break;
}
case FillType.RepeatingBitmap:
case FillType.ClippedBitmap:
case FillType.NonsmoothedRepeatingBitmap:
case FillType.NonsmoothedClippedBitmap:
shapeStyle.smooth =
(
style.type !== FillType.NonsmoothedRepeatingBitmap &&
style.type !== FillType.NonsmoothedClippedBitmap
);
shapeStyle.repeat =
(
style.type !== FillType.ClippedBitmap &&
style.type !== FillType.NonsmoothedClippedBitmap
);
/*var index = dependencies.indexOf(style.bitmapId);
if (index === -1) {
index = dependencies.length;
dependencies.push(style.bitmapId);
}*/
shapeStyle.material = this.getMaterial(style.bitmapId, factory);
scale = 1 / 20;
break;
default:
console.log('shape parser encountered invalid fill style ' + style.type);
}
if (!style.matrix) {
shapeStyle.transform = IDENTITY_MATRIX;
return shapeStyle;
}
const matrix = style.matrix;
shapeStyle.transform = {
a: matrix.a * scale,
b: matrix.b * scale,
c: matrix.c * scale,
d: matrix.d * scale,
tx: matrix.tx / 20,
ty: matrix.ty / 20
};
// null data that's unused from here on out
style.matrix = null;
return shapeStyle;
}
private static getMaterial(bitmapIndex: number, factory: IMaterialFactory): IMaterial {
let material: IMaterial = factory.mapMatsForBitmaps[bitmapIndex];
if (!material) {
let myImage: Image2D = <Image2D> factory.awaySymbols[bitmapIndex];
if (!myImage)
myImage = new BitmapImage2D(512, 512, true, 0xff0000ff, true);
material = factory.createMaterial(myImage);
material.alphaBlending = true;
material.useColorTransform = true;
material.bothSides = true;
factory.mapMatsForBitmaps[bitmapIndex] = material;
}
return material;
}
public static processMorphStyle(style: any, isLineStyle: boolean): ShapeStyle {
const morphStyle: ShapeStyle = Object.create(style);
if (isLineStyle) {
morphStyle.width = style.widthMorph;
if (!style.color && style.hasFill) {
const fillStyle = this.processMorphStyle(style.fillStyle, false);
morphStyle.transform = fillStyle.transform;
morphStyle.colors = fillStyle.colors;
morphStyle.ratios = fillStyle.ratios;
return morphStyle;
} else {
morphStyle.color = style.colorMorph;
return morphStyle;
}
}
if (style.type === undefined) {
return morphStyle;
}
if (style.type === FillType.Solid) {
morphStyle.color = style.colorMorph;
return morphStyle;
}
let scale = 1;
switch (style.type) {
case FillType.LinearGradient:
case FillType.RadialGradient:
case FillType.FocalRadialGradient: {
const records = style.records;
const colors = morphStyle.colors = [];
const ratios = morphStyle.ratios = [];
for (let i = 0; i < records.length; i++) {
const record = records[i];
colors.push(record.colorMorph);
ratios.push(record.ratioMorph);
}
scale = 1;
break;
}
case FillType.RepeatingBitmap:
case FillType.ClippedBitmap:
case FillType.NonsmoothedRepeatingBitmap:
case FillType.NonsmoothedClippedBitmap:
scale = 1 / 20;
break;
default:
console.log('shape parser encountered invalid fill style');
}
if (!style.matrix) {
morphStyle.transform = IDENTITY_MATRIX;
return morphStyle;
}
const matrix = style.matrixMorph;
morphStyle.transform = {
a: (matrix.a * scale),
b: (matrix.b * scale),
c: (matrix.c * scale),
d: (matrix.d * scale),
tx: matrix.tx / 20,
ty: matrix.ty / 20
};
return morphStyle;
}
/*
* Paths are stored in 2-dimensional arrays. Each of the inner arrays contains
* all the paths for a certain fill or line style.
*/
public static createPathsList(styles: any[], isLineStyle: boolean, isMorph: boolean,
factory: IMaterialFactory): SegmentedPath[] {
const paths: SegmentedPath[] = [];
for (let i = 0; i < styles.length; i++) {
const style = this.processStyle(styles[i], isLineStyle, isMorph, factory);
if (!isLineStyle) {
paths[i] = new SegmentedPath(style, null);
} else {
paths[i] = new SegmentedPath(null, style);
}
}
return paths;
}
}