import { StringEncoder, Timer } from '@uino/base-thing';
import { Utils } from '../common/Utils';
import { MathUtils } from '../math/MathUtils';
const __ = {
private: Symbol('private'),
}
const _spriteTypeName = StringEncoder.toText("<@secret Sprite>");
const _spritesName = StringEncoder.toText("<@secret sprites>");
const _watermarkEvent = StringEncoder.toText("<@secret __!water#mark*event@__>");
const _hideWatermarkEvent = StringEncoder.toText("<@secret __!hide!water#mark*event@__>");
/**
* @class Logo
* The logo.
* @memberof THING
*/
class Logo {
/**
* The logo controller.
*/
constructor() {
this[__.private] = {};
let _private = this[__.private];
_private.timer = new Timer({
interval: 500,
onInterval: () => {
this._check();
}
});
_private.options = {};
}
// #region Private
_createWatermarkStyle(text) {
let _private = this[__.private];
let renderer = Utils.createObject('CanvasRenderer');
renderer.resize(512, 512);
let options = {
size: 24,
type: 'Verdana',
color: [1, 1, 1],
shadowColor: [0, 0, 0],
shadowAngle: 30,
shadowDistance: 2,
};
let result = renderer.getTextRows(text, options);
if (!result) {
renderer.dispose();
return null;
}
renderer.resize(result.size[0], result.size[1]);
renderer.drawText(result, options);
let canvas = renderer.getContext();
let style = Utils.createObject('Style');
style.setOpacityOp(() => { return _PRO_ ? 0.05 : 0.08; });
style.setImage('Map', Utils.createObject('ImageTextureResource', { data: canvas }));
// Update options
_private.options['imageWidth'] = canvas.width;
_private.options['imageHeight'] = canvas.height;
renderer.dispose();
return style;
}
_removeWatermarkSprites() {
let sprites = this[_spritesName];
if (Utils.isArray(sprites)) {
sprites.forEach(sprite => {
sprite.dispose();
});
sprites.length = 0;
}
}
_createWatermarkSprites(rootNode, style, size, screenSize, imageSize) {
let width = screenSize[0];
let height = screenSize[1];
let spriteWidth = size[0];
let spriteHeight = size[1];
// Get image size
let imageWidth = imageSize[0];
let imageHeight = imageSize[1];
// Prepare to create sprites
this[_spritesName] = this[_spritesName] || [];
let sprites = this[_spritesName];
// Destroy previous sprites
this._removeWatermarkSprites();
// Hide sprite type to prevent cracker
for (let y = -height; y < height; y += spriteHeight) {
for (let x = -width; x < width; x += spriteWidth) {
let sprite = Utils.createObject(_spriteTypeName);
sprite.setScale([imageWidth, imageHeight, 1]);
sprite.setPosition([x, y, -1]);
sprite.setStyle(style);
sprite.setAttribute('Rotation', MathUtils.degToRad(30));
sprites.push(sprite);
rootNode.add(sprite);
}
}
}
_initOptions(options) {
let _private = this[__.private];
let rootNode = options['rootNode'];
let enable = Utils.parseValue(options['enable'], true);
let text = options['text'] || StringEncoder.toText("<@secret ThingJS by UINO>");
let width = options['width'] || 480;
let height = options['height'] || 320;
// Check text
if (!text) {
return;
}
// Create watermark style
let style = this._createWatermarkStyle(text);
if (!style) {
return;
}
// Setup options
_private.options['enable'] = enable;
_private.options['rootNode'] = rootNode;
_private.options['style'] = style;
_private.options['width'] = width;
_private.options['height'] = height;
}
_initEvents() {
let _private = this[__.private];
if (!_private.options['enable']) {
return;
}
// Get the application
let app = Utils.getCurrentApp();
// Hook secret event to wait for watermark image update
app.on(_watermarkEvent, async (ev) => {
let { scaleFacotr, opacity, width, height, data, text } = ev;
// Update image from text
if (text) {
// Create watermark style
let style = this._createWatermarkStyle(text);
if (!style) {
return;
}
// Update the style image
_private.options['style'] = style;
// Get the app viewport size
let app = Utils.getCurrentApp();
let size = app.size;
// Create sprites to show watermark
let { rootNode, width, height, imageWidth, imageHeight } = _private.options;
this._createWatermarkSprites(rootNode, style, [width, height], size, [imageWidth, imageHeight]);
}
// Update image from base64
else if (data) {
// Get the style image
let style = _private.options['style'];
// Get the texture image resource
let textureResource = style.getImage('Map');
if (!textureResource) {
return;
}
// If it's base64 format then need to convert to image resource type
if (Utils.isString(data)) {
let image = await Utils.loadBitmapImageFromBase64Async(data);
if (!image) {
return;
}
textureResource.setImage(image);
width = image.width;
height = image.height;
}
else if (width && height) {
textureResource.setImage({ width, height, data });
textureResource.enable('FlipY', true);
}
// Get the sprite scale
scaleFacotr = Utils.parseValue(scaleFacotr, 1);
let scale = [width * scaleFacotr, height * scaleFacotr, 1];
// Auto fit best size
while (true) {
if (scale[0] > 256 || scale[1] > 256) {
scale[0] *= 0.5;
scale[1] *= 0.5;
}
else {
break;
}
}
// Update sprite scale
let rootNode = _private.options['rootNode'];
rootNode.getChildren().forEach(sprite => {
sprite.setScale(scale);
});
}
// Update opacity value
if (Utils.isNumber(opacity)) {
// Get the style image
let style = _private.options['style'];
style.setOpacityOp(() => { return opacity; });
}
}, {
enumerable: false
});
// Hide watermark
app.on(_hideWatermarkEvent, (ev) => {
this._removeWatermarkSprites();
}, {
enumerable: false
});
}
_isVisible() {
let _private = this[__.private];
let rootNode = _private.options['rootNode'];
while (rootNode) {
if (!rootNode.getVisible()) {
return false;
}
rootNode = rootNode.getParent();
}
return true;
}
_forceShow() {
let _private = this[__.private];
let rootNode = _private.options['rootNode'];
while (rootNode) {
// We do not use interface to show to prevent cracker hook it
rootNode._visible = true;
rootNode._node.visible = true;
rootNode = rootNode.getParent();
}
}
_check() {
let _private = this[__.private];
let options = _private.options;
let enable = options['enable'];
if (enable) {
if (!this._isVisible()) {
let rootNode = options['rootNode'];
let children = rootNode.getChildren().slice(0);
children.forEach(child => {
child.dispose();
});
let style = options['style'];
let width = options['width'];
let height = options['height'];
let imageWidth = options['imageWidth'];
let imageHeight = options['imageHeight'];
let screenSize = app.size;
this._createWatermarkSprites(rootNode, style, [width, height], screenSize, [imageWidth, imageHeight]);
this._forceShow();
}
}
}
// #endregion
init(rootNode) {
let _private = this[__.private];
this._initOptions({ rootNode });
this._initEvents();
let app = Utils.getCurrentApp();
let size = app.size;
let { style, width, height, imageWidth, imageHeight } = _private.options;
this._createWatermarkSprites(rootNode, style, [width, height], size, [imageWidth, imageHeight]);
}
update(deltaTime) {
let _private = this[__.private];
// Convert seconds -> milliseconds
_private.timer.update(deltaTime * 1000);
}
}
export { Logo }