diff --git a/src/App.tsx b/src/App.tsx index c8212b77..30e5e23f 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,18 +1,9 @@ import React from 'react'; import './App.css'; import { vec3, vec4 } from "./render/math"; -import {} from "./render/webgl/WebGLTexture"; -// eslint-disable-next-line -function App() { - - let a: vec3 = new vec3([1, 1, 1]); - let b: vec3 = new vec3([3, 2, 1]); - let c: vec3 = new vec3([2, 3, 1]); - let d: vec3 = new vec3([1, 2, 3]); - let ab: vec3 = vec3.difference(b, a); +function App() { - ab.print(); return (
sasa diff --git a/src/render/math/Util.ts b/src/render/math/Util.ts new file mode 100755 index 00000000..1f3cd2e6 --- /dev/null +++ b/src/render/math/Util.ts @@ -0,0 +1,29 @@ +export class Util { + /** + * 判断参数x是否是2的n次方,即x是不是1、2、4、8、16、32、64、..... + * @param x + * @returns + */ + public static isPowerOfTwo(x: number) { + return (x & (x - 1)) === 0; + } + + /** + * 取下一个2的n次方数 + * 如果x为3,则返回4 + * 如果x为4,则返回4 + * 如果x为5,则返回8 + * @param x + * @returns + */ + public static getNextPowerOfTwo(x: number): number { + if (x <= 0) { + throw new Error("参数必须要大于0!") + } + --x; + for (var i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; + } +} \ No newline at end of file diff --git a/src/render/math/index.ts b/src/render/math/index.ts index 70ee1c92..3bb2a9ef 100755 --- a/src/render/math/index.ts +++ b/src/render/math/index.ts @@ -2,4 +2,5 @@ export * from './Vec2'; export * from './Vec3'; export * from './Vec4'; export * from './Mat4'; -export * from './Quat'; \ No newline at end of file +export * from './Quat'; +export * from './Util'; \ No newline at end of file diff --git a/src/render/webgl/WebGLTexture.ts b/src/render/webgl/WebGLTexture.ts index 10d5d2ff..46677804 100755 --- a/src/render/webgl/WebGLTexture.ts +++ b/src/render/webgl/WebGLTexture.ts @@ -1,4 +1,5 @@ import { EGLTexWrapType } from "../common"; +import { Util } from "../math"; import { GLHelper } from "./WebGLHepler"; @@ -14,6 +15,29 @@ export class GLTexture { public target: number; //gl.TEXTURE_2D public name: string; //纹理的名称 + /** + * @var + */ + public static readonly Colors: string[] = [ + 'aqua', //浅绿色 + 'black', //黑色 + 'blue', //蓝色 + 'fuchsia', //紫红色 + 'gray', //灰色 + 'green', //绿色 + 'lime', //绿黄色 + 'maroon', //褐红色 + 'navy', //海军蓝 + 'olive', //橄榄色 + 'orange', //橙色 + 'purple', //紫色 + 'red', //红色 + 'silver', //银灰色 + 'teal', //蓝绿色 + 'yellow', //黄色 + 'white' //白色 + ]; + public constructor(gl: WebGLRenderingContext, name: string = '') { this.gl = gl; this.isMipmap = false; @@ -32,12 +56,91 @@ export class GLTexture { } /** - * 判断是否是2的倍数 - * @param x + * 将非2的n次方的srcImage转换成2的n次方的CanvasRenderingContext2D对象 + * 然后后续用来生成mipmap纹理 + * @param srcImage * @returns */ - public static isPowerOfTwo(x: number) { - return (x & (x - 1)) === 0; + public static createPowerOfTwoCanvas(srcImage: HTMLImageElement | HTMLCanvasElement): HTMLCanvasElement { + let canvas: HTMLCanvasElement = document.createElement("canvas"); + canvas.width = Util.getNextPowerOfTwo(srcImage.width); + canvas.height = Util.getNextPowerOfTwo(srcImage.height); + + let ctx: CanvasRenderingContext2D | null = canvas.getContext("2d"); + if (ctx === null) { + throw new Error("create canvasRenderingContext2D failed!"); + } + ctx.drawImage(srcImage, 0, 0, srcImage.width, srcImage.height, 0, 0, canvas.width, canvas.height); + return canvas; + } + + /** + * 发送纹理到显卡 + * @param source + * @param unit + * @param mipmap + */ + public upload(source: HTMLImageElement | HTMLCanvasElement, unit: number = 0, mipmap: boolean = false): void { + + //绑定要操作的texture,默认是0号texture + this.bind(unit); + + //翻转texture + this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, 1); + + this.width = source.width; + this.height = source.height; + + //生成mipmap纹理 + if (mipmap === true) { + let isWidthPowerOfTwo: boolean = Util.isPowerOfTwo(this.width); + let isHeightPowerOfTwo: boolean = Util.isPowerOfTwo(this.height); + if (isWidthPowerOfTwo === true && isHeightPowerOfTwo === true) { + this.gl.texImage2D(this.target, 0, this.format, this.format, this.type, source); + this.gl.generateMipmap(this.target); + } else { + let canvas: HTMLCanvasElement = GLTexture.createPowerOfTwoCanvas(source); + this.gl.texImage2D(this.target, 0, this.format, this.format, this.type, canvas); + GLHelper.checkGLError(this.gl); + this.gl.generateMipmap(this.target); + GLHelper.checkGLError(this.gl); + this.width = canvas.width; + this.height = canvas.height; + } + this.isMipmap = true; + } else { + this.isMipmap = false; + this.gl.texImage2D(this.target, 0, this.format, this.format, this.type, source); + } + this.unbind(); + } + + public static createDefaultTexture(gl: WebGLRenderingContext): GLTexture { + let step: number = 4; + let canvas: HTMLCanvasElement = document.createElement('canvas') as HTMLCanvasElement; + canvas.width = 32 * step; + canvas.height = 32 * step; + + let context: CanvasRenderingContext2D | null = canvas.getContext("2d"); + if (context === null) { + alert("离屏Canvas获取渲染上下文失败!") + throw new Error("离屏Canvas获取渲染上下文失败!"); + } + + for (let i: number = 0; i < step; i++) { + for (let j: number = 0; j < step; j++) { + let idx: number = step * i + j; + context.save(); + context.fillStyle = GLTexture.Colors[idx]; + context.fillRect(i * 32, j * 32, 32, 32); + context.restore(); + } + } + + let tex: GLTexture = new GLTexture(gl); + tex.wrap(); + tex.upload(canvas); + return tex; } /** @@ -72,4 +175,31 @@ export class GLTexture { } this.gl.texParameteri(this.target, this.gl.TEXTURE_MIN_FILTER, magLinear ? this.gl.LINEAR : this.gl.NEAREST); } + + /** + * 绑定texture + * @param uint + */ + public bind(uint: number = 0): void { + if (this.texture !== null) { + this.gl.activeTexture(this.gl.TEXTURE0 + uint); + this.gl.bindTexture(this.target, this.texture); + } + } + + /** + * 解除textture绑定 + */ + public unbind(): void { + if (this.texture) { + this.gl.bindTexture(this.target, null); + } + } + + /** + * 清除纹理 + */ + public destory(): void { + this.gl.deleteTexture(this.texture); + } } \ No newline at end of file