0

here's the full code, I had to remove spaces from some of the functions that weren't related to the problem to make sure im in the 30k character limit of stack overflow

const EPSILON = 0.000001;
const mat4 = { rotateZ: function(out, a, rad) { let s = Math.sin(rad); let c = Math.cos(rad); let a00 = a[0]; let a01 = a[1]; let a02 = a[2]; let a03 = a[3]; let a10 = a[4]; let a11 = a[5]; let a12 = a[6]; let a13 = a[7]; if (a !== out) { out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } out[0] = a00 * c + a10 * s; out[1] = a01 * c + a11 * s; out[2] = a02 * c + a12 * s; out[3] = a03 * c + a13 * s; out[4] = a10 * c - a00 * s; out[5] = a11 * c - a01 * s; out[6] = a12 * c - a02 * s; out[7] = a13 * c - a03 * s; return out; }, create: function() { let out = new Float32Array(16); out[0] = 1; out[5] = 1; out[10] = 1; out[15] = 1; return out; }, perspective: function(out, fovy, aspect, near, far) { let f = 1.0 / Math.tan(fovy / 2), nf; out[0] = f / aspect; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = f; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = -1; out[12] = 0; out[13] = 0; out[15] = 0; if (far !== null && far !== Infinity) { nf = 1 / (near - far); out[10] = (far + near) * nf; out[14] = (2 * far * near) * nf; } else { out[10] = -1; out[14] = -2 * near; } return out; }, translate: function(out, a, v) { let x = v[0], y = v[1], z = v[2]; if (a === out) { out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; return out; } else { let a00, a01, a02, a03; let a10, a11, a12, a13; let a20, a21, a22, a23; a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; out[12] = a00 * x + a10 * y + a20 * z + a[12]; out[13] = a01 * x + a11 * y + a21 * z + a[13]; out[14] = a02 * x + a12 * y + a22 * z + a[14]; out[15] = a03 * x + a13 * y + a23 * z + a[15]; return out; } }, scale: function(out, a, v) { let x = v[0], y = v[1], z = v[2]; out[0] = a[0] * x; out[1] = a[1] * x; out[2] = a[2] * x; out[3] = a[3] * x; out[4] = a[4] * y; out[5] = a[5] * y; out[6] = a[6] * y; out[7] = a[7] * y; out[8] = a[8] * z; out[9] = a[9] * z; out[10] = a[10] * z; out[11] = a[11] * z; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; }, multiply: function(out, a, b) { let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; let b0  = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; return out; }, lookAt: function(out, eye, center, up) { let x0, x1, x2, y0, y1, y2, z0, z1, z2, len; let eyex = eye[0]; let eyey = eye[1]; let eyez = eye[2]; let upx = up[0]; let upy = up[1]; let upz = up[2]; let centerx = center[0]; let centery = center[1]; let centerz = center[2]; if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) { return identity(out); } z0 = eyex - centerx; z1 = eyey - centery; z2 = eyez - centerz; len = 1 / Math.hypot(z0, z1, z2); z0 *= len; z1 *= len; z2 *= len; x0 = upy * z2 - upz * z1; x1 = upz * z0 - upx * z2; x2 = upx * z1 - upy * z0; len = Math.hypot(x0, x1, x2); if (!len) { x0 = 0; x1 = 0; x2 = 0; } else { len = 1 / len; x0 *= len; x1 *= len; x2 *= len; } y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0; len = Math.hypot(y0, y1, y2); if (!len) { y0 = 0; y1 = 0; y2 = 0; } else { len = 1 / len; y0 *= len; y1 *= len; y2 *= len; } out[0] = x0; out[1] = y0; out[2] = z0; out[3] = 0; out[4] = x1; out[5] = y1; out[6] = z1; out[7] = 0; out[8] = x2; out[9] = y2; out[10] = z2; out[11] = 0; out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); out[15] = 1; return out; }, moveToVec3: function(out, v) { out[12] = v[0]; out[13] = v[1]; out[14] = v[2]; } }; const mat3 = { clone: function(a) { let out = new Float32Array(9); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; return out; }, create: function() { let out = new Float32Array(9); out[0] = 1; out[4] = 1; out[8] = 1; return out; } }; const vec3 = { multiply: function(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; }, create: function() { return new Float32Array(3);; }, copy: function(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } }; const vec2 = { create: function() { return new Float32Array(2);; }, copy: function(out, a) { out[0] = a[0]; out[1] = a[1]; return out; }, fromValues: function(x, y) { let out = new Float32Array(2); out[0] = x; out[1] = y; return out; }, multiply: function(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; }, add: function(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; return out; } };
const FRAGMENT_SHADER = ` precision highp float; varying highp vec2 vTextureCoord; varying lowp vec4 vColor; uniform sampler2D uSampler; uniform bool aUseText; void main(void) { if( aUseText ){ gl_FragColor = texture2D(uSampler, vTextureCoord); } else { gl_FragColor = vColor; } } `;
const VERTEX_SHADER = ` attribute vec4 aVertexPosition; attribute vec4 aVertexColor; attribute vec2 aTextureCoord; uniform mat4 uModelViewMatrix; uniform mat4 uProjectionMatrix; uniform mat3 uTextMatrix; uniform float uPointSize; varying lowp vec4 vColor; varying highp vec2 vTextureCoord; void main(void) { gl_PointSize = uPointSize; gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; vColor = aVertexColor; vTextureCoord = (vec3(aTextureCoord, 1)*uTextMatrix).xy; } `;

class WebglEntity {
    constructor() {
        this.matrix = mat4.create();
        this.coords = vec3.create();
    }
    translate(newCoords) {
        const {
            matrix,
            coords
        } = this;
        mat4.translate(matrix, matrix, newCoords);
        vec3.copy(coords, [matrix[12], matrix[13], matrix[14]]);

        return this;
    }
    move(newCoords) {
        const {
            matrix,
            coords
        } = this;
        vec3.copy(coords, newCoords);
        mat4.moveToVec3(matrix, coords);

        return this;
    }
}
class Camera extends WebglEntity {
    constructor(fieldOfView, aspect, zNear, zFar) {
      super();

      this.projection = mat4.perspective(mat4.create(), fieldOfView, aspect, zNear, zFar);

    }
    lookAt(lookAt) {
        const {
            matrix,
            projection,
            coords
        } = this;
        mat4.lookAt(matrix, coords, lookAt, [0, 1, 0]);
        mat4.multiply(matrix, projection, matrix);
        return this;
    }
}
class Rect extends WebglEntity{

  constructor(){

    super();

    this.positionsBuffer = undefined;
    this.fragColorPos = undefined;

    this.strokeColorPos = undefined;
    this.strokePositionBuffer = undefined;

    this.vertexAttribInfo = undefined;
    this.vertextColorAttribInfo = undefined;

    this.vertexCount = undefined;
    this.textureInfo = undefined;


    this.multiTextures = false;

    this.strokeSize = 1;
    this.fillers = {
      fill: false,
      texture: false,
      stroke: false
    };
  }
  setup(matrix, positionsBuffer,  strokePositionBuffer, vertexAttribInfo, vertextColorAttribInfo, vertexCount){

    this.matrix = matrix;

    this.positionsBuffer = positionsBuffer;
    this.strokePositionBuffer = strokePositionBuffer;

    this.vertexAttribInfo = vertexAttribInfo;
    this.vertextColorAttribInfo = vertextColorAttribInfo;

    this.vertexCount = vertexCount;

    return this;
  }

}

class Display{

 constructor(gl, programInfo, zAxis, texture){
   this.gl = gl;
   this.programInfo = programInfo;

   this.canvas = gl.canvas;

   this.currentCamera = new Camera(45 * Math.PI / 180, gl.canvas.width/gl.canvas.height, 0.1, 100.0);

   this.currentCamera.translate([0, 0, zAxis]).lookAt([0, 0, 0]);

   this.zAxis = zAxis;
   this.drawZAxis = 0;

   this.last = {};

   texture.textAttribInfo = {
     numComponents: 2,
     type: gl.FLOAT,
     normalize: false,
     stride: 0,
     offset: 0
   };

   this.texture = texture;
   this.spriteSheets = [];

   const context = texture.context;
   const canvas = texture.canvas;

   this.images = {};

 }


 clear(color){

   const gl = this.gl;

   gl.clearColor(0.1, 0.1, 0.1, 1);

   gl.clearDepth(1.0);
   gl.enable(gl.DEPTH_TEST);
   gl.depthFunc(gl.LEQUAL);

   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);


 }

 rect(x, y, w, h){

   const {rect, stroke} = this.createRectPos(w, h);

   const square = new Rect();
   square.setup(...this.getRectInfo(x, y, rect, stroke));

   return square;
 }

 fillRect(rect, color){
   const {createStaticDrawBuffer, gl, parseColor} = this;

   rect.fillers.fill = true;

   if(color){
     rect.fragColorPos = createStaticDrawBuffer(gl, [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]);

   }
 }

 createRectPos(w, h){

   const rect = [ w/2,  h/2, -w/2,  h/2, w/2, -h/2, -w/2, -h/2 ];
   const stroke = [ -w/2,  h/2, w/2,  h/2, w/2, -h/2, -w/2, -h/2, ];
   return {rect, stroke};
 }

 getRectInfo(x, y, rect, stroke){
   return this.createSquareBuffer(rect, stroke, [x, y, this.drawZAxis]);
 }

 createStaticDrawBuffer(gl, data){

   const buffer = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);

   return buffer;
 }

 createSquareBuffer(positions, strokePosition, coords) {
   const {gl, createStaticDrawBuffer} = this;

   const positionsBuffer      = createStaticDrawBuffer(gl, positions);
   const strokePositionBuffer = createStaticDrawBuffer(gl, strokePosition);
   const modelViewMatrix = mat4.create();

   mat4.translate(modelViewMatrix, modelViewMatrix, coords);

   return [modelViewMatrix, positionsBuffer, strokePositionBuffer, this.createAttribInfo(2, gl.FLOAT, false, 0, 0), this.createAttribInfo(4, gl.FLOAT, false, 0, 0), positions.length/2]; }

 createAttribInfo(numComponents, type, normalize, stride, offset){

   return { numComponents, type, normalize, stride, offset};
 }

 enableAttrib(buffer, attrib, gl, {numComponents, type, normalize, stride, offset}){

   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
   gl.vertexAttribPointer(attrib, numComponents,type,normalize,stride,offset);
   gl.enableVertexAttribArray(attrib);

 }

 drawBuffer(buffer){

   const {gl, drawTexture, enableAttrib, createStaticDrawBuffer, currentCamera, texture: {context, canvas, textAttribInfo}, programInfo: {uniformLocations, program, attribLocations: {vertexPosition, vertexColor, textureCoord}}} = this;

   const cameraMatrix = currentCamera.matrix;

   const {positionsBuffer, fragColorPos, strokeColorPos, strokePositionBuffer, matrix, vertexAttribInfo, vertextColorAttribInfo, vertexCount, fragTextPos, fillers: {fill, stroke, texture}, strokeSize, textureInfo, multiTextures} = buffer;

   gl.uniformMatrix4fv(uniformLocations.projectionMatrix, false, cameraMatrix);
   gl.uniformMatrix4fv(uniformLocations.modelViewMatrix, false, matrix);

   if(fill){

     enableAttrib(positionsBuffer, vertexPosition, gl, vertexAttribInfo);
     enableAttrib(fragColorPos, vertexColor, gl, vertextColorAttribInfo);
     gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexCount);
     gl.disableVertexAttribArray(vertexColor);

   }

 }

 static loadShader(gl, program, type, source) {

   const shader = gl.createShader(type);
   gl.shaderSource(shader, source);
   gl.compileShader(shader);
   gl.attachShader(program, shader);

 }

 static async create(canvas, width, height, zAxis = 6){
   canvas.width  = width;
   canvas.height = height;

   const gl = canvas.getContext("webgl");

   const shaderProgram = gl.createProgram();

   Display.loadShader(gl, shaderProgram, gl.VERTEX_SHADER, VERTEX_SHADER);
   Display.loadShader(gl, shaderProgram, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);

   gl.linkProgram(shaderProgram);

   const programInfo = {
     program: shaderProgram,
     attribLocations: {
       vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
       vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
       textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),


     },
     uniformLocations: {
       projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
       modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
       textMatrix: gl.getUniformLocation(shaderProgram, 'uTextMatrix'),
       sampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
       useText: gl.getUniformLocation(shaderProgram, 'aUseText'),
       pointSize: gl.getUniformLocation(shaderProgram, 'uPointSize'),
     },
   };

   gl.useProgram(programInfo.program);

   gl.uniform1f(programInfo.uniformLocations.pointSize, 1.0);

   gl.enable(gl.BLEND);
   gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

   const textureBuffer = gl.createTexture();

   gl.activeTexture(gl.TEXTURE0);
   gl.bindTexture(gl.TEXTURE_2D, textureBuffer);
   gl.uniform1i(programInfo.uniformLocations.uSampler, 0);

   const textureCanvas = document.createElement("canvas");

   textureCanvas.width = 0;
   textureCanvas.height = 0;

   let texture = {
       canvas: textureCanvas,
       buffer: textureBuffer,
       context: textureCanvas.getContext("2d"),
     };

   return new Display(gl, programInfo, zAxis, texture);
 }
}

class Engine { constructor(time_step, update, render, allowedSkippedFrames) { this.accumulated_time = 0; this.animation_frame_request = undefined, this.time = undefined, this.time_step = time_step, this.updated = false; this.update = update; this.render = render; this.allowedSkippedFrames = allowedSkippedFrames; this.run = this.run.bind(this); this.end = false; } run(time_stamp) { const { accumulated_time, time, time_step, updated, update, render, allowedSkippedFrames, end } = this; this.accumulated_time += time_stamp - time; this.time = time_stamp; if (accumulated_time > time_stamp * allowedSkippedFrames) { this.accumulated_time = time_stamp; } while (this.accumulated_time >= time_step) { this.accumulated_time -= time_step; update(time_stamp); this.updated = true; } if (updated) { this.updated = false; render(time_stamp); } if (end) { return; } this.animation_frame_request = requestAnimationFrame(this.run); } start() { this.accumulated_time = this.time_step; this.time = performance.now(); this.animation_frame_request = requestAnimationFrame(this.run); } stop() { this.end = true; cancelAnimationFrame(this.animation_frame_request); } }

class Entity extends Rect {

  constructor(){

    super();

    this.velocity = vec2.create();
    this.area = undefined;
    this.mass = 2;

    this.updateFillers = {};
    this.delete = false;
    this.draw = true;
  }

  setup(w, h, ...args){
    this.area = vec2.fromValues(w, h);
    super.setup(...args);

    return this;
  }

  fill(...args){
    this.updateFillers.fill = args;
  }

  update(deltaTime, speed){

    return this;
  }

  move(x, y){

    super.move([x, y, this.coords[2]]);

    return this;

  }

}

class Quixotic{

  constructor(display){

    this.display = display;

    this.engine = undefined;

    this.render = undefined;
    this.update = undefined;
    this.frameRate = undefined;

    this.time = 0; this.speed = 1;
    this.world = {

      objects: {},
      objectsCollisionInfo: {},
      objectsArray: [],
      classesInfo: {}

    };

    this.timePassed = 0;

  }

  createEntity(Class, ...args){
    const display = this.display; const {rect, stroke} = display.createRectPos(5, 5); Class = Class ? Class : Entity; const className = Class.name; if(className !== "Entity" && !Entity.prototype.isPrototypeOf(Class.prototype)){ throw new TypeError("Expected extended class of Entity. Instead got: " + className); } let instance; const {objectsArray, classesInfo, objects} = this.world; const classInfo = classesInfo[className]; if(classInfo){ if(classInfo.args){ instance = new Class(...[...classInfo.args, ...args]); } else { instance = new Class(...args); } const name = classInfo.name; if(Array.isArray(objects[name])){ objects[name].push(instance); instance.name = name; } else { console.warn("Didn't save object in world.objects object, object wouldn't detect collision"); } } else { instance = new Class(...args); } instance.setup(5, 5, ...display.getRectInfo(0, 0, rect, stroke, "#000")); objectsArray.push(instance); return instance; }

  createBackground(objects){
    const buffer = document.createElement("canvas").getContext("2d");

    const bufferRect = this.createEntity();
    let {zAxis, canvas: {width, height}} = this.display;
    zAxis--;
    const halfZ = zAxis/2;
    let {coords: [x, y], area: [w, h]} = objects[objects.length - 1];

    let [mX, mY, mW, mH] = [x, y, w, h];
    for(let i = objects.length-1; i--;){

      const {coords: [_x, _y], area: [_w, _h]} = objects[i];
      x < _x ? _x : x;
      y < _y ? _y : y;

      if(mX < _x){
         mX = _x;
         mW = _w;
      }
      if(mY < _y){
         mY = _y;
         mH = _h;
       }
    }

    buffer.canvas.width = width;
    buffer.canvas.height = height;
    for(let i = objects.length; i--;){

      const {coords: [_x, _y], area: [_w, _h]} = objects[i];
      buffer.fillRect(((_x-halfZ-_w*2)/zAxis+1)*width, ((-_y-halfZ-_h*2)/zAxis+1)*height, _w*2/zAxis*width, _h*2/zAxis*height);
    }

    document.body.appendChild(buffer.canvas)

  }

  buildWorld({objects, classes, tileMap}){

    const world = this.world;

    if(Array.isArray(objects)){
      for(let i = objects.length - 1; i > -1; i --){
        const object = objects[i];
        const {name, array, amount, position, collision, args, area} = object;

        let createClass;

        if(!object.class){
          createClass = Entity;
        }

        const _args = args ? args : [];

        let pos;

        if(position){
            let p = amount;
            if(array){
              const positions = position.positions;
              pos = function(){
                p--;
                return positions[p];
              };
            } else {
              pos = function(){
                return position.position;
              };
            }
          }

        if(array){

          let _array = [];

          for(let j = amount; j--;){

            const instance = this.createEntity(createClass, ..._args);
            instance.name = name;

            if(position){
              instance.move(...pos());
            }

            if(area){

              instance.setSize(area);

            }
            _array.push(instance);
          }
          world.objects[name] = _array;
          world.objectsArray.push(..._array);

        }
      }
    }

    return;

  }

  setup(game){

    const {style: {backgroundColor, backgroundImage, stroke}, world, engine: {frameRate, update, render}, setup} = game; this.buildWorld(world); const {display, entitySystem, world: {objectsArray, objects}} = this; if(backgroundImage){ display.gl.canvas.style.background = `url(${backgroundImage})`; if(repeatX || repeatY){ console.log("not read yet"); } } this.frameRate = frameRate; let lastUpdated = 0; this.update = (time) =>{ let deltaTime = time - lastUpdated; lastUpdated = time; const speed = this.speed; this.timePassed += deltaTime*speed; for(let i = objectsArray.length; i--;){ const object = objectsArray[i]; if(object.delete){ objectsArray.splice(i, 1); } object.update(deltaTime/1000, speed); } update(deltaTime/1000, this); }; let lastRendered = 0; this.render = (timeStamp) => { const deltaTime = timeStamp - lastRendered; lastRendered = timeStamp; if(backgroundColor) display.clear(backgroundColor); const length = objectsArray.length; for(let i = objectsArray.length; i--; ){ const object = objectsArray[length - i - 1]; if(object.draw){ const updateFillers = Object.entries(object.updateFillers); const fillersLength = updateFillers.length; if(fillersLength){ for(let i = fillersLength; i--;){ const [func, args] = updateFillers[fillersLength - i - 1]; display[func + "Rect"](object, ...args); } object.updateFillers = {}; } display.drawBuffer(object); } } const speed = this.speed; const spriteSheets = display.spriteSheets; for(let i = spriteSheets.length; i--;){ spriteSheets[i].update(deltaTime/1000*speed); } render(display, this); }; setup(this, display, this.world); this.engine = new Engine(this.frameRate, this.update, this.render, 3); this.engine.start(); return game;
  }

  static async create({display: {canvas, width, height, zAxis}, homeURL}){

    const display = await Display.create(canvas, width, height, zAxis);

    return new Quixotic(display);
  }

}


const fps = document.querySelector("#fps");
const minLength = innerWidth > innerHeight ? innerHeight : innerWidth;
const game = {

  create: {

    display: {

      canvas: document.querySelector("#canvas"),
      zAxis: 96,
      width: minLength,
      height: minLength,

    },

    homeURL: "/src"
  },

  style: {
    backgroundColor: "#111122"
  },

  world: {
    objects: [
      {
        name: "trees",

        array: true,
        amount: 5,
        position: {
          type: "set",
          positions: [ [-37.5, 37.5], [0,0], [-37.5,-37.5], [37.5,-37.5], [37.5,37.5], [10,10], [15,10], [20,10], [25,10], [30,10]]

        }
      }
    ]
  },

  engine: {

    frameRate: 1000/30,

    update: function(deltaTime, engine){
      fps.innerText = 1/deltaTime;
    },

    render: function(display){}
  },

  setup: function(engine, display, {objects: {trees}}){

     trees.forEach(tree => {
       tree.fill("#00ff00")
     })
    engine.createBackground(trees);
  }

};



Quixotic.create(game.create)
  .then(engine => {

    engine.setup(game);
  });
 * {
         box-sizing:border-box;
         margin:0;
         padding:0;
    }
     body {
         background-color: #111c31;
         overflow: hidden;
         align-items:space-around;
         display:grid;
         height:100%;
         width:100%;
    }
     #canvas {
         background-color: #152646;
         /* justify-self: center; */
    }
    #fps {
      position: fixed;
      color: white;
      right: 0;
    }
    canvas {
      position: fixed
    }
   
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>webgl x 2dCanvas</title>
  </head>
  <body>
    <canvas id="canvas" width="300" height="300"></canvas>
    <p id = "fps"></p>
  </body>
</html>

Here's code from line 374 where the problem is happening

createBackground(objects){ //method
  const buffer = document.createElement("canvas").getContext("2d");

  const bufferRect = this.createEntity();
  let {zAxis, canvas: {width, height}} = this.display;
  zAxis--; //zAxis is where the camera is at, currently 96, but with webgl the objects have to be 1 point lower, so 95.

  const halfZ = zAxis/2;
  let {coords: [x, y], area: [w, h]} = objects[objects.length - 1];

  let [mX, mY, mW, mH] = [x, y, w, h];
  for(let i = objects.length-1; i--;){

    const {coords: [_x, _y], area: [_w, _h]} = objects[i];
    x < _x ? _x : x;
    y < _y ? _y : y;

    if(mX < _x){
       mX = _x;
       mW = _w;
    }
    if(mY < _y){
       mY = _y;
       mH = _h;
     }
  }

  buffer.canvas.width = ((mX-halfZ+mW*2)/zAxis+1)*width;
  buffer.canvas.height = ((mY-halfZ+mH*2)/zAxis+1)*height;

  for(let i = objects.length; i--;){

    const {coords: [_x, _y], area: [_w, _h]} = objects[i];
    buffer.fillRect(((_x-halfZ-_w*2)/zAxis+1)*width, ((_y-halfZ-_h*2)/zAxis+1)*height, _w*2/zAxis*width, _h*2/zAxis*height);
  }

  document.body.appendChild(buffer.canvas)

}

I have this function that takes objects that are being drawn with webgl on a 3d world with a couple vectors and matrices, basically I get all their positions and volumes to draw them on a 2d canvas, heres the result I got so far

results, black squares not quit covering the green square

the green squares are the ones being drawn with webgl and the black squares are the ones being draw on a canvas rendering 2d, the end result should be the black squares covering the green squares but my math is off somewhere.

The full code can be found here https://github.com/bahaaaldin214/Quixotic-Engine/tree/test

The shaders are in src/modules/webgl/shaders

other information

camera position: 96,

green squares positions:

[
    [-37.5, 37.5], //bottom left
    [0,0], //center
    [-37.5,-37.5],  //top left
    [37.5,-37.5], //bottom right
    [37.5,37.5], //top right
]
  • There's not enough code in your question to be able to answer it. We need to see what the data is, how you're drawing it in webgl including your shaders and what you set your attributes and uniforms to. – gman Jun 03 '20 at 02:47
  • Ok thank you ill update the question – Bahaaaldin Mohammad Jun 03 '20 at 02:49
  • That's still not enough code. Stack Overflow requires enough code **in the question itself** to be able to answer the question. Without the math, shaders, uniform settings etc **in the question itself** we can't answer. See [this](https://meta.stackoverflow.com/a/349790/128511) – gman Jun 03 '20 at 05:36
  • there's simply too much code for that – Bahaaaldin Mohammad Jun 03 '20 at 05:41
  • That's what you're required to make it minimal. If you're not willing to put in the effort why should we? – gman Jun 03 '20 at 05:42
  • I would put in the effort if there was a way to write a fully working webgl example that will fit in a stackoverflow question – Bahaaaldin Mohammad Jun 03 '20 at 05:44
  • There are literally 1000s of fulling working webgl examples in questions and answers on stack overflow. [Here's one using three.js](https://stackoverflow.com/questions/62142543/piecing-together-meshes-in-threejs-causes-visible-seam/62153589#62153589), [Here's one using twgl](https://stackoverflow.com/questions/62092581/webgl-fps-camera-movement-along-the-local-axis-instead-of-the-world-axis-with-gl/62096622#62096622), [Here's one using raw webgl](https://stackoverflow.com/questions/62129454/why-is-the-webgl-instancing-extension-only-drawing-one-triangle-instead-of-two/62133395#62133395). – gman Jun 03 '20 at 05:52
  • [Every example on this site](https://webglfundamentals.org) and [this one](https://threejsfundamentals.org) will run in a [snippet](https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/) on S.O. You can copy and paste them in. Full code is not required it just helps check you haven't missed any info. How are we supposed to guess how your WebGL code is positioning things so then we can see why your non-webgl code is not getting the same result if you haven't actually shown what you're doing in WebGL? – gman Jun 03 '20 at 05:53
  • alright after 2 hours (not complaining it was kinda fun) of strippnig code I got a working snippet up, I had to also remove spaces of some code that was taking too much space but isnt related to the problem hopefully there wouldnt be an issue with that – Bahaaaldin Mohammad Jun 03 '20 at 19:23

1 Answers1

1

Well now that I've seen the code. First off, my bad but I didn't make it clear you should post minimal code. There is lots of unneeded code. Also I'm not sure if that's your own math library or if it's paired down glmatrix. If it's the latter you can just <script src="cdn/to/glmatrix"></script> to use it.

In any case you're positioning the squares using a perspective matrix and view matrix (the camera) so you need to use the same math for the 2D canvas.

const worldViewProjection = mat4.create();
buffer.canvas.width = width;
buffer.canvas.height = height;
for (let i = objects.length; i--;) {
  const {
    coords: [_x, _y],
    area: [_w, _h]
  } = objects[i];
  mat4.multiply(worldViewProjection, this.display.currentCamera.matrix, objects[i].matrix);
  const points = [
    [-_w / 2, -_h / 2, 0],
    [ _w / 2,  _h / 2, 0],
  ].map(p => {
    const ndc = vec3.transformMat4([], p, worldViewProjection);
    return [
      (ndc[0] *  0.5 + 0.5) * width,
      (ndc[1] * -0.5 + 0.5) * height,
    ];
  });
  const ww = points[1][0] - points[0][0];
  const hh = points[1][1] - points[0][1];

  buffer.strokeStyle = 'red';
  buffer.strokeRect(...points[0], ww, hh);
} 

const EPSILON = 0.000001;
const FRAGMENT_SHADER = ` precision highp float; varying highp vec2 vTextureCoord; varying lowp vec4 vColor; uniform sampler2D uSampler; uniform bool aUseText; void main(void) { if( aUseText ){ gl_FragColor = texture2D(uSampler, vTextureCoord); } else { gl_FragColor = vColor; } } `;
const VERTEX_SHADER = ` attribute vec4 aVertexPosition; attribute vec4 aVertexColor; attribute vec2 aTextureCoord; uniform mat4 uModelViewMatrix; uniform mat4 uProjectionMatrix; uniform mat3 uTextMatrix; uniform float uPointSize; varying lowp vec4 vColor; varying highp vec2 vTextureCoord; void main(void) { gl_PointSize = uPointSize; gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; vColor = aVertexColor; vTextureCoord = (vec3(aTextureCoord, 1)*uTextMatrix).xy; } `;

mat4.moveToVec3 = function(out, v) {
  out[12] = v[0];
  out[13] = v[1];
  out[14] = v[2];
};


class WebglEntity {
  constructor() {
    this.matrix = mat4.create();
    this.coords = vec3.create();
  }
  translate(newCoords) {
    const {
      matrix,
      coords
    } = this;
    mat4.translate(matrix, matrix, newCoords);
    vec3.copy(coords, [matrix[12], matrix[13], matrix[14]]);

    return this;
  }
  move(newCoords) {
    const {
      matrix,
      coords
    } = this;
    vec3.copy(coords, newCoords);
    mat4.moveToVec3(matrix, coords);

    return this;
  }
}
class Camera extends WebglEntity {
  constructor(fieldOfView, aspect, zNear, zFar) {
    super();

    this.projection = mat4.perspective(mat4.create(), fieldOfView, aspect, zNear, zFar);

  }
  lookAt(lookAt) {
    const {
      matrix,
      projection,
      coords
    } = this;
    mat4.lookAt(matrix, coords, lookAt, [0, 1, 0]);
    mat4.multiply(matrix, projection, matrix);
    return this;
  }
}
class Rect extends WebglEntity {

  constructor() {

    super();

    this.positionsBuffer = undefined;
    this.fragColorPos = undefined;

    this.strokeColorPos = undefined;
    this.strokePositionBuffer = undefined;

    this.vertexAttribInfo = undefined;
    this.vertextColorAttribInfo = undefined;

    this.vertexCount = undefined;
    this.textureInfo = undefined;


    this.multiTextures = false;

    this.strokeSize = 1;
    this.fillers = {
      fill: false,
      texture: false,
      stroke: false
    };
  }
  setup(matrix, positionsBuffer, strokePositionBuffer, vertexAttribInfo, vertextColorAttribInfo, vertexCount) {

    this.matrix = matrix;

    this.positionsBuffer = positionsBuffer;
    this.strokePositionBuffer = strokePositionBuffer;

    this.vertexAttribInfo = vertexAttribInfo;
    this.vertextColorAttribInfo = vertextColorAttribInfo;

    this.vertexCount = vertexCount;

    return this;
  }

}

class Display {

  constructor(gl, programInfo, zAxis, texture) {
    this.gl = gl;
    this.programInfo = programInfo;

    this.canvas = gl.canvas;

    this.currentCamera = new Camera(45 * Math.PI / 180, gl.canvas.width / gl.canvas.height, 0.1, 100.0);

    this.currentCamera.translate([0, 0, zAxis]).lookAt([0, 0, 0]);

    this.zAxis = zAxis;
    this.drawZAxis = 0;

    this.last = {};

    texture.textAttribInfo = {
      numComponents: 2,
      type: gl.FLOAT,
      normalize: false,
      stride: 0,
      offset: 0
    };

    this.texture = texture;
    this.spriteSheets = [];

    const context = texture.context;
    const canvas = texture.canvas;

    this.images = {};

  }


  clear(color) {

    const gl = this.gl;

    gl.clearColor(0.1, 0.1, 0.1, 1);

    gl.clearDepth(1.0);
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);


  }

  rect(x, y, w, h) {

    const {
      rect,
      stroke
    } = this.createRectPos(w, h);

    const square = new Rect();
    square.setup(...this.getRectInfo(x, y, rect, stroke));

    return square;
  }

  fillRect(rect, color) {
    const {
      createStaticDrawBuffer,
      gl,
      parseColor
    } = this;

    rect.fillers.fill = true;

    if (color) {
      rect.fragColorPos = createStaticDrawBuffer(gl, [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]);

    }
  }

  createRectPos(w, h) {

    const rect = [w / 2, h / 2, -w / 2, h / 2, w / 2, -h / 2, -w / 2, -h / 2];
    const stroke = [-w / 2, h / 2, w / 2, h / 2, w / 2, -h / 2, -w / 2, -h / 2, ];
    return {
      rect,
      stroke
    };
  }

  getRectInfo(x, y, rect, stroke) {
    return this.createSquareBuffer(rect, stroke, [x, y, this.drawZAxis]);
  }

  createStaticDrawBuffer(gl, data) {

    const buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);

    return buffer;
  }

  createSquareBuffer(positions, strokePosition, coords) {
    const {
      gl,
      createStaticDrawBuffer
    } = this;

    const positionsBuffer = createStaticDrawBuffer(gl, positions);
    const strokePositionBuffer = createStaticDrawBuffer(gl, strokePosition);
    const modelViewMatrix = mat4.create();

    mat4.translate(modelViewMatrix, modelViewMatrix, coords);

    return [modelViewMatrix, positionsBuffer, strokePositionBuffer, this.createAttribInfo(2, gl.FLOAT, false, 0, 0), this.createAttribInfo(4, gl.FLOAT, false, 0, 0), positions.length / 2];
  }

  createAttribInfo(numComponents, type, normalize, stride, offset) {

    return {
      numComponents,
      type,
      normalize,
      stride,
      offset
    };
  }

  enableAttrib(buffer, attrib, gl, {
    numComponents,
    type,
    normalize,
    stride,
    offset
  }) {

    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.vertexAttribPointer(attrib, numComponents, type, normalize, stride, offset);
    gl.enableVertexAttribArray(attrib);

  }

  drawBuffer(buffer) {

    const {
      gl,
      drawTexture,
      enableAttrib,
      createStaticDrawBuffer,
      currentCamera,
      texture: {
        context,
        canvas,
        textAttribInfo
      },
      programInfo: {
        uniformLocations,
        program,
        attribLocations: {
          vertexPosition,
          vertexColor,
          textureCoord
        }
      }
    } = this;

    const cameraMatrix = currentCamera.matrix;

    const {
      positionsBuffer,
      fragColorPos,
      strokeColorPos,
      strokePositionBuffer,
      matrix,
      vertexAttribInfo,
      vertextColorAttribInfo,
      vertexCount,
      fragTextPos,
      fillers: {
        fill,
        stroke,
        texture
      },
      strokeSize,
      textureInfo,
      multiTextures
    } = buffer;

    gl.uniformMatrix4fv(uniformLocations.projectionMatrix, false, cameraMatrix);
    gl.uniformMatrix4fv(uniformLocations.modelViewMatrix, false, matrix);

    if (fill) {

      enableAttrib(positionsBuffer, vertexPosition, gl, vertexAttribInfo);
      enableAttrib(fragColorPos, vertexColor, gl, vertextColorAttribInfo);
      gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexCount);
      gl.disableVertexAttribArray(vertexColor);

    }

  }

  static loadShader(gl, program, type, source) {

    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    gl.attachShader(program, shader);

  }

  static async create(canvas, width, height, zAxis = 6) {
    canvas.width = width;
    canvas.height = height;

    const gl = canvas.getContext("webgl");

    const shaderProgram = gl.createProgram();

    Display.loadShader(gl, shaderProgram, gl.VERTEX_SHADER, VERTEX_SHADER);
    Display.loadShader(gl, shaderProgram, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);

    gl.linkProgram(shaderProgram);

    const programInfo = {
      program: shaderProgram,
      attribLocations: {
        vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
        vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
        textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),


      },
      uniformLocations: {
        projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
        modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        textMatrix: gl.getUniformLocation(shaderProgram, 'uTextMatrix'),
        sampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
        useText: gl.getUniformLocation(shaderProgram, 'aUseText'),
        pointSize: gl.getUniformLocation(shaderProgram, 'uPointSize'),
      },
    };

    gl.useProgram(programInfo.program);

    gl.uniform1f(programInfo.uniformLocations.pointSize, 1.0);

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

    const textureBuffer = gl.createTexture();

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, textureBuffer);
    gl.uniform1i(programInfo.uniformLocations.uSampler, 0);

    const textureCanvas = document.createElement("canvas");

    textureCanvas.width = 0;
    textureCanvas.height = 0;

    let texture = {
      canvas: textureCanvas,
      buffer: textureBuffer,
      context: textureCanvas.getContext("2d"),
    };

    return new Display(gl, programInfo, zAxis, texture);
  }
}

class Engine {
  constructor(time_step, update, render, allowedSkippedFrames) {
    this.accumulated_time = 0;
    this.animation_frame_request = undefined, this.time = undefined, this.time_step = time_step, this.updated = false;
    this.update = update;
    this.render = render;
    this.allowedSkippedFrames = allowedSkippedFrames;
    this.run = this.run.bind(this);
    this.end = false;
  }
  run(time_stamp) {
    const {
      accumulated_time,
      time,
      time_step,
      updated,
      update,
      render,
      allowedSkippedFrames,
      end
    } = this;
    this.accumulated_time += time_stamp - time;
    this.time = time_stamp;
    if (accumulated_time > time_stamp * allowedSkippedFrames) {
      this.accumulated_time = time_stamp;
    }
    while (this.accumulated_time >= time_step) {
      this.accumulated_time -= time_step;
      update(time_stamp);
      this.updated = true;
    }
    if (updated) {
      this.updated = false;
      render(time_stamp);
    }
    if (end) {
      return;
    }
    this.animation_frame_request = requestAnimationFrame(this.run);
  }
  start() {
    this.accumulated_time = this.time_step;
    this.time = performance.now();
    this.animation_frame_request = requestAnimationFrame(this.run);
  }
  stop() {
    this.end = true;
    cancelAnimationFrame(this.animation_frame_request);
  }
}

class Entity extends Rect {

  constructor() {

    super();

    this.velocity = vec2.create();
    this.area = undefined;
    this.mass = 2;

    this.updateFillers = {};
    this.delete = false;
    this.draw = true;
  }

  setup(w, h, ...args) {
    this.area = vec2.fromValues(w, h);
    super.setup(...args);

    return this;
  }

  fill(...args) {
    this.updateFillers.fill = args;
  }

  update(deltaTime, speed) {

    return this;
  }

  move(x, y) {

    super.move([x, y, this.coords[2]]);

    return this;

  }

}

class Quixotic {

  constructor(display) {

    this.display = display;

    this.engine = undefined;

    this.render = undefined;
    this.update = undefined;
    this.frameRate = undefined;

    this.time = 0;
    this.speed = 1;
    this.world = {

      objects: {},
      objectsCollisionInfo: {},
      objectsArray: [],
      classesInfo: {}

    };

    this.timePassed = 0;

  }

  createEntity(Class, ...args) {
    const display = this.display;
    const {
      rect,
      stroke
    } = display.createRectPos(5, 5);
    Class = Class ? Class : Entity;
    const className = Class.name;
    if (className !== "Entity" && !Entity.prototype.isPrototypeOf(Class.prototype)) {
      throw new TypeError("Expected extended class of Entity. Instead got: " + className);
    }
    let instance;
    const {
      objectsArray,
      classesInfo,
      objects
    } = this.world;
    const classInfo = classesInfo[className];
    if (classInfo) {
      if (classInfo.args) {
        instance = new Class(...[...classInfo.args, ...args]);
      } else {
        instance = new Class(...args);
      }
      const name = classInfo.name;
      if (Array.isArray(objects[name])) {
        objects[name].push(instance);
        instance.name = name;
      } else {
        console.warn("Didn't save object in world.objects object, object wouldn't detect collision");
      }
    } else {
      instance = new Class(...args);
    }
    instance.setup(5, 5, ...display.getRectInfo(0, 0, rect, stroke, "#000"));
    objectsArray.push(instance);
    return instance;
  }

  createBackground(objects) {
    const buffer = document.createElement("canvas").getContext("2d");

    const bufferRect = this.createEntity();
    let {
      zAxis,
      canvas: {
        width,
        height
      }
    } = this.display;
    zAxis--;
    const halfZ = zAxis / 2;
    let {
      coords: [x, y],
      area: [w, h]
    } = objects[objects.length - 1];

    const worldViewProjection = mat4.create();
    buffer.canvas.width = width;
    buffer.canvas.height = height;
    for (let i = objects.length; i--;) {
      const {
        coords: [_x, _y],
        area: [_w, _h]
      } = objects[i];
      mat4.multiply(worldViewProjection, this.display.currentCamera.matrix, objects[i].matrix);
      const points = [
        [-_w / 2, -_h / 2, 0],
        [_w / 2, _h / 2, 0],
      ].map(p => {
        const ndc = vec3.transformMat4([], p, worldViewProjection);
        return [
          (ndc[0] * 0.5 + 0.5) * width,
          (ndc[1] * -0.5 + 0.5) * height,
        ];
      });
      const ww = points[1][0] - points[0][0];
      const hh = points[1][1] - points[0][1];

      buffer.strokeStyle = 'red';
      buffer.strokeRect(...points[0], ww, hh);
    }
    document.body.appendChild(buffer.canvas)

  }

  buildWorld({
    objects,
    classes,
    tileMap
  }) {

    const world = this.world;

    if (Array.isArray(objects)) {
      for (let i = objects.length - 1; i > -1; i--) {
        const object = objects[i];
        const {
          name,
          array,
          amount,
          position,
          collision,
          args,
          area
        } = object;

        let createClass;

        if (!object.class) {
          createClass = Entity;
        }

        const _args = args ? args : [];

        let pos;

        if (position) {
          let p = amount;
          if (array) {
            const positions = position.positions;
            pos = function() {
              p--;
              return positions[p];
            };
          } else {
            pos = function() {
              return position.position;
            };
          }
        }

        if (array) {

          let _array = [];

          for (let j = amount; j--;) {

            const instance = this.createEntity(createClass, ..._args);
            instance.name = name;

            if (position) {
              instance.move(...pos());
            }

            if (area) {

              instance.setSize(area);

            }
            _array.push(instance);
          }
          world.objects[name] = _array;
          world.objectsArray.push(..._array);

        }
      }
    }

    return;

  }

  setup(game) {

    const {
      style: {
        backgroundColor,
        backgroundImage,
        stroke
      },
      world,
      engine: {
        frameRate,
        update,
        render
      },
      setup
    } = game;
    this.buildWorld(world);
    const {
      display,
      entitySystem,
      world: {
        objectsArray,
        objects
      }
    } = this;
    if (backgroundImage) {
      display.gl.canvas.style.background = `url(${backgroundImage})`;
      if (repeatX || repeatY) {
        console.log("not read yet");
      }
    }
    this.frameRate = frameRate;
    let lastUpdated = 0;
    this.update = (time) => {
      let deltaTime = time - lastUpdated;
      lastUpdated = time;
      const speed = this.speed;
      this.timePassed += deltaTime * speed;
      for (let i = objectsArray.length; i--;) {
        const object = objectsArray[i];
        if (object.delete) {
          objectsArray.splice(i, 1);
        }
        object.update(deltaTime / 1000, speed);
      }
      update(deltaTime / 1000, this);
    };
    let lastRendered = 0;
    this.render = (timeStamp) => {
      const deltaTime = timeStamp - lastRendered;
      lastRendered = timeStamp;
      if (backgroundColor) display.clear(backgroundColor);
      const length = objectsArray.length;
      for (let i = objectsArray.length; i--;) {
        const object = objectsArray[length - i - 1];
        if (object.draw) {
          const updateFillers = Object.entries(object.updateFillers);
          const fillersLength = updateFillers.length;
          if (fillersLength) {
            for (let i = fillersLength; i--;) {
              const [func, args] = updateFillers[fillersLength - i - 1];
              display[func + "Rect"](object, ...args);
            }
            object.updateFillers = {};
          }
          display.drawBuffer(object);
        }
      }
      const speed = this.speed;
      const spriteSheets = display.spriteSheets;
      for (let i = spriteSheets.length; i--;) {
        spriteSheets[i].update(deltaTime / 1000 * speed);
      }
      render(display, this);
    };
    setup(this, display, this.world);
    this.engine = new Engine(this.frameRate, this.update, this.render, 3);
    this.engine.start();
    return game;
  }

  static async create({
    display: {
      canvas,
      width,
      height,
      zAxis
    },
    homeURL
  }) {

    const display = await Display.create(canvas, width, height, zAxis);

    return new Quixotic(display);
  }

}


const fps = document.querySelector("#fps");
const minLength = innerWidth > innerHeight ? innerHeight : innerWidth;
const game = {

  create: {

    display: {

      canvas: document.querySelector("#canvas"),
      zAxis: 96,
      width: minLength,
      height: minLength,

    },

    homeURL: "/src"
  },

  style: {
    backgroundColor: "#111122"
  },

  world: {
    objects: [{
      name: "trees",

      array: true,
      amount: 5,
      position: {
        type: "set",
        positions: [
          [-37.5, 37.5],
          [0, 0],
          [-37.5, -37.5],
          [37.5, -37.5],
          [37.5, 37.5],
          [10, 10],
          [15, 10],
          [20, 10],
          [25, 10],
          [30, 10]
        ]

      }
    }]
  },

  engine: {

    frameRate: 1000 / 30,

    update: function(deltaTime, engine) {
      fps.innerText = 1 / deltaTime;
    },

    render: function(display) {}
  },

  setup: function(engine, display, {
    objects: {
      trees
    }
  }) {

    trees.forEach(tree => {
      tree.fill("#00ff00")
    })
    engine.createBackground(trees);
  }

};



Quixotic.create(game.create)
  .then(engine => {

    engine.setup(game);
  });
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  background-color: #111c31;
  overflow: hidden;
  align-items: space-around;
  display: grid;
  height: 100%;
  width: 100%;
}

#canvas {
  background-color: #152646;
  /* justify-self: center; */
}

#fps {
  position: fixed;
  color: white;
  right: 0;
}

canvas {
  position: fixed
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>
<canvas id="canvas" width="300" height="300"></canvas>
<p id="fps"></p>

note: the code only works because the camera is not rotated, nor are the squares. If you did rotate the camera or the squares you'd need to draw triangles with canvas 2d after transforming each set of 3 vertices, just like WebGL does.

gman
  • 100,619
  • 31
  • 269
  • 393
  • ohh I didnt know I had to do all the matrix math, thank you very much! – Bahaaaldin Mohammad Jun 03 '20 at 20:57
  • Well neither did I until I you showed me your WebGL code – gman Jun 03 '20 at 21:00
  • I have a method (but not in the minified code above) that lets me attach images to rectangles instead of coloring them, I wanna attach the canvas to the rectangle I created bufferRect but I dont know where to position the rectangle and how big to make it – Bahaaaldin Mohammad Jun 5 at 22:14 – Bahaaaldin Mohammad Jun 10 '20 at 21:57