Compare commits

..

2 Commits

Author SHA1 Message Date
AncTe
7cf2e370f2
Merge df8328c33b into 820dc5bf4c 2025-09-17 08:16:52 +00:00
df8328c33b feat: fog weather & refactor: rain weather 2025-09-17 16:16:35 +08:00
23 changed files with 296 additions and 188 deletions

View File

@ -1,6 +1,8 @@
import { logger } from '@motajs/common';
import { MotaOffscreenCanvas2D } from '@motajs/render-core';
import { SizedCanvasImageSource } from '@motajs/render-elements';
import {
MotaOffscreenCanvas2D,
SizedCanvasImageSource
} from '@motajs/render-core';
// 经过测试https://www.measurethat.net/Benchmarks/Show/30741/1/drawimage-img-vs-canvas-vs-bitmap-cropping-fix-loading
// 得出结论ImageBitmap和Canvas的绘制性能不如Image于是直接画Image就行所以缓存基本上就是存Image

View File

@ -1,7 +1,6 @@
import { RenderAdapter } from '@motajs/render-core';
import { RenderAdapter, SizedCanvasImageSource } from '@motajs/render-core';
import { logger } from '@motajs/common';
import { ILayerRenderExtends, Layer, LayerMovingRenderable } from './layer';
import { SizedCanvasImageSource } from '@motajs/render-elements';
import EventEmitter from 'eventemitter3';
import { texture } from './cache';
import { TimingFn } from 'mutate-animate';

View File

@ -4,9 +4,9 @@ import {
RenderItem,
RenderItemPosition,
MotaOffscreenCanvas2D,
Transform
Transform,
SizedCanvasImageSource
} from '@motajs/render-core';
import { SizedCanvasImageSource } from '@motajs/render-elements';
import { isNil } from 'lodash-es';
import { RenderableData, AutotileRenderable, texture } from './cache';
import { IAnimateFrame, renderEmits } from './frame';

View File

@ -1,5 +1,5 @@
import { BaseProps, TagDefine } from '@motajs/render-vue';
import { Transform } from '@motajs/render-core';
import { CanvasStyle, Transform } from '@motajs/render-core';
import {
ILayerGroupRenderExtends,
FloorLayer,
@ -10,7 +10,6 @@ import {
import { EAnimateEvent } from './animate';
import { EIconEvent, EWinskinEvent } from './misc';
import { IEnemyCollection } from '@motajs/types';
import { CanvasStyle } from '@motajs/render-elements';
export interface AnimateProps extends BaseProps {}

View File

@ -22,6 +22,7 @@ export abstract class EffectBase<T> {
this.program = program;
this.shader = shader;
shader.useProgram(program);
this.initProgram(program, options);
}

View File

@ -8,7 +8,14 @@ import {
onTick
} from '@motajs/render';
import { WeatherController } from '../weather';
import { defineComponent, onMounted, onUnmounted, reactive, ref } from 'vue';
import {
defineComponent,
onMounted,
onUnmounted,
reactive,
ref,
shallowRef
} from 'vue';
import { Textbox, Tip } from '../components';
import { GameUI } from '@motajs/system-ui';
import {
@ -76,7 +83,7 @@ const MainScene = defineComponent(() => {
width: 480
};
const map = ref<LayerGroup>();
const map = shallowRef<LayerGroup>();
const hideStatus = ref(false);
const locked = ref(false);
const weather = new WeatherController();

View File

@ -1,10 +1,11 @@
import { WeatherController } from './controller';
import { CloudWeather, RainWeather, SunWeather } from './presets';
import { CloudWeather, FogWeather, RainWeather, SunWeather } from './presets';
export function createWeather() {
WeatherController.register('cloud', CloudWeather);
WeatherController.register('rain', RainWeather);
WeatherController.register('sun', SunWeather);
WeatherController.register('fog', FogWeather);
// WeatherController.register('snow', SnowWeather);
}

View File

@ -1,83 +1,9 @@
import { MotaOffscreenCanvas2D, Sprite } from '@motajs/render-core';
import { Weather } from '../weather';
import { CloudLike } from './cloudLike';
import { SizedCanvasImageSource } from '@motajs/render-core';
export class CloudWeather extends Weather<Sprite> {
/** 云层的不透明度 */
private alpha: number = 0;
/** 水平速度 */
private vx: number = 0;
/** 竖直速度 */
private vy: number = 0;
/** 水平位置 */
private cx: number = 0;
/** 竖直位置 */
private cy: number = 0;
/** 云层移动的最大速度 */
private maxSpeed: number = 1;
/** 云层图像 */
private image: HTMLImageElement | null = null;
/** 上一次执行速度变换的时刻 */
private lastTick = 0;
private drawCloud(canvas: MotaOffscreenCanvas2D) {
const ctx = canvas.ctx;
if (!this.image) return;
ctx.globalAlpha = this.alpha;
const { width, height } = this.image;
for (let x = -1; x < 2; x++) {
for (let y = -1; y < 2; y++) {
const dx = x * width + this.cx;
const dy = y * height + this.cy;
if (dx > canvas.width || dy > canvas.height) continue;
if (dx + width < 0 || dy + height < 0) continue;
ctx.drawImage(this.image, dx, dy, width, height);
}
}
}
tick(time: number): void {
if (!this.element || !this.image) return;
this.element.update();
const dt = time - this.lastTick;
this.lastTick = time;
if (dt > 100) return;
const dvx = (Math.random() - 0.5) * this.level * 10;
const dvy = (Math.random() - 0.5) * this.level * 10;
const addx = (dvx * dt) / 1000;
const addy = (dvy * dt) / 1000;
if (Math.sign(addx) === Math.sign(this.vx)) {
const ratio = Math.sqrt(
(this.maxSpeed - Math.abs(this.vx)) / this.maxSpeed
);
const value = Math.abs(addx) * ratio;
this.vx += value * Math.sign(addx);
} else {
this.vx += addx;
}
if (Math.sign(addy) === Math.sign(this.vy)) {
const ratio = Math.sqrt(
(this.maxSpeed - Math.abs(this.vy)) / this.maxSpeed
);
const value = Math.abs(addy) * ratio;
this.vy += value * Math.sign(addy);
} else {
this.vy += addy;
}
this.cx += (this.vx * dt) / 1000;
this.cy += (this.vy * dt) / 1000;
this.cx %= this.image.width;
this.cy %= this.image.height;
}
createElement(level: number): Sprite {
const element = new Sprite('static', true);
element.setRenderFn(canvas => this.drawCloud(canvas));
this.maxSpeed = Math.sqrt(level) * 100;
this.vx = ((Math.random() - 0.5) * this.maxSpeed) / 2;
this.vy = ((Math.random() - 0.5) * this.maxSpeed) / 2;
this.alpha = Math.sqrt(level) / 10;
this.image = core.material.images.images['cloud.png'];
return element;
export class CloudWeather extends CloudLike {
getImage(): SizedCanvasImageSource | null {
return core.material.images.images['cloud.png'] ?? null;
}
onDestroy(): void {}

View File

@ -0,0 +1,88 @@
import { MotaOffscreenCanvas2D, Sprite } from '@motajs/render-core';
import { Weather } from '../weather';
import { SizedCanvasImageSource } from '@motajs/render-core';
export abstract class CloudLike extends Weather<Sprite> {
/** 不透明度 */
private alpha: number = 0;
/** 水平速度 */
private vx: number = 0;
/** 竖直速度 */
private vy: number = 0;
/** 水平位置 */
private cx: number = 0;
/** 竖直位置 */
private cy: number = 0;
/** 移动的最大速度 */
private maxSpeed: number = 1;
/** 上一次执行速度变换的时刻 */
private lastTick = 0;
/** 绘制天气使用的图片 */
private image: SizedCanvasImageSource | null = null;
/**
* 使
*/
abstract getImage(): SizedCanvasImageSource | null;
private drawImage(canvas: MotaOffscreenCanvas2D) {
const ctx = canvas.ctx;
if (!this.image) return;
ctx.globalAlpha = this.alpha;
const { width, height } = this.image;
for (let x = -1; x < 2; x++) {
for (let y = -1; y < 2; y++) {
const dx = x * width + this.cx;
const dy = y * height + this.cy;
if (dx > canvas.width || dy > canvas.height) continue;
if (dx + width < 0 || dy + height < 0) continue;
ctx.drawImage(this.image, dx, dy, width, height);
}
}
}
tick(time: number): void {
if (!this.element || !this.image) return;
this.element.update();
const dt = time - this.lastTick;
this.lastTick = time;
if (dt > 100) return;
const dvx = (Math.random() - 0.5) * this.level * 10;
const dvy = (Math.random() - 0.5) * this.level * 10;
const addx = (dvx * dt) / 1000;
const addy = (dvy * dt) / 1000;
if (Math.sign(addx) === Math.sign(this.vx)) {
const ratio = Math.sqrt(
(this.maxSpeed - Math.abs(this.vx)) / this.maxSpeed
);
const value = Math.abs(addx) * ratio;
this.vx += value * Math.sign(addx);
} else {
this.vx += addx;
}
if (Math.sign(addy) === Math.sign(this.vy)) {
const ratio = Math.sqrt(
(this.maxSpeed - Math.abs(this.vy)) / this.maxSpeed
);
const value = Math.abs(addy) * ratio;
this.vy += value * Math.sign(addy);
} else {
this.vy += addy;
}
this.cx += (this.vx * dt) / 1000;
this.cy += (this.vy * dt) / 1000;
this.cx %= this.image.width;
this.cy %= this.image.height;
}
createElement(level: number): Sprite {
const element = new Sprite('static', true);
element.setRenderFn(canvas => this.drawImage(canvas));
this.maxSpeed = Math.sqrt(level) * 100;
this.vx = ((Math.random() - 0.5) * this.maxSpeed) / 2;
this.vy = ((Math.random() - 0.5) * this.maxSpeed) / 2;
this.alpha = Math.sqrt(level) / 10;
this.image = this.getImage();
return element;
}
}

View File

@ -0,0 +1,35 @@
import { MotaOffscreenCanvas2D } from '@motajs/render-core';
import { CloudLike } from './cloudLike';
import { SizedCanvasImageSource } from '@motajs/render-core';
export class FogWeather extends CloudLike {
/** 雾天气的图像比较小,因此将四个进行合并 */
private static mergedFog: MotaOffscreenCanvas2D | null = null;
getImage(): SizedCanvasImageSource | null {
if (FogWeather.mergedFog) {
return FogWeather.mergedFog.canvas;
} else {
return FogWeather.mergeFog();
}
}
onDestroy(): void {}
/**
* 2x2
*/
static mergeFog() {
const image = core.material.images.images['fog.png'];
if (!image) return null;
const { width, height } = image;
this.mergedFog = new MotaOffscreenCanvas2D();
this.mergedFog.size(width * 2, height * 2);
const ctx = this.mergedFog.ctx;
ctx.drawImage(image, 0, 0, width, width);
ctx.drawImage(image, width, 0, width, width);
ctx.drawImage(image, 0, height, width, width);
ctx.drawImage(image, width, height, width, width);
return this.mergedFog.canvas;
}
}

View File

@ -1,4 +1,6 @@
export * from './cloud';
export * from './cloudLike';
export * from './fog';
export * from './rain';
export * from './snow';
export * from './sun';

View File

@ -1,8 +1,9 @@
import {
Shader,
ShaderProgram,
IShaderUniform,
UniformType
UniformType,
MotaOffscreenCanvas2D,
GL2
} from '@motajs/render';
import { Weather } from '../weather';
@ -73,24 +74,61 @@ void main() {
vec2 texPos = (pos + 1.0) / 2.0;
texPos.y = 1.0 - texPos.y;
vec4 tex = texture(u_sampler, texPos);
outColor = mix(u_color, tex, 0.9);
outColor = mix(u_color, tex, 0.8);
}
`;
/** 雨滴顶点坐标 */
const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
export class RainWeather extends Weather<Shader> {
/** 下雨流程的 uniform 变量 */
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
/** 使用的着色器程序 */
private program: ShaderProgram | null = null;
interface RainCreateData {
/** 进度变量 */
readonly uProgress: IShaderUniform<UniformType.Uniform1f> | null;
/** 下雨着色器程序 */
readonly program: ShaderProgram;
}
class RainShader extends GL2 {
/** 下雨程序 */
private rainProgram: ShaderProgram | null = null;
/** 背景程序 */
private backProgram: ShaderProgram | null = null;
create(level: number): RainCreateData {
const gl = this.gl;
const program = this.createProgram(ShaderProgram);
program.fs(rainFs);
program.vs(rainVs);
program.requestCompile();
this.useProgram(program);
const pos = program.defineAttribArray('a_rainVertex');
program.defineAttribArray('a_offset');
program.defineAttribArray('a_data');
program.defineUniform('u_color', this.UNIFORM_4f);
const uProgress = program.defineUniform('u_progress', this.UNIFORM_1f);
program.mode(this.DRAW_ARRAYS_INSTANCED);
if (pos) {
pos.buffer(vertex, gl.STATIC_DRAW);
pos.pointer(2, gl.FLOAT, false, 0, 0);
pos.enable();
}
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * level);
this.generateRainPath(level, program);
this.rainProgram = program;
this.backProgram = this.createProgram(ShaderProgram);
this.backProgram.requestCompile();
return { uProgress, program };
}
/**
*
* @param num
*/
generateRainPath(level: number, program: ShaderProgram, shader: Shader) {
generateRainPath(level: number, program: ShaderProgram) {
const num = level * 100;
const angle = (((Math.random() - 0.5) * Math.PI) / 30) * level;
const deviation = (Math.PI / 180) * (12 - level);
@ -98,8 +136,8 @@ export class RainWeather extends Weather<Shader> {
const aOffset = program.getAttribArray('a_offset');
const aData = program.getAttribArray('a_data');
const color = program.getUniform<UniformType.Uniform4f>('u_color');
const gl = shader.gl;
if (!aOffset || !aData) return;
const gl = this.gl;
if (!aOffset || !aData || !color) return;
const tan = Math.tan(angle);
@ -135,52 +173,47 @@ export class RainWeather extends Weather<Shader> {
aData.enable();
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, num);
color?.set(1, 1, 1, 0.1);
color.set(1, 1, 1, 0.1);
}
createElement(level: number): Shader {
const shader = new Shader();
const gl = shader.gl;
shader.size(480, 480);
protected drawScene(
canvas: MotaOffscreenCanvas2D,
gl: WebGL2RenderingContext
): void {
const program1 = this.backProgram;
const program2 = this.rainProgram;
if (!program1 || !program2) return;
this.useProgram(program1);
program1.texTexture('u_sampler', canvas.canvas);
this.draw(gl, program1);
this.useProgram(program2);
program2.texTexture('u_sampler', canvas.canvas);
this.draw(gl, program2);
}
}
export class RainWeather extends Weather<GL2> {
/** 下雨流程的 uniform 变量 */
private progress: IShaderUniform<UniformType.Uniform1f> | null = null;
/** 下雨着色器程序 */
private program: ShaderProgram | null = null;
createElement(level: number): GL2 {
const shader = new RainShader();
shader.setHD(true);
shader.setZIndex(100);
const program = shader.createProgram(ShaderProgram);
program.fs(rainFs);
program.vs(rainVs);
program.requestCompile();
const pos = program.defineAttribArray('a_rainVertex');
program.defineAttribArray('a_offset');
program.defineAttribArray('a_data');
program.defineUniform('u_progress', shader.UNIFORM_1f);
program.defineUniform('u_color', shader.UNIFORM_4f);
program.mode(shader.DRAW_ARRAYS_INSTANCED);
shader.useProgram(program);
if (pos) {
pos.buffer(vertex, gl.STATIC_DRAW);
pos.pointer(2, gl.FLOAT, false, 0, 0);
pos.enable();
}
program.paramArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, 100 * this.level);
this.progress = program.getUniform<UniformType.Uniform1f>('u_progress');
this.generateRainPath(level, program, shader);
const { uProgress, program } = shader.create(level);
this.progress = uProgress;
this.program = program;
return shader;
}
tick(timestamp: number): void {
if (!this.element) return;
if (!this.element || !this.program) return;
this.element.update();
const time = 5000 - 400 * this.level;
const progress = (timestamp % time) / time;
this.progress?.set(progress);
}
onDestroy(): void {
if (!this.element || !this.program) return;
this.element.deleteProgram(this.program);
}
onDestroy(): void {}
}

View File

@ -576,14 +576,6 @@ export function loadDefaultResource() {
] = res.resource;
});
});
const weathers: (keyof Weather)[] = ['fog'];
weathers.forEach(v => {
const res = LoadTask.add('material', `material/${v}.png`);
res.once('load', res => {
// @ts-expect-error 需要赋值
core.animateFrame.weather[v] = res.resource;
});
});
// animates
{
const res = LoadTask.add(
@ -619,7 +611,6 @@ export async function loadCompressedResource() {
HTMLImageElement
>[];
materialImages.push('keyboard');
const weathers: (keyof Weather)[] = ['fog'];
Object.entries(list).forEach(v => {
const [uri, list] = v;
@ -696,9 +687,6 @@ export async function loadCompressedResource() {
HTMLImageElement
>
] = image;
} else if (weathers.some(v => name === v + '.png')) {
// @ts-expect-error 需要赋值
core.animateFrame.weather[v] = image;
}
}

View File

@ -4,6 +4,7 @@ import { MotaOffscreenCanvas2D } from './canvas2d';
import { ERenderItemEvent, RenderItem, RenderItemPosition } from './item';
import { Transform } from './transform';
import { isWebGL2Supported } from './utils';
import { SizedCanvasImageSource } from './types';
export interface IGL2ProgramPrefix {
readonly VERTEX: string;
@ -170,23 +171,34 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
super(type, false);
this.canvas = document.createElement('canvas');
this.gl = this.canvas.getContext('webgl2')!;
const gl = this.canvas.getContext('webgl2')!;
this.gl = gl;
if (!GL2.support) {
this.canvas.width = 0;
this.canvas.height = 0;
} else {
const num = this.gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS);
const num = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
if (typeof num === 'number') {
this.MAX_TEXTURE_COUNT = num;
}
}
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
this.init();
}
private init() {
const gl = this.gl;
if (!gl) return;
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
gl.depthFunc(gl.LEQUAL);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
}
onResize(scale: number): void {
this.sizeGL(this.width, this.height);
super.onResize(scale);
this.sizeGL(this.width, this.height);
}
setHD(hd: boolean): void {
@ -201,9 +213,10 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
private sizeGL(width: number, height: number) {
const ratio = this.highResolution ? devicePixelRatio : 1;
const scale = ratio * this.cache.scale;
const scale = ratio * this.scale;
this.canvas.width = width * scale;
this.canvas.height = height * scale;
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
}
protected render(
@ -218,12 +231,10 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
// 清空画布
const gl = this.gl;
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clearDepth(1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
this.program.ready();
this.drawScene(canvas, gl, this.program, transform);
this.drawScene(canvas, gl, transform);
canvas.clear();
canvas.ctx.drawImage(this.canvas, 0, 0, this.width, this.height);
@ -239,7 +250,6 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
protected abstract drawScene(
canvas: MotaOffscreenCanvas2D,
gl: WebGL2RenderingContext,
program: GL2Program,
transform: Transform
): void;
@ -252,6 +262,7 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
const indices = program.usingIndices;
const param = program.getDrawParams(program.renderMode);
if (!param) return;
program.ready();
switch (program.renderMode) {
case RenderMode.Arrays: {
const { mode, first, count } = param as DrawArraysParam;
@ -308,7 +319,6 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.bindFramebuffer(gl.FRAMEBUFFER, buffer);
if (clear) {
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clearDepth(1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
@ -404,15 +414,6 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
this.canvas.remove();
super.destroy();
}
private init() {
const gl = this.gl;
if (!gl) return;
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.depthFunc(gl.LEQUAL);
}
}
type _U1 = [x0: number];
@ -727,6 +728,7 @@ class ShaderUniform<T extends UniformType> implements IShaderUniform<T> {
set(...params: UniformSetFn[T]): void {
// 因为ts类型推导的限制类型肯定正确但是推导不出所以这里直接 as any 屏蔽掉类型推导
this.gl.useProgram(this.program.program);
const [x0, x1, x2, x3] = params as any[];
switch (this.type) {
case UniformType.Uniform1f:
@ -815,6 +817,7 @@ class ShaderAttrib<T extends AttribType> implements IShaderAttrib<T> {
set(...params: AttribSetFn[T]) {
// 因为ts类型推导的限制类型肯定正确但是推导不出所以这里直接 as any 屏蔽掉类型推导
this.gl.useProgram(this.program.program);
const [x0, x1, x2, x3] = params as any[];
switch (this.type) {
case AttribType.Attrib1f:
@ -878,6 +881,7 @@ class ShaderAttribArray implements IShaderAttribArray {
): void;
buffer(data: any, usage: any, srcOffset?: any, length?: any): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.data);
if (typeof srcOffset === 'number') {
gl.bufferData(gl.ARRAY_BUFFER, data, usage, srcOffset, length);
@ -895,6 +899,7 @@ class ShaderAttribArray implements IShaderAttribArray {
): void;
sub(dstOffset: any, data: any, offset?: any, length?: any): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.data);
if (typeof offset === 'number') {
gl.bufferSubData(gl.ARRAY_BUFFER, dstOffset, data, offset, length);
@ -911,6 +916,7 @@ class ShaderAttribArray implements IShaderAttribArray {
p4: GLintptr
): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.data);
gl.vertexAttribPointer(this.location, p0, p1, p2, p3, p4);
}
@ -922,20 +928,24 @@ class ShaderAttribArray implements IShaderAttribArray {
offset: GLintptr
): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.data);
gl.vertexAttribIPointer(this.location, size, type, stride, offset);
}
divisor(divisor: number): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.vertexAttribDivisor(this.location, divisor);
}
enable(): void {
this.gl.useProgram(this.program.program);
this.gl.enableVertexAttribArray(this.location);
}
disable(): void {
this.gl.useProgram(this.program.program);
this.gl.disableVertexAttribArray(this.location);
}
}
@ -956,6 +966,7 @@ class ShaderIndices implements IShaderIndices {
): void;
buffer(p0: any, p1: any, p2?: any, p3?: any): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.data);
if (typeof p2 === 'number') {
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, p0, p1, p2, p3);
@ -973,6 +984,7 @@ class ShaderIndices implements IShaderIndices {
): void;
sub(p0: any, p1: any, p2?: any, p3?: any): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.data);
if (typeof p2 === 'number') {
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, p0, p1, p2, p3);
@ -991,6 +1003,7 @@ class ShaderUniformMatrix implements IShaderUniformMatrix {
) {}
set(x2: GLboolean, x3: Float32List, x4?: number, x5?: number): void {
this.gl.useProgram(this.program.program);
switch (this.type) {
case UniformMatrix.UMatrix2x2:
this.gl.uniformMatrix2fv(this.location, x2, x3, x4, x5);
@ -1037,6 +1050,7 @@ class ShaderUniformBlock implements IShaderUniformBlock {
set(srcData: ArrayBufferView, srcOffset: number, length?: number): void;
set(srcData: unknown, srcOffset?: unknown, length?: unknown): void {
const gl = this.gl;
gl.useProgram(this.program.program);
const buffer = this.buffer;
gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
if (srcOffset !== void 0) {
@ -1065,6 +1079,7 @@ class ShaderTexture2D implements IShaderTexture2D {
set(source: TexImageSource): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.activeTexture(gl.TEXTURE0 + this.index);
gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
@ -1096,6 +1111,7 @@ class ShaderTexture2D implements IShaderTexture2D {
height: number
): void {
const gl = this.gl;
gl.useProgram(this.program.program);
gl.activeTexture(gl.TEXTURE0 + this.index);
gl.bindTexture(gl.TEXTURE_2D, this.texture);
@ -1191,8 +1207,6 @@ export class GL2Program extends EventEmitter<ShaderProgramEvent> {
/** 当前正在使用的顶点索引数组 */
usingIndices: IShaderIndices | null = null;
/** 着色器内容是否是默认内容,可以用于优化空着色器 */
modified: boolean = false;
/** 渲染模式 */
renderMode: RenderMode = RenderMode.Elements;
@ -1376,7 +1390,6 @@ export class GL2Program extends EventEmitter<ShaderProgramEvent> {
vs(vs: string) {
this.vertex = this.prefix.VERTEX + vs;
this.shaderDirty = true;
this.modified = true;
}
/**
@ -1386,7 +1399,6 @@ export class GL2Program extends EventEmitter<ShaderProgramEvent> {
fs(fs: string) {
this.fragment = this.prefix.FRAGMENT + fs;
this.shaderDirty = true;
this.modified = true;
}
/**
@ -1671,6 +1683,24 @@ export class GL2Program extends EventEmitter<ShaderProgramEvent> {
return obj;
}
/**
* 使 sub set
* @param program 使
* @param texture
* @param source
* @returns
*/
texTexture(texture: string, source: SizedCanvasImageSource) {
const tex = this.getTexture(texture);
if (!tex) return false;
if (tex.width === source.width && tex.height === source.height) {
tex.sub(source, 0, 0, source.width, source.height);
} else {
tex.set(source);
}
return true;
}
/**
* 使 {@link GL2.deleteProgram}
*/

View File

@ -8,4 +8,5 @@ export * from './render';
export * from './shader';
export * from './sprite';
export * from './transform';
export * from './types';
export * from './utils';

View File

@ -1,5 +1,6 @@
import { MotaOffscreenCanvas2D } from './canvas2d';
import { EGL2Event, GL2, GL2Program, IGL2ProgramPrefix } from './gl2';
import { RenderItemPosition } from './item';
const SHADER_PREFIX: IGL2ProgramPrefix = {
VERTEX: /* glsl */ `#version 300 es
@ -38,20 +39,17 @@ export interface EShaderEvent extends EGL2Event {}
export class Shader<E extends EShaderEvent = EShaderEvent> extends GL2<
EShaderEvent | E
> {
constructor(type: RenderItemPosition = 'static') {
super(type);
}
protected drawScene(
canvas: MotaOffscreenCanvas2D,
gl: WebGL2RenderingContext,
program: GL2Program
gl: WebGL2RenderingContext
): void {
if (!program.modified) return;
const tex = program.getTexture('u_sampler');
if (!tex) return;
const c = canvas.canvas;
if (tex.width === c.width && tex.height === c.height) {
tex.sub(c, 0, 0, c.width, c.height);
} else {
tex.set(c);
}
const program = this.program;
if (!program) return;
program.texTexture('u_sampler', canvas.canvas);
this.draw(gl, program);
}
}
@ -63,9 +61,6 @@ export class ShaderProgram extends GL2Program {
super(gl2, vs, fs);
if (!vs) this.vs(DEFAULT_VS);
if (!fs) this.fs(DEFAULT_FS);
if (!vs && !fs) {
this.modified = false;
}
}
ready(): boolean {

View File

@ -2,11 +2,11 @@ import {
Transform,
ERenderItemEvent,
RenderItem,
MotaOffscreenCanvas2D
MotaOffscreenCanvas2D,
CanvasStyle
} from '@motajs/render-core';
import { logger } from '@motajs/common';
import { clamp, isEqual, isNil } from 'lodash-es';
import { CanvasStyle } from './types';
export type CircleParams = [
cx?: number,

View File

@ -1,3 +1,2 @@
export * from './graphics';
export * from './misc';
export * from './types';

View File

@ -7,11 +7,11 @@ import {
ElementLocator,
ElementScale,
CustomContainerRenderFn,
CustomContainerPropagateFn
CustomContainerPropagateFn,
CanvasStyle
} from '@motajs/render-core';
import {
BezierParams,
CanvasStyle,
CircleParams,
EllipseParams,
ILineProperty,

View File

@ -130,6 +130,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"cloud.png",
"def.png",
"exp.png",
"fog.png",
"hero1.png",
"hero2.png",
"hp.png",

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -118,6 +118,7 @@ type ImageIds =
| 'cloud.png'
| 'def.png'
| 'exp.png'
| 'fog.png'
| 'hero1.png'
| 'hero2.png'
| 'hp.png'