Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Gfx {
- constructor() {
- this.canvas = document.getElementById("canvas");
- this.gl = canvas.getContext("webgl");
- //viewPos changes as you drag your cursor across the canvas
- this.x_viewPos = 0;
- this.y_viewPos = 0;
- }
- init() {
- this.resizeCanvas(window.innerWidth, window.innerHeight);
- const vsSource = `
- attribute vec4 aVertPos;
- uniform mat4 uMVMat;
- uniform mat4 uProjMat;
- void main() {
- gl_Position = uProjMat * uMVMat * aVertPos;
- }
- `;
- //my tiles get drawn in the frag shader below
- const fsSource = `
- precision mediump float;
- uniform vec2 uViewPos;
- uniform vec2 uTileColorSampSize;
- uniform sampler2D uTileColorSamp;
- void main() {
- //tile width and height are both 33px including a 1px border
- const float lineThickness = (1.0/33.0);
- //gridMult components will either be 0.0 or 1.0. This is used to place the grid lines
- vec2 gridMult = vec2(
- ceil(max(0.0, fract((gl_FragCoord.x-uViewPos.x)/33.0) - lineThickness)),
- ceil(max(0.0, fract((gl_FragCoord.y-uViewPos.y)/33.0) - lineThickness))
- );
- //tileIndex is used to pull color data from the sampler texture
- //add 0.5 due to pixel coords being off in gl
- vec2 tileIndex = vec2(
- floor((gl_FragCoord.x-uViewPos.x)/33.0) + 0.5,
- floor((gl_FragCoord.y-uViewPos.y)/33.0) + 0.5
- );
- //divide by samp size as tex coords are 0.0 to 1.0
- vec4 tileColor = texture2D(uTileColorSamp, vec2(
- tileIndex.x/uTileColorSampSize.x,
- tileIndex.y/uTileColorSampSize.y
- ));
- gl_FragColor = vec4(
- tileColor.x * gridMult.x * gridMult.y,
- tileColor.y * gridMult.x * gridMult.y,
- tileColor.z * gridMult.x * gridMult.y,
- 1.0 //the 4th rgba in our sampler is always 1.0 anyway
- );
- }
- `;
- const shader = this.buildShader(vsSource, fsSource);
- this.programInfo = {
- program: shader,
- attribLocs: {
- vertexPosition: this.gl.getAttribLocation(shader, 'aVertPos')
- },
- uniformLocs: {
- projMat: this.gl.getUniformLocation(shader, 'uProjMat'),
- MVMat: this.gl.getUniformLocation(shader, 'uMVMat'),
- viewPos: this.gl.getUniformLocation(shader, 'uViewPos'),
- tileColorSamp: this.gl.getUniformLocation(shader, 'uTileColorSamp'),
- tileColorSampSize: this.gl.getUniformLocation(shader, 'uTileColorSampSize')
- }
- };
- const buffers = this.initBuffers();
- //check and enable OES_texture_float to allow us to create our sampler tex
- if (!this.gl.getExtension("OES_texture_float")) {
- alert("Sorry, your browser/GPU/driver doesn't support floating point textures");
- }
- this.gl.clearColor(0.0, 0.0, 0.15, 1.0);
- this.gl.clearDepth(1.0);
- this.gl.enable(this.gl.DEPTH_TEST);
- this.gl.depthFunc(this.gl.LEQUAL);
- const FOV = 45 * Math.PI / 180; // in radians
- const aspect = this.gl.canvas.width / this.gl.canvas.height;
- this.projMat = glMatrix.mat4.create();
- glMatrix.mat4.perspective(this.projMat, FOV, aspect, 0.0, 100.0);
- this.MVMat = glMatrix.mat4.create();
- glMatrix.mat4.translate(this.MVMat, this.MVMat, [-0.0, -0.0, -1.0]);
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffers.position);
- this.gl.vertexAttribPointer(this.programInfo.attribLocs.vertPos, 2, this.gl.FLOAT, false, 0, 0);
- this.gl.enableVertexAttribArray(this.programInfo.attribLocs.vertPos);
- this.glDraw();
- }
- //glDraw() gets called once above, as well as in every frame of my render loop
- //(not included here as I have it in a seperate Timing class)
- glDraw() {
- this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
- this.gl.useProgram(this.programInfo.program);
- //X and Y TILE_COUNTs varrified to correspond to colorArray size in testing
- //(colorArray.length = rgbaLength * X_TILE_COUNT * Y_TILE_COUNT)
- //(colorArray.length = rgbaLength * widthInTiles * heightInTiles)
- //(colorArray.length = 4 * 27 * 20)
- let x_tileColorSampSize = X_TILE_COUNT;
- let y_tileColorSampSize = Y_TILE_COUNT;
- //getTileColorArray() produces a flat array of floats between 0.0and 1.0
- //equal in length to rgbaLength * X_TILE_COUNT * Y_TILE_COUNT
- //every 4th value is 1.0, representing tile alpha
- let colorArray = this.getTileColorArray();
- let colorTex = this.colorMapTexFromArray(
- x_tileColorSampSize,
- y_tileColorSampSize,
- colorArray
- );
- //SO solution said to use anyting between 0 and 15 for texUnit, they used 3
- //I imagine this is just an arbitrary location in memory to hold a texture
- let texUnit = 3;
- this.gl.activeTexture(this.gl.TEXTURE0 + texUnit);
- this.gl.bindTexture(this.gl.TEXTURE_2D, colorTex);
- this.gl.uniform1i(
- this.programInfo.uniformLocs.tileColorSamp,
- texUnit
- );
- this.gl.uniform2fv(
- this.programInfo.uniformLocs.tileColorSampSize,
- [x_tileColorSampSize, y_tileColorSampSize]
- );
- this.gl.uniform2fv(
- this.programInfo.uniformLocs.viewPos,
- [-this.x_viewPos, this.y_viewPos] //these change as you drag your cursor across the canvas
- );
- this.gl.uniformMatrix4fv(
- this.programInfo.uniformLocs.projMat,
- false,
- this.projMat
- );
- this.gl.uniformMatrix4fv(
- this.programInfo.uniformLocs.MVMat,
- false,
- this.MVMat
- );
- this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
- }
- colorMapTexFromArray(width, height, colorArray) {
- let float32Arr = Float32Array.from(colorArray);
- let oldActive = this.gl.getParameter(this.gl.ACTIVE_TEXTURE);
- //SO solution said "working register 31, thanks", next to next line
- //not sure what that means but I think they're just looking for any
- //arbitrary place to store the texture?
- this.gl.activeTexture(this.gl.TEXTURE15);
- var texture = this.gl.createTexture();
- this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
- this.gl.texImage2D(
- this.gl.TEXTURE_2D, 0, this.gl.RGBA,
- //if I replace width and height with certain magic numbers
- //like 4 or 8 (all the way up to 32 for width and 16 for height)
- //I will see colored tiles, though obviously they don't map correctly.
- //I THINK I've only seen it work with a widths and heights that are
- //a power of 2... could the issue be that I need my texture to have
- //width and height equal to a power of 2?
- width, height, 0,
- this.gl.RGBA, this.gl.FLOAT, float32Arr
- );
- //use gl.NEAREST to prevent gl from blurring texture
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
- this.gl.bindTexture(this.gl.TEXTURE_2D, null);
- this.gl.activeTexture(oldActive);
- return texture;
- }
- //I don't think the issue would be in the functions below, but I included them anyway
- resizeCanvas(baseWidth, baseHeight) {
- let widthMod = 0;
- let heightMod = 0;
- //...some math is done here to account for some DOM elements that consume window space...
- this.canvas.width = baseWidth + widthMod;
- this.canvas.height = baseHeight + heightMod;
- this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
- }
- initBuffers() {
- const posBuff = this.gl.createBuffer();
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, posBuff);
- const positions = [
- -1.0, 1.0,
- 1.0, 1.0,
- -1.0, -1.0,
- 1.0, -1.0,
- ];
- this.gl.bufferData(
- this.gl.ARRAY_BUFFER,
- new Float32Array(positions),
- this.gl.STATIC_DRAW
- );
- return {
- position: posBuff
- };
- }
- buildShader(vsSource, fsSource) {
- const vertShader = this.loadShader(this.gl.VERTEX_SHADER, vsSource);
- const fragShader = this.loadShader(this.gl.FRAGMENT_SHADER, fsSource);
- const shaderProg = this.gl.createProgram();
- this.gl.attachShader(shaderProg, vertShader);
- this.gl.attachShader(shaderProg, fragShader);
- this.gl.linkProgram(shaderProg);
- if (!this.gl.getProgramParameter(shaderProg, this.gl.LINK_STATUS)) {
- console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProg));
- return null;
- }
- return shaderProg;
- }
- loadShader(type, source) {
- const shader = this.gl.createShader(type);
- this.gl.shaderSource(shader, source);
- this.gl.compileShader(shader);
- if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
- console.error('An error occurred compiling the shaders: ' + this.gl.getShaderInfoLog(shader));
- this.gl.deleteShader(shader);
- return null;
- }
- return shader;
- }
- //getTileColorArray as it appears in my code, in case you want to take a peak.
- //every tileGrid[i][j] has a color, which is an array of 4 values between 0.0 and 1.0
- //the fourth (last) value in tileGrid[i][j].color is always 1.0
- getTileColorArray() {
- let i_min = Math.max(0, Math.floor(this.x_pxPosToTilePos(this.x_viewPos)));
- let i_max = Math.min(GLOBAL.map.worldWidth-1, i_min + Math.ceil(this.x_pxPosToTilePos(this.canvas.width)) + 1);
- let j_min = Math.max(0, Math.floor(this.y_pxPosToTilePos(this.y_viewPos)));
- let j_max = Math.min(GLOBAL.map.worldHeight-1, j_min + Math.ceil(this.y_pxPosToTilePos(this.canvas.height)) + 1);
- let colorArray = [];
- for (let i=i_min; i <= i_max; i++) {
- for (let j=j_min; j <= j_max; j++) {
- colorArray = colorArray.concat(GLOBAL.map.tileGrid[i][j].color);
- }
- }
- return colorArray;
- }
Advertisement
Add Comment
Please, Sign In to add comment