<commit_before>"use strict";

var CityTour = CityTour || {};
CityTour.Scene = CityTour.Scene || {};

CityTour.Scene.TerrainGeometryBuilder = function() {
  var TERRAIN_COLOR_1 = new THREE.Color(0.0, 0.48, 0.0);
  var TERRAIN_COLOR_2 = new THREE.Color(0.0, 0.49, 0.0);
  var WATER_COLOR_1 = new THREE.Color(0.1, 0.2, 1.0);
  var WATER_COLOR_2 = new THREE.Color(0.1, 0.19, 1.0);

  var SOLID_SHADING_MODE = 1;
  var GRADIENT_SHADING_MODE = 2;
  var SHADING_MODE = SOLID_SHADING_MODE;

  var reusableTriangle = new THREE.Geometry();
  reusableTriangle.faces = [new THREE.Face3(0, 1, 2)];

  var buildTriangleGeometry = function(x1, y1, z1, material1, x2, y2, z2, material2, x3, y3, z3, material3, color_variant) {
    var waterColor, landColor;

    reusableTriangle.vertices = [ new THREE.Vector3(x1, y1, z1), new THREE.Vector3(x2, y2, z2), new THREE.Vector3(x3, y3, z3) ];

    if (color_variant === 1) {
      waterColor = WATER_COLOR_1;
      landColor = TERRAIN_COLOR_1;
    }
    else {
      waterColor = WATER_COLOR_2;
      landColor = TERRAIN_COLOR_2;
    }

    if (SHADING_MODE === SOLID_SHADING_MODE) {
      if (material1 === CityTour.Terrain.WATER && material2 === CityTour.Terrain.WATER && material3 == CityTour.Terrain.WATER) {
        reusableTriangle.faces[0].vertexColors = [waterColor, waterColor, waterColor];
      }
      else {
        reusableTriangle.faces[0].vertexColors = [landColor, landColor, landColor];
      }
    }
    else {
      reusableTriangle.faces[0].vertexColors = [(material1 === CityTour.Terrain.WATER) ? waterColor : landColor,
                                                (material2 === CityTour.Terrain.WATER) ? waterColor : landColor,
                                                (material3 === CityTour.Terrain.WATER) ? waterColor : landColor,];
    }

    reusableTriangle.computeFaceNormals();

    return reusableTriangle;
  };

  var terrainGeometryBuilder = {};

  terrainGeometryBuilder.build = function(terrain, roadNetwork) {
    var mapX, mapZ, triangle;
    var leftRoad, topRoad, bottomRoad, rightRoad;
    var topLeftRoad, topRightRoad, bottomLeftRoad, bottomRightRoad;
    var topLeftX, topLeftZ, topRightX, topRightZ, bottomLeftX, bottomLeftZ, bottomRightX, bottomRightZ;
    var topLeftHeight, topRightHeight, bottomLeftHeight, bottomRightHeight;
    var topLeftMaterial, topRightMaterial, bottomLeftMaterial, bottomRightMaterial;

    var halfStreetWidth = CityTour.Config.STREET_WIDTH / 2;
    var halfStreetDepth = CityTour.Config.STREET_DEPTH / 2;

    var triangleWidth = 1 / terrain.subDivisions();
    var triangleDepth = 1 / terrain.subDivisions();

    var terrainGeometry = new THREE.Geometry();
    var terrainMaterial = new THREE.MeshLambertMaterial({ vertexColors: THREE.VertexColors });

    for (mapX = terrain.minColumn(); mapX < terrain.maxColumn(); mapX += triangleWidth) {
      for (mapZ = terrain.minRow(); mapZ < terrain.maxRow(); mapZ += triangleDepth) {
        topLeftRoad     = roadNetwork.getIntersectionSurfaceType(mapX, mapZ) === CityTour.RoadNetwork.TERRAIN_SURFACE;
        topRightRoad    = roadNetwork.getIntersectionSurfaceType(mapX + triangleWidth, mapZ) === CityTour.RoadNetwork.TERRAIN_SURFACE;
        bottomLeftRoad  = roadNetwork.getIntersectionSurfaceType(mapX, mapZ + triangleDepth) === CityTour.RoadNetwork.TERRAIN_SURFACE;
        bottomRightRoad = roadNetwork.getIntersectionSurfaceType(mapX + triangleWidth, mapZ + triangleDepth) === CityTour.RoadNetwork.TERRAIN_SURFACE;

        leftRoad = (Math.floor(mapX) === mapX) && roadNetwork.hasEdgeBetween(mapX, Math.floor(mapZ), mapX, Math.floor(mapZ) + 1, CityTour.RoadNetwork.TERRAIN_SURFACE);
        rightRoad = (Math.ceil(mapX + triangleWidth) === (mapX + triangleWidth)) && roadNetwork.hasEdgeBetween(mapX + triangleWidth, Math.floor(mapZ), mapX + triangleWidth, Math.floor(mapZ) + 1, CityTour.RoadNetwork.TERRAIN_SURFACE);
        topRoad = (Math.floor(mapZ) === mapZ) && roadNetwork.hasEdgeBetween(Math.floor(mapX), mapZ, Math.floor(mapX) + 1, mapZ, CityTour.RoadNetwork.TERRAIN_SURFACE);
        bottomRoad = (Math.ceil(mapZ + triangleDepth) === (mapZ + triangleDepth)) && roadNetwork.hasEdgeBetween(Math.floor(mapX), mapZ + triangleDepth, Math.floor(mapX) + 1, mapZ + triangleDepth, CityTour.RoadNetwork.TERRAIN_SURFACE);

        topLeftX = CityTour.Coordinates.mapXToSceneX(mapX);
        topLeftZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
        if (topLeftRoad || leftRoad) {
          topLeftX += halfStreetWidth;
        }
        if (topLeftRoad || topRoad) {
          topLeftZ += halfStreetDepth;
        }

        topRightX = CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth);
        topRightZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
        if (topRightRoad || rightRoad) {
          topRightX -= halfStreetWidth;
        }
        if (topRightRoad || topRoad) {
          topRightZ += halfStreetDepth;
        }

        bottomLeftX = CityTour.Coordinates.mapXToSceneX(mapX);
        bottomLeftZ = CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth);
        if (bottomLeftRoad || leftRoad) {
          bottomLeftX += halfStreetWidth;
        }
        if (bottomLeftRoad || bottomRoad) {
          bottomLeftZ -= halfStreetDepth;
        }

        bottomRightX = CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth);
        bottomRightZ = CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth);
        if (bottomRightRoad || rightRoad) {
          bottomRightX -= halfStreetWidth;
        }
        if (bottomRightRoad || bottomRoad) {
          bottomRightZ -= halfStreetDepth;
        }

        topLeftHeight = terrain.heightAtCoordinates(mapX, mapZ);
        topRightHeight = terrain.heightAtCoordinates(mapX + triangleWidth, mapZ);
        bottomLeftHeight = terrain.heightAtCoordinates(mapX, mapZ + triangleDepth);
        bottomRightHeight = terrain.heightAtCoordinates(mapX + triangleWidth, mapZ + triangleDepth);

        topLeftMaterial = terrain.materialAtCoordinates(mapX, mapZ);
        topRightMaterial = terrain.materialAtCoordinates(mapX + triangleWidth, mapZ);
        bottomLeftMaterial = terrain.materialAtCoordinates(mapX, mapZ + triangleDepth);
        bottomRightMaterial = terrain.materialAtCoordinates(mapX + triangleWidth, mapZ + triangleDepth);

        // Core triangles
        triangle = buildTriangleGeometry(topLeftX,    topLeftHeight,    topLeftZ, topLeftMaterial,
                                         bottomLeftX, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                         topRightX,   topRightHeight,   topRightZ, topRightMaterial, 1);
        terrainGeometry.merge(triangle);

        triangle = buildTriangleGeometry(bottomLeftX,  bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                         bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                         topRightX,    topRightHeight, topRightZ, topRightMaterial, 2);
        terrainGeometry.merge(triangle);

        // Extra left-side triangles
        if (!leftRoad) {
          if (topLeftRoad && !bottomLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), topLeftHeight, topLeftZ, topLeftMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX), bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             topLeftX, topLeftHeight, topLeftZ, topLeftMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (bottomLeftRoad && !topLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), topLeftHeight, topLeftZ, topLeftMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX), bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (topLeftRoad && bottomLeftRoad) {
            triangle = buildTriangleGeometry(bottomLeftX - CityTour.Config.STREET_WIDTH, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             topLeftX, topLeftHeight, topLeftZ, topLeftMaterial, 2);
            terrainGeometry.merge(triangle);
          }
        }

        // Extra right-side triangles
        if (!rightRoad) {
          if (topRightRoad && !bottomRightRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), topRightHeight, topRightZ, topRightMaterial,
                                             topRightX, topRightHeight, topRightZ, topRightMaterial, 1);

            terrainGeometry.merge(triangle);
          }

          if (bottomRightRoad && !topRightRoad) {
            triangle = buildTriangleGeometry(bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), topRightHeight, topRightZ, topRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }

          if (topRightRoad && bottomRightRoad) {
            triangle = buildTriangleGeometry(topRightX,    topRightHeight, topRightZ, topRightMaterial,
                                             bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             topRightX + CityTour.Config.STREET_WIDTH, topRightHeight, topRightZ, topRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }
        }

        // Extra top-side triangles
        if (!topRoad) {
          if (topLeftRoad && !topRightRoad) {
            triangle = buildTriangleGeometry(topLeftX,  topLeftHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topLeftMaterial,
                                             topLeftX,  topLeftHeight, topLeftZ, topLeftMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), topRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topRightMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (topRightRoad && !topLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), topLeftHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topLeftMaterial,
                                             topRightX, topRightHeight, topRightZ, topRightMaterial,
                                             topRightX, topRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topRightMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (topLeftRoad && topRightRoad) {
            triangle = buildTriangleGeometry(topLeftX, topLeftHeight, topLeftZ, topLeftMaterial,
                                             topRightX, topRightHeight, topRightZ, topRightMaterial,
                                             topRightX, topRightHeight, topRightZ - CityTour.Config.STREET_DEPTH, topRightMaterial, 2);

            terrainGeometry.merge(triangle);
          }
        }

        // Extra bottom-side triangles
        if (!bottomRoad) {
          if (bottomLeftRoad && !bottomRightRoad) {
            triangle = buildTriangleGeometry(bottomLeftX,  bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX,  bottomLeftHeight, CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth), bottomLeftMaterial,
                                             bottomRightX, bottomRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth), bottomRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }

          if (bottomRightRoad && !bottomLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomRightX, bottomRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth), bottomRightMaterial,
                                             bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }

          if (bottomLeftRoad && bottomRightRoad) {
            triangle = buildTriangleGeometry(bottomLeftX,  bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX,  bottomLeftHeight, bottomLeftZ + CityTour.Config.STREET_DEPTH, bottomLeftMaterial,
                                             bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial, 1);

            terrainGeometry.merge(triangle);
          }
        }

      }
    }

    return [new THREE.Mesh(terrainGeometry, terrainMaterial)];
  };

  return terrainGeometryBuilder;
};
<commit_msg>Adding vertical sides to terrain geometry, to give model more weight<commit_after>"use strict";

var CityTour = CityTour || {};
CityTour.Scene = CityTour.Scene || {};

CityTour.Scene.TerrainGeometryBuilder = function() {
  var TERRAIN_COLOR_1 = new THREE.Color(0.0, 0.48, 0.0);
  var TERRAIN_COLOR_2 = new THREE.Color(0.0, 0.49, 0.0);
  var WATER_COLOR_1 = new THREE.Color(0.1, 0.2, 1.0);
  var WATER_COLOR_2 = new THREE.Color(0.1, 0.19, 1.0);

  var SOLID_SHADING_MODE = 1;
  var GRADIENT_SHADING_MODE = 2;
  var SHADING_MODE = SOLID_SHADING_MODE;

  var SIDE_BOTTOM_HEIGHT = -100;

  var reusableTriangle = new THREE.Geometry();
  reusableTriangle.faces = [new THREE.Face3(0, 1, 2)];

  var buildTriangleGeometry = function(x1, y1, z1, material1, x2, y2, z2, material2, x3, y3, z3, material3, color_variant) {
    var waterColor, landColor;

    reusableTriangle.vertices = [ new THREE.Vector3(x1, y1, z1), new THREE.Vector3(x2, y2, z2), new THREE.Vector3(x3, y3, z3) ];

    if (color_variant === 1) {
      waterColor = WATER_COLOR_1;
      landColor = TERRAIN_COLOR_1;
    }
    else {
      waterColor = WATER_COLOR_2;
      landColor = TERRAIN_COLOR_2;
    }

    if (SHADING_MODE === SOLID_SHADING_MODE) {
      if (material1 === CityTour.Terrain.WATER && material2 === CityTour.Terrain.WATER && material3 == CityTour.Terrain.WATER) {
        reusableTriangle.faces[0].vertexColors = [waterColor, waterColor, waterColor];
      }
      else {
        reusableTriangle.faces[0].vertexColors = [landColor, landColor, landColor];
      }
    }
    else {
      reusableTriangle.faces[0].vertexColors = [(material1 === CityTour.Terrain.WATER) ? waterColor : landColor,
                                                (material2 === CityTour.Terrain.WATER) ? waterColor : landColor,
                                                (material3 === CityTour.Terrain.WATER) ? waterColor : landColor,];
    }

    reusableTriangle.computeFaceNormals();

    return reusableTriangle;
  };

  var terrainGeometryBuilder = {};

  terrainGeometryBuilder.build = function(terrain, roadNetwork) {
    var mapX, mapZ, triangle;
    var sceneX, sceneZ;
    var leftRoad, topRoad, bottomRoad, rightRoad;
    var topLeftRoad, topRightRoad, bottomLeftRoad, bottomRightRoad;
    var topLeftX, topLeftZ, topRightX, topRightZ, bottomLeftX, bottomLeftZ, bottomRightX, bottomRightZ;
    var topLeftHeight, topRightHeight, bottomLeftHeight, bottomRightHeight;
    var topLeftMaterial, topRightMaterial, bottomLeftMaterial, bottomRightMaterial;

    var halfStreetWidth = CityTour.Config.STREET_WIDTH / 2;
    var halfStreetDepth = CityTour.Config.STREET_DEPTH / 2;

    var triangleWidth = 1 / terrain.subDivisions();
    var triangleDepth = 1 / terrain.subDivisions();

    var terrainGeometry = new THREE.Geometry();
    var terrainMaterial = new THREE.MeshLambertMaterial({ vertexColors: THREE.VertexColors });

    // North vertical face
    mapZ = CityTour.Config.TERRAIN_ROWS / 2;
    sceneZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
    for (mapX = terrain.minColumn(); mapX < terrain.maxColumn(); mapX += triangleWidth) {
      var leftX = CityTour.Coordinates.mapXToSceneX(mapX);
      var rightX = CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth);

      var leftHeight = terrain.heightAtCoordinates(mapX, mapZ);
      var rightHeight = terrain.heightAtCoordinates(mapX + triangleWidth, mapZ);

      var leftMaterial = terrain.materialAtCoordinates(mapX, mapZ);
      var rightMaterial = terrain.materialAtCoordinates(mapX + triangleWidth, mapZ);
      var material = (leftMaterial === CityTour.Terrain.WATER && rightMaterial === CityTour.Terrain.WATER) ? CityTour.Terrain.WATER : CityTour.Terrain.LAND;

      triangle = buildTriangleGeometry(leftX,  leftHeight,         sceneZ, material,
                                       leftX,  SIDE_BOTTOM_HEIGHT, sceneZ, material,
                                       rightX, rightHeight,        sceneZ, material,
                                       1);
      terrainGeometry.merge(triangle);

      triangle = buildTriangleGeometry(leftX,  SIDE_BOTTOM_HEIGHT, sceneZ, material,
                                       rightX, SIDE_BOTTOM_HEIGHT, sceneZ, material,
                                       rightX, rightHeight,        sceneZ, material,
                                       1);
      terrainGeometry.merge(triangle);
    }

    // South vertical face
    mapZ = -(CityTour.Config.TERRAIN_ROWS / 2);
    sceneZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
    for (mapX = terrain.minColumn(); mapX < terrain.maxColumn(); mapX += triangleWidth) {
      var leftX = CityTour.Coordinates.mapXToSceneX(mapX);
      var rightX = CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth);

      var leftHeight = terrain.heightAtCoordinates(mapX, mapZ);
      var rightHeight = terrain.heightAtCoordinates(mapX + triangleWidth, mapZ);

      var leftMaterial = terrain.materialAtCoordinates(mapX, mapZ);
      var rightMaterial = terrain.materialAtCoordinates(mapX + triangleWidth, mapZ);
      var material = (leftMaterial === CityTour.Terrain.WATER && rightMaterial === CityTour.Terrain.WATER) ? CityTour.Terrain.WATER : CityTour.Terrain.LAND;

      triangle = buildTriangleGeometry(rightX, rightHeight,        sceneZ, material,
                                       leftX,  SIDE_BOTTOM_HEIGHT, sceneZ, material,
                                       leftX,  leftHeight,         sceneZ, material,
                                       1);
      terrainGeometry.merge(triangle);

      triangle = buildTriangleGeometry(leftX,  SIDE_BOTTOM_HEIGHT, sceneZ, material,
                                       rightX, rightHeight,        sceneZ, material,
                                       rightX, SIDE_BOTTOM_HEIGHT, sceneZ, material,
                                       1);
      terrainGeometry.merge(triangle);
    }

    // West vertical face
    mapX = -(CityTour.Config.TERRAIN_COLUMNS / 2);
    sceneX = CityTour.Coordinates.mapXToSceneX(mapX);
    for (mapZ = terrain.minRow(); mapZ < terrain.maxRow(); mapZ += triangleDepth) {
      var topZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
      var bottomZ = CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth);

      var topHeight = terrain.heightAtCoordinates(mapX, mapZ);
      var bottomHeight = terrain.heightAtCoordinates(mapX, mapZ + triangleDepth);

      var topMaterial = terrain.materialAtCoordinates(mapX, mapZ);
      var bottomMaterial = terrain.materialAtCoordinates(mapX, mapZ + triangleDepth);
      var material = (topMaterial === CityTour.Terrain.WATER && bottomMaterial === CityTour.Terrain.WATER) ? CityTour.Terrain.WATER : CityTour.Terrain.LAND;

      triangle = buildTriangleGeometry(sceneX, SIDE_BOTTOM_HEIGHT, topZ,    material,
                                       sceneX, bottomHeight,       bottomZ, material,
                                       sceneX, topHeight,          topZ,    material,
                                       1);
      terrainGeometry.merge(triangle);

      triangle = buildTriangleGeometry(sceneX, SIDE_BOTTOM_HEIGHT, topZ,    material,
                                       sceneX, SIDE_BOTTOM_HEIGHT, bottomZ, material,
                                       sceneX, bottomHeight,       bottomZ, material,
                                       1);
      terrainGeometry.merge(triangle);
    }

    // East vertical face
    mapX = CityTour.Config.TERRAIN_COLUMNS / 2;
    sceneX = CityTour.Coordinates.mapXToSceneX(mapX);
    for (mapZ = terrain.minRow(); mapZ < terrain.maxRow(); mapZ += triangleDepth) {
      var topZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
      var bottomZ = CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth);

      var topHeight = terrain.heightAtCoordinates(mapX, mapZ);
      var bottomHeight = terrain.heightAtCoordinates(mapX, mapZ + triangleDepth);

      var topMaterial = terrain.materialAtCoordinates(mapX, mapZ);
      var bottomMaterial = terrain.materialAtCoordinates(mapX, mapZ + triangleDepth);
      var material = (topMaterial === CityTour.Terrain.WATER && bottomMaterial === CityTour.Terrain.WATER) ? CityTour.Terrain.WATER : CityTour.Terrain.LAND;

      triangle = buildTriangleGeometry(sceneX, SIDE_BOTTOM_HEIGHT, bottomZ, material,
                                       sceneX, topHeight,          topZ,    material,
                                       sceneX, bottomHeight,       bottomZ, material,
                                       1);
      terrainGeometry.merge(triangle);

      triangle = buildTriangleGeometry(sceneX, SIDE_BOTTOM_HEIGHT, bottomZ, material,
                                       sceneX, SIDE_BOTTOM_HEIGHT, topZ,    material,
                                       sceneX, topHeight,          topZ,    material,
                                       1);
      terrainGeometry.merge(triangle);
    }

    // Main terrain
    for (mapX = terrain.minColumn(); mapX < terrain.maxColumn(); mapX += triangleWidth) {
      for (mapZ = terrain.minRow(); mapZ < terrain.maxRow(); mapZ += triangleDepth) {
        topLeftRoad     = roadNetwork.getIntersectionSurfaceType(mapX, mapZ) === CityTour.RoadNetwork.TERRAIN_SURFACE;
        topRightRoad    = roadNetwork.getIntersectionSurfaceType(mapX + triangleWidth, mapZ) === CityTour.RoadNetwork.TERRAIN_SURFACE;
        bottomLeftRoad  = roadNetwork.getIntersectionSurfaceType(mapX, mapZ + triangleDepth) === CityTour.RoadNetwork.TERRAIN_SURFACE;
        bottomRightRoad = roadNetwork.getIntersectionSurfaceType(mapX + triangleWidth, mapZ + triangleDepth) === CityTour.RoadNetwork.TERRAIN_SURFACE;

        leftRoad = (Math.floor(mapX) === mapX) && roadNetwork.hasEdgeBetween(mapX, Math.floor(mapZ), mapX, Math.floor(mapZ) + 1, CityTour.RoadNetwork.TERRAIN_SURFACE);
        rightRoad = (Math.ceil(mapX + triangleWidth) === (mapX + triangleWidth)) && roadNetwork.hasEdgeBetween(mapX + triangleWidth, Math.floor(mapZ), mapX + triangleWidth, Math.floor(mapZ) + 1, CityTour.RoadNetwork.TERRAIN_SURFACE);
        topRoad = (Math.floor(mapZ) === mapZ) && roadNetwork.hasEdgeBetween(Math.floor(mapX), mapZ, Math.floor(mapX) + 1, mapZ, CityTour.RoadNetwork.TERRAIN_SURFACE);
        bottomRoad = (Math.ceil(mapZ + triangleDepth) === (mapZ + triangleDepth)) && roadNetwork.hasEdgeBetween(Math.floor(mapX), mapZ + triangleDepth, Math.floor(mapX) + 1, mapZ + triangleDepth, CityTour.RoadNetwork.TERRAIN_SURFACE);

        topLeftX = CityTour.Coordinates.mapXToSceneX(mapX);
        topLeftZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
        if (topLeftRoad || leftRoad) {
          topLeftX += halfStreetWidth;
        }
        if (topLeftRoad || topRoad) {
          topLeftZ += halfStreetDepth;
        }

        topRightX = CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth);
        topRightZ = CityTour.Coordinates.mapZToSceneZ(mapZ);
        if (topRightRoad || rightRoad) {
          topRightX -= halfStreetWidth;
        }
        if (topRightRoad || topRoad) {
          topRightZ += halfStreetDepth;
        }

        bottomLeftX = CityTour.Coordinates.mapXToSceneX(mapX);
        bottomLeftZ = CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth);
        if (bottomLeftRoad || leftRoad) {
          bottomLeftX += halfStreetWidth;
        }
        if (bottomLeftRoad || bottomRoad) {
          bottomLeftZ -= halfStreetDepth;
        }

        bottomRightX = CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth);
        bottomRightZ = CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth);
        if (bottomRightRoad || rightRoad) {
          bottomRightX -= halfStreetWidth;
        }
        if (bottomRightRoad || bottomRoad) {
          bottomRightZ -= halfStreetDepth;
        }

        topLeftHeight = terrain.heightAtCoordinates(mapX, mapZ);
        topRightHeight = terrain.heightAtCoordinates(mapX + triangleWidth, mapZ);
        bottomLeftHeight = terrain.heightAtCoordinates(mapX, mapZ + triangleDepth);
        bottomRightHeight = terrain.heightAtCoordinates(mapX + triangleWidth, mapZ + triangleDepth);

        topLeftMaterial = terrain.materialAtCoordinates(mapX, mapZ);
        topRightMaterial = terrain.materialAtCoordinates(mapX + triangleWidth, mapZ);
        bottomLeftMaterial = terrain.materialAtCoordinates(mapX, mapZ + triangleDepth);
        bottomRightMaterial = terrain.materialAtCoordinates(mapX + triangleWidth, mapZ + triangleDepth);

        // Core triangles
        triangle = buildTriangleGeometry(topLeftX,    topLeftHeight,    topLeftZ, topLeftMaterial,
                                         bottomLeftX, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                         topRightX,   topRightHeight,   topRightZ, topRightMaterial, 1);
        terrainGeometry.merge(triangle);

        triangle = buildTriangleGeometry(bottomLeftX,  bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                         bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                         topRightX,    topRightHeight, topRightZ, topRightMaterial, 2);
        terrainGeometry.merge(triangle);

        // Extra left-side triangles
        if (!leftRoad) {
          if (topLeftRoad && !bottomLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), topLeftHeight, topLeftZ, topLeftMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX), bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             topLeftX, topLeftHeight, topLeftZ, topLeftMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (bottomLeftRoad && !topLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), topLeftHeight, topLeftZ, topLeftMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX), bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (topLeftRoad && bottomLeftRoad) {
            triangle = buildTriangleGeometry(bottomLeftX - CityTour.Config.STREET_WIDTH, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX, bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             topLeftX, topLeftHeight, topLeftZ, topLeftMaterial, 2);
            terrainGeometry.merge(triangle);
          }
        }

        // Extra right-side triangles
        if (!rightRoad) {
          if (topRightRoad && !bottomRightRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), topRightHeight, topRightZ, topRightMaterial,
                                             topRightX, topRightHeight, topRightZ, topRightMaterial, 1);

            terrainGeometry.merge(triangle);
          }

          if (bottomRightRoad && !topRightRoad) {
            triangle = buildTriangleGeometry(bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), topRightHeight, topRightZ, topRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }

          if (topRightRoad && bottomRightRoad) {
            triangle = buildTriangleGeometry(topRightX,    topRightHeight, topRightZ, topRightMaterial,
                                             bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial,
                                             topRightX + CityTour.Config.STREET_WIDTH, topRightHeight, topRightZ, topRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }
        }

        // Extra top-side triangles
        if (!topRoad) {
          if (topLeftRoad && !topRightRoad) {
            triangle = buildTriangleGeometry(topLeftX,  topLeftHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topLeftMaterial,
                                             topLeftX,  topLeftHeight, topLeftZ, topLeftMaterial,
                                             CityTour.Coordinates.mapXToSceneX(mapX + triangleWidth), topRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topRightMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (topRightRoad && !topLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), topLeftHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topLeftMaterial,
                                             topRightX, topRightHeight, topRightZ, topRightMaterial,
                                             topRightX, topRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ), topRightMaterial, 2);
            terrainGeometry.merge(triangle);
          }

          if (topLeftRoad && topRightRoad) {
            triangle = buildTriangleGeometry(topLeftX, topLeftHeight, topLeftZ, topLeftMaterial,
                                             topRightX, topRightHeight, topRightZ, topRightMaterial,
                                             topRightX, topRightHeight, topRightZ - CityTour.Config.STREET_DEPTH, topRightMaterial, 2);

            terrainGeometry.merge(triangle);
          }
        }

        // Extra bottom-side triangles
        if (!bottomRoad) {
          if (bottomLeftRoad && !bottomRightRoad) {
            triangle = buildTriangleGeometry(bottomLeftX,  bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX,  bottomLeftHeight, CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth), bottomLeftMaterial,
                                             bottomRightX, bottomRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth), bottomRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }

          if (bottomRightRoad && !bottomLeftRoad) {
            triangle = buildTriangleGeometry(CityTour.Coordinates.mapXToSceneX(mapX), bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomRightX, bottomRightHeight, CityTour.Coordinates.mapZToSceneZ(mapZ + triangleDepth), bottomRightMaterial,
                                             bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial, 1);
            terrainGeometry.merge(triangle);
          }

          if (bottomLeftRoad && bottomRightRoad) {
            triangle = buildTriangleGeometry(bottomLeftX,  bottomLeftHeight, bottomLeftZ, bottomLeftMaterial,
                                             bottomLeftX,  bottomLeftHeight, bottomLeftZ + CityTour.Config.STREET_DEPTH, bottomLeftMaterial,
                                             bottomRightX, bottomRightHeight, bottomRightZ, bottomRightMaterial, 1);

            terrainGeometry.merge(triangle);
          }
        }

      }
    }

    return [new THREE.Mesh(terrainGeometry, terrainMaterial)];
  };

  return terrainGeometryBuilder;
};
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../common/common.js';

/** @enum {symbol} */
export const IssueCategory = {
  CrossOriginEmbedderPolicy: Symbol('CrossOriginEmbedderPolicy'),
  MixedContent: Symbol('MixedContent'),
  SameSiteCookie: Symbol('SameSiteCookie'),
  Other: Symbol('Other')
};

/** @enum {symbol} */
export const IssueKind = {
  BreakingChange: Symbol('BreakingChange'),
};

/**
 * @typedef {{
  *            title:string,
  *            message: (function():!Element),
  *            issueKind: !IssueKind,
  *            link: string,
  *            linkTitle: string
  *          }}
  */
// @ts-ignore typedef
export let IssueDescription;  // eslint-disable-line no-unused-vars

/**
 * @typedef {{
 *            columnNumber: (number|undefined),
 *            lineNumber: number,
 *            url: string
 *          }}
 */
// @ts-ignore typedef
export let AffectedSource;  // eslint-disable-line no-unused-vars

/**
 * @abstract
 */
export class Issue extends Common.ObjectWrapper.ObjectWrapper {
  /**
   * @param {string} code
   */
  constructor(code) {
    super();
    /** @type {string} */
    this._code = code;
  }

  /**
   * @return {string}
   */
  code() {
    return this._code;
  }

  /**
   * @return {string}
   */
  primaryKey() {
    throw new Error('Not implemented');
  }

  /**
   * @return {!Iterable<!Protocol.Audits.AffectedCookie>}
   */
  cookies() {
    return [];
  }

  /**
   * @returns {!Iterable<!Protocol.Audits.MixedContentIssueDetails>}
   */
  mixedContents() {
    return [];
  }

  /**
   * @return {!Iterable<!Protocol.Audits.AffectedRequest>}
   */
  requests() {
    return [];
  }

  /**
   * @returns {!Iterable<!AffectedSource>}
   */
  sources() {
    return [];
  }

  /**
   * @param {string} requestId
   * @return {boolean}
   */
  isAssociatedWithRequestId(requestId) {
    for (const request of this.requests()) {
      if (request.requestId === requestId) {
        return true;
      }
    }
    return false;
  }

  /**
   * @return {?IssueDescription}
   */
  getDescription() {
    throw new Error('Not implemented');
  }

  /**
   * @return {!IssueCategory}
   */
  getCategory() {
    throw new Error('Not implemented');
  }
}

/**
 * An `AggregatedIssue` representes a number of `Issue` objects that is displayed together. Currently only grouping by
 * issue code, is supported. The class provides helpers to support displaying of all resources that are affected by
 * the aggregated issues.
 */
export class AggregatedIssue extends Issue {
  /**
   * @param {string} code
   */
  constructor(code) {
    super(code);
    /** @type {!Map<string, !Protocol.Audits.AffectedCookie>} */
    this._cookies = new Map();
    /** @type {!Map<string, !Protocol.Audits.AffectedRequest>} */
    this._requests = new Map();
    /** @type {?Issue} */
    this._representative = null;
  }

  /**
   * @override
   */
  primaryKey() {
    // There should only be one aggregated issue per code.
    return this.code();
  }

  /**
   * @override
   * @return {!Iterable<!Protocol.Audits.AffectedCookie>}
   */
  cookies() {
    return this._cookies.values();
  }

  /**
   * @override
   * @return {!Iterable<!Protocol.Audits.AffectedRequest>}
   */
  requests() {
    return this._requests.values();
  }

  /**
   * @override
   */
  getDescription() {
    if (this._representative) {
      return this._representative.getDescription();
    }
    return null;
  }

  /**
   * @override
   * @return {!IssueCategory}
   */
  getCategory() {
    if (this._representative) {
      return this._representative.getCategory();
    }
    return IssueCategory.Other;
  }

  /**
   * @param {!Issue} issue
   */
  addInstance(issue) {
    if (!this._representative) {
      this._representative = issue;
    }
    for (const cookie of issue.cookies()) {
      const key = JSON.stringify(cookie);
      if (!this._cookies.has(key)) {
        this._cookies.set(key, cookie);
      }
    }
    for (const request of issue.requests()) {
      if (!this._requests.has(request.requestId)) {
        this._requests.set(request.requestId, request);
      }
    }
  }
}
<commit_msg>[cleanup] Remove dead 'AggregatedIssue' class from Issue.js<commit_after>// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../common/common.js';

/** @enum {symbol} */
export const IssueCategory = {
  CrossOriginEmbedderPolicy: Symbol('CrossOriginEmbedderPolicy'),
  MixedContent: Symbol('MixedContent'),
  SameSiteCookie: Symbol('SameSiteCookie'),
  Other: Symbol('Other')
};

/** @enum {symbol} */
export const IssueKind = {
  BreakingChange: Symbol('BreakingChange'),
};

/**
 * @typedef {{
  *            title:string,
  *            message: (function():!Element),
  *            issueKind: !IssueKind,
  *            link: string,
  *            linkTitle: string
  *          }}
  */
// @ts-ignore typedef
export let IssueDescription;  // eslint-disable-line no-unused-vars

/**
 * @typedef {{
 *            columnNumber: (number|undefined),
 *            lineNumber: number,
 *            url: string
 *          }}
 */
// @ts-ignore typedef
export let AffectedSource;  // eslint-disable-line no-unused-vars

/**
 * @abstract
 */
export class Issue extends Common.ObjectWrapper.ObjectWrapper {
  /**
   * @param {string} code
   */
  constructor(code) {
    super();
    /** @type {string} */
    this._code = code;
  }

  /**
   * @return {string}
   */
  code() {
    return this._code;
  }

  /**
   * @return {string}
   */
  primaryKey() {
    throw new Error('Not implemented');
  }

  /**
   * @return {!Iterable<!Protocol.Audits.AffectedCookie>}
   */
  cookies() {
    return [];
  }

  /**
   * @returns {!Iterable<!Protocol.Audits.MixedContentIssueDetails>}
   */
  mixedContents() {
    return [];
  }

  /**
   * @return {!Iterable<!Protocol.Audits.AffectedRequest>}
   */
  requests() {
    return [];
  }

  /**
   * @returns {!Iterable<!AffectedSource>}
   */
  sources() {
    return [];
  }

  /**
   * @param {string} requestId
   * @return {boolean}
   */
  isAssociatedWithRequestId(requestId) {
    for (const request of this.requests()) {
      if (request.requestId === requestId) {
        return true;
      }
    }
    return false;
  }

  /**
   * @return {?IssueDescription}
   */
  getDescription() {
    throw new Error('Not implemented');
  }

  /**
   * @return {!IssueCategory}
   */
  getCategory() {
    throw new Error('Not implemented');
  }
}
<|endoftext|>


<commit_before>// main.js
var React = require('react');
var ReactDOM = require('react-dom');
import { Provider } from 'react-redux'
import rpc from 'app/rpc'
import store from 'app/utils/store'
import plugin from 'app/utils/plugin'

require("sass/serverboards.sass")

import Main from 'app/containers/main.js'

import Flash from 'app/flash'
import FlashActions from 'app/actions/flash'

Flash.log=function(message, options={}){
  options=Object.assign({}, {timeout: message.length*100}, options)
  store.dispatch( FlashActions.add(message, options) )
  var close =function(){
    store.dispatch(FlashActions.remove(message))
  }
  setTimeout(close, options.timeout)
  return {close}
}

window.Serverboards = {
  rpc,
  store,
  Flash,
  React,
  add_screen: plugin.add_screen,
}

ReactDOM.render(
  (
    <Provider store={store}>
      <Main/>
    </Provider>
  ),
  document.getElementById('react')
);
<commit_msg>Increased time for messages<commit_after>// main.js
var React = require('react');
var ReactDOM = require('react-dom');
import { Provider } from 'react-redux'
import rpc from 'app/rpc'
import store from 'app/utils/store'
import plugin from 'app/utils/plugin'

require("sass/serverboards.sass")

import Main from 'app/containers/main.js'

import Flash from 'app/flash'
import FlashActions from 'app/actions/flash'

Flash.log=function(message, options={}){
  options=Object.assign({}, {timeout: 1000 + (message.length*200)}, options)
  store.dispatch( FlashActions.add(message, options) )
  var close =function(){
    store.dispatch(FlashActions.remove(message))
  }
  setTimeout(close, options.timeout)
  return {close}
}

window.Serverboards = {
  rpc,
  store,
  Flash,
  React,
  add_screen: plugin.add_screen,
}

ReactDOM.render(
  (
    <Provider store={store}>
      <Main/>
    </Provider>
  ),
  document.getElementById('react')
);
<|endoftext|>


<commit_before>import EmberRouter from '@ember/routing/router';
import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import config from './config/environment';

const Router = EmberRouter.extend({
  location: config.locationType,
  rootURL: config.rootURL,
  metrics: service(),

  didTransition() {
    this._super(...arguments);
    this._trackPage();
  },

  _trackPage() {
    scheduleOnce('afterRender', this, () => {
      const page = this.get('url');
      const title = this.getWithDefault('currentRouteName', 'unknown');

      this.get('metrics').trackPage({ page, title });
    });
  }
});

Router.map(function() {
  this.route('find-broadcasts');
  this.route('invoice');
  this.route('statistics');
  this.route('imprint');
  this.route('history');
  this.route('data-privacy');

  this.route('authentication', function() {
    this.route('callback');
  });
  this.route('visualize', function() {
    this.route('geo');
    this.route('diff', function() {
      this.route('media');
      this.route('stations');
    });
    this.route('graph');
    this.route('time', function() {
      this.route('progress', { path: '/progress/:broadcast_id' });
    });
    this.route('demography');
  });
  this.route('about-us');
  this.route('broadcast', { path: '/broadcast/:broadcast_id' }, function() {
    this.route('edit');
  });
  this.route('404', { path: '*' });
});

export default Router;
<commit_msg>Fix deprecation warning `didTransition`<commit_after>import EmberRouter from '@ember/routing/router';
import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import config from './config/environment';

const Router = EmberRouter.extend({
  location: config.locationType,
  rootURL: config.rootURL,

  metrics: service(),
  router: service(),

  init() {
    this._super(...arguments);

    this.on('routeDidChange', () => {
      const page = this.router.currentURL;
      const title = this.router.currentRouteName || 'unknown';

      this.metrics.trackPage({ page, title });
    });
  }
});

Router.map(function() {
  this.route('find-broadcasts');
  this.route('invoice');
  this.route('statistics');
  this.route('imprint');
  this.route('history');
  this.route('data-privacy');

  this.route('authentication', function() {
    this.route('callback');
  });
  this.route('visualize', function() {
    this.route('geo');
    this.route('diff', function() {
      this.route('media');
      this.route('stations');
    });
    this.route('graph');
    this.route('time', function() {
      this.route('progress', { path: '/progress/:broadcast_id' });
    });
    this.route('demography');
  });
  this.route('about-us');
  this.route('broadcast', { path: '/broadcast/:broadcast_id' }, function() {
    this.route('edit');
  });
  this.route('404', { path: '*' });
});

export default Router;
<|endoftext|>


<commit_before>import minimModule from 'minim';
import minimParseResult from 'minim-parse-result';

const minim = minimModule.namespace()
  .use(minimParseResult);

/*
 * Find an adapter by a given media type and method name, which should be
 * either `parse` or `serialize`. If no adapter is found, then
 * undefined is returned.
 */
function findAdapter(adapters, mediaType, method) {
  for (let i = 0; i < adapters.length; i += 1) {
    if (adapters[i].mediaTypes.indexOf(mediaType) !== -1 && adapters[i][method]) {
      return adapters[i];
    }
  }

  return null;
}

class Fury {
  constructor() {
    this.adapters = [];
  }

  /*
   * Register to use an adapter with this Fury instance.
   */
  use(adapter) {
    this.adapters.push(adapter);
    return this;
  }

  /*
   * Load serialized refract elements into Javascript objects.
   */
  // eslint-disable-next-line class-methods-use-this
  load(elements) {
    return minim.fromRefract(elements);
  }

  findAdapter(source, mediaType, method) {
    let adapter;

    if (mediaType) {
      adapter = findAdapter(this.adapters, mediaType, method);
    } else {
      for (let i = 0; i < this.adapters.length; i += 1) {
        const current = this.adapters[i];

        if (current.detect && current.detect(source) && current[method]) {
          adapter = this.adapters[i];
          break;
        }
      }
    }

    return adapter;
  }

  validate({ source, mediaType, adapterOptions }, done) {
    const adapter = this.findAdapter(source, mediaType, 'validate');

    if (!adapter) {
      return this.parse({ source, mediaType, adapterOptions }, (err, result) => {
        if (result && result.annotations.length > 0) {
          const { ParseResult } = minim.elements;
          const parseResult = new ParseResult(result.annotations);
          done(err, parseResult);
        } else {
          done(err, null);
        }
      });
    }

    let options = { minim, source };

    if (adapterOptions) {
      options = Object.assign(options, adapterOptions);
    }

    return adapter.validate(options, (err, elements) => {
      if (!elements || elements instanceof minim.BaseElement) {
        done(err, elements);
      } else {
        done(err, this.load(elements));
      }
    });
  }

  /*
   * Parse an input document into Javascript objects. This method uses
   * the registered adapters to automatically detect the input format,
   * then uses the adapter to convert into refract elements and loads
   * these into objects.
   */
  parse({ source, mediaType, generateSourceMap = false, adapterOptions }, done) {
    const adapter = this.findAdapter(source, mediaType, 'parse');

    if (!adapter) {
      return done(new Error('Document did not match any registered parsers!'));
    }

    try {
      let options = { generateSourceMap, minim, source };

      if (adapterOptions) {
        options = Object.assign(options, adapterOptions);
      }

      return adapter.parse(options, (err, elements) => {
        if (!elements || elements instanceof minim.BaseElement) {
          done(err, elements);
        } else {
          done(err, this.load(elements));
        }
      });
    } catch (err) {
      return done(err);
    }
  }

  /*
   * Serialize a parsed API into the given output format.
   */
  serialize({ api, mediaType = 'text/vnd.apiblueprint' }, done) {
    const adapter = findAdapter(this.adapters, mediaType, 'serialize');

    if (adapter) {
      try {
        return adapter.serialize({ api, minim }, done);
      } catch (err) {
        return done(err);
      }
    } else {
      return done(new Error('Media type did not match any registered serializer!'));
    }
  }
}

/*
  Since we need to provide a sane interface to both ES6 `import` and
  normal Node.js `require` statements, we make a single default export
  and set up some other faux exports within it. See Babel's module
  docs: https://babeljs.io/docs/usage/modules/.
*/
const fury = new Fury();

fury.Fury = Fury;

export default fury;
<commit_msg>feat: Expose minim namespace in Fury<commit_after>import minimModule from 'minim';
import minimParseResult from 'minim-parse-result';

const minim = minimModule.namespace()
  .use(minimParseResult);

/*
 * Find an adapter by a given media type and method name, which should be
 * either `parse` or `serialize`. If no adapter is found, then
 * undefined is returned.
 */
function findAdapter(adapters, mediaType, method) {
  for (let i = 0; i < adapters.length; i += 1) {
    if (adapters[i].mediaTypes.indexOf(mediaType) !== -1 && adapters[i][method]) {
      return adapters[i];
    }
  }

  return null;
}

class Fury {
  constructor() {
    this.minim = minim;
    this.adapters = [];
  }

  /*
   * Register to use an adapter with this Fury instance.
   */
  use(adapter) {
    this.adapters.push(adapter);
    return this;
  }

  /*
   * Load serialized refract elements into Javascript objects.
   */
  // eslint-disable-next-line class-methods-use-this
  load(elements) {
    return this.minim.fromRefract(elements);
  }

  findAdapter(source, mediaType, method) {
    let adapter;

    if (mediaType) {
      adapter = findAdapter(this.adapters, mediaType, method);
    } else {
      for (let i = 0; i < this.adapters.length; i += 1) {
        const current = this.adapters[i];

        if (current.detect && current.detect(source) && current[method]) {
          adapter = this.adapters[i];
          break;
        }
      }
    }

    return adapter;
  }

  validate({ source, mediaType, adapterOptions }, done) {
    const adapter = this.findAdapter(source, mediaType, 'validate');

    if (!adapter) {
      return this.parse({ source, mediaType, adapterOptions }, (err, result) => {
        if (result && result.annotations.length > 0) {
          const { ParseResult } = this.minim.elements;
          const parseResult = new ParseResult(result.annotations);
          done(err, parseResult);
        } else {
          done(err, null);
        }
      });
    }

    let options = { minim: this.minim, source };

    if (adapterOptions) {
      options = Object.assign(options, adapterOptions);
    }

    return adapter.validate(options, (err, elements) => {
      if (!elements || elements instanceof this.minim.Element) {
        done(err, elements);
      } else {
        done(err, this.load(elements));
      }
    });
  }

  /*
   * Parse an input document into Javascript objects. This method uses
   * the registered adapters to automatically detect the input format,
   * then uses the adapter to convert into refract elements and loads
   * these into objects.
   */
  parse({ source, mediaType, generateSourceMap = false, adapterOptions }, done) {
    const adapter = this.findAdapter(source, mediaType, 'parse');

    if (!adapter) {
      return done(new Error('Document did not match any registered parsers!'));
    }

    try {
      let options = { generateSourceMap, minim: this.minim, source };

      if (adapterOptions) {
        options = Object.assign(options, adapterOptions);
      }

      return adapter.parse(options, (err, elements) => {
        if (!elements || elements instanceof this.minim.Element) {
          done(err, elements);
        } else {
          done(err, this.load(elements));
        }
      });
    } catch (err) {
      return done(err);
    }
  }

  /*
   * Serialize a parsed API into the given output format.
   */
  serialize({ api, mediaType = 'text/vnd.apiblueprint' }, done) {
    const adapter = findAdapter(this.adapters, mediaType, 'serialize');

    if (adapter) {
      try {
        return adapter.serialize({ api, minim: this.minim }, done);
      } catch (err) {
        return done(err);
      }
    } else {
      return done(new Error('Media type did not match any registered serializer!'));
    }
  }
}

/*
  Since we need to provide a sane interface to both ES6 `import` and
  normal Node.js `require` statements, we make a single default export
  and set up some other faux exports within it. See Babel's module
  docs: https://babeljs.io/docs/usage/modules/.
*/
const fury = new Fury();

fury.Fury = Fury;

export default fury;
<|endoftext|>


<commit_before>/**
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org
 */

(function () {

    /**
     * me.game represents your current game, it contains all the objects,
     * tilemap layers, current viewport, collision map, etc...

     * me.game is also responsible for updating (each frame) the object status
     * and draw them

     * @namespace me.game
     * @memberOf me
     */
    me.game = (function () {
        // hold public stuff in our singleton
        var api = {};

        /*
         * PRIVATE STUFF
         */

        // flag to redraw the sprites
        var initialized = false;

        // to know when we have to refresh the display
        var isDirty = true;

        // frame counter for frameSkipping
        // reset the frame counter
        var frameCounter = 0;
        var frameRate = 1;

        // reference to the renderer object
        var renderer = null;

        /*
         * PUBLIC STUFF
         */

        /**
         * a reference to the game viewport.
         * @public
         * @type {me.Viewport}
         * @name viewport
         * @memberOf me.game
         */
        api.viewport = null;

        /**
         * a reference to the game world

         * a world is a virtual environment containing all the game objects
         * @public
         * @type {me.Container}
         * @name world
         * @memberOf me.game
         */
        api.world = null;

        /**
         * when true, all objects will be added under the root world container

         * when false, a `me.Container` object will be created for each
         * corresponding `TMXObjectGroup`
         * default value : true
         * @public
         * @type {boolean}
         * @name mergeGroup
         * @memberOf me.game
         */
        api.mergeGroup = true;

        /**
         * The property of should be used when sorting entities

         * value : "x", "y", "z" (default: "z")
         * @public
         * @type {string}
         * @name sortOn
         * @memberOf me.game
         */
        api.sortOn = "z";

        /**
         * default layer tmxRenderer
         * @private
         * @ignore
         * @type {me.TMXRenderer}
         * @name tmxRenderer
         * @memberOf me.game
         */
        api.tmxRenderer = null;

        /**
         * Fired when a level is fully loaded and

         * and all entities instantiated.

         * Additionnaly the level id will also be passed
         * to the called function.
         * @public
         * @callback
         * @name onLevelLoaded
         * @memberOf me.game
         * @example
         * // call myFunction () everytime a level is loaded
         * me.game.onLevelLoaded = this.myFunction.bind(this);
         */
        api.onLevelLoaded = function () {};

        /**
         * Provide an object hash with all tag parameters specified in the url.
         * @property {Boolean} [hitbox=false] draw the hitbox in the debug panel (if enabled)
         * @property {Boolean} [velocity=false] draw the entities velocity in the debug panel (if enabled)
         * @property {Boolean} [quadtree=false] draw the quadtree in the debug panel (if enabled)
         * @property {Boolean} [webgl=false] force the renderer to WebGL
         * @public
         * @type {Object}
         * @name HASH
         * @memberOf me.game
         * @example
         * // http://www.example.com/index.html#debug&hitbox=true&mytag=value
         * console.log(me.game.HASH["mytag"]); //> "value"
         */
        api.HASH = null;

        /**
         * Initialize the game manager
         * @name init
         * @memberOf me.game
         * @private
         * @ignore
         * @function
         * @param {Number} [width] width of the canvas
         * @param {Number} [height] width of the canvas
         * init function.
         */
        api.init = function (width, height) {
            if (!initialized) {
                // if no parameter specified use the system size
                width  = width  || me.video.renderer.getWidth();
                height = height || me.video.renderer.getHeight();

                // create a defaut viewport of the same size
                api.viewport = new me.Viewport(0, 0, width, height);

                // the root object of our world is an entity container
                api.world = new me.Container(0, 0, width, height);
                api.world.name = "rootContainer";

                me.event.subscribe(me.event.VIEWPORT_ONRESIZE, function () {
                    var level = me.levelDirector.getCurrentLevel();

                    if (typeof(level) !== "undefined") {
                        // Center the map if smaller than the current viewport
                        me.game.world.pos.set(
                            Math.max(0, ~~((me.game.viewport.width - level.width) / 2)),
                            Math.max(0, ~~((me.game.viewport.height - level.height) / 2)),
                            0
                        );

                        // Translate the display if required
                        api.world.transform.identity();
                        api.world.transform.translateV(me.game.world.pos);
                    }
                });

                // initialize the collision system (the quadTree mostly)
                me.collision.init();

                renderer = me.video.renderer;

                // publish init notification
                me.event.publish(me.event.GAME_INIT);

                // translate global pointer events
                me.input._translatePointerEvents();

                // make display dirty by default
                isDirty = true;

                // set as initialized
                initialized = true;
            }
        };

        /**
         * reset the game Object manager

         * destroy all current objects
         * @name reset
         * @memberOf me.game
         * @public
         * @function
         */
        api.reset = function () {

            // clear the quadtree
            me.collision.quadTree.clear();

            // remove all objects
            api.world.destroy();

            // reset the viewport to zero ?
            if (api.viewport) {
                api.viewport.reset();
            }

            // reset the renderer
            renderer.reset();

            // reset the frame counter
            frameCounter = 0;
            frameRate = ~~(0.5 + 60 / me.sys.fps);
        };

        /**
         * Returns the parent container of the specified Child in the game world
         * @name getParentContainer
         * @memberOf me.game
         * @function
         * @param {me.Renderable} child
         * @return {me.Container}
         */
        api.getParentContainer = function (child) {
            return child.ancestor;
        };

        /**
         * force the redraw (not update) of all objects
         * @name repaint
         * @memberOf me.game
         * @public
         * @function
         */

        api.repaint = function () {
            isDirty = true;
        };

        /**
         * update all objects of the game manager
         * @name update
         * @memberOf me.game
         * @private
         * @ignore
         * @function
         * @param {Number} time current timestamp as provided by the RAF callback
         */
        api.update = function (time) {
            // handle frame skipping if required
            if ((++frameCounter % frameRate) === 0) {
                // reset the frame counter
                frameCounter = 0;

                // update the timer
                me.timer.update(time);

                // clear the quadtree
                me.collision.quadTree.clear();

                // insert the world container (children) into the quadtree
                me.collision.quadTree.insertContainer(api.world);

                // update all objects (and pass the elapsed time since last frame)
                isDirty = api.world.update(me.timer.getDelta()) || isDirty;

                // update the camera/viewport
                isDirty = api.viewport.update(me.timer.getDelta()) || isDirty;
            }
        };

        /**
         * draw all existing objects
         * @name draw
         * @memberOf me.game
         * @private
         * @ignore
         * @function
         */
        api.draw = function () {
            if (isDirty) {
                // cache the viewport rendering position, so that other object
                // can access it later (e,g. entityContainer when drawing floating objects)
                var translateX = api.viewport.pos.x + ~~api.viewport.offset.x;
                var translateY = api.viewport.pos.y + ~~api.viewport.offset.y;

                // translate the world coordinates by default to screen coordinates
                api.world.transform.translate(-translateX, -translateY);

                // prepare renderer to draw a new frame
                me.video.renderer.prepareSurface();

                // update all objects,
                // specifying the viewport as the rectangle area to redraw
                api.world.draw(renderer, api.viewport);

                // translate back
                api.world.transform.translate(translateX, translateY);

                // draw our camera/viewport
                api.viewport.draw(renderer);
            }

            isDirty = false;

            // blit our frame
            me.video.renderer.blitSurface();
        };

        // return our object
        return api;
    })();
})();
<commit_msg>Stable game loop update implemented. me.sys.interpolation needs to be set to false for loop update to be called multiple times, because it is incompatible. No API changes.<commit_after>/**
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org
 */

(function () {

    /**
     * me.game represents your current game, it contains all the objects,
     * tilemap layers, current viewport, collision map, etc...

     * me.game is also responsible for updating (each frame) the object status
     * and draw them

     * @namespace me.game
     * @memberOf me
     */
    me.game = (function () {
        // hold public stuff in our singleton
        var api = {};

        /*
         * PRIVATE STUFF
         */

        // flag to redraw the sprites
        var initialized = false;

        // to know when we have to refresh the display
        var isDirty = true;

        // frame counter for frameSkipping
        // reset the frame counter
        var frameCounter = 0;
        var frameRate = 1;

        // time accumulation for multiple update calls
        var accumulator = 0.0;

        // min update step size
        var stepSize = 1000 / 60;

        // reference to the renderer object
        var renderer = null;

        /*
         * PUBLIC STUFF
         */

        /**
         * a reference to the game viewport.
         * @public
         * @type {me.Viewport}
         * @name viewport
         * @memberOf me.game
         */
        api.viewport = null;

        /**
         * a reference to the game world

         * a world is a virtual environment containing all the game objects
         * @public
         * @type {me.Container}
         * @name world
         * @memberOf me.game
         */
        api.world = null;

        /**
         * when true, all objects will be added under the root world container

         * when false, a `me.Container` object will be created for each
         * corresponding `TMXObjectGroup`
         * default value : true
         * @public
         * @type {boolean}
         * @name mergeGroup
         * @memberOf me.game
         */
        api.mergeGroup = true;

        /**
         * The property of should be used when sorting entities

         * value : "x", "y", "z" (default: "z")
         * @public
         * @type {string}
         * @name sortOn
         * @memberOf me.game
         */
        api.sortOn = "z";

        /**
         * default layer tmxRenderer
         * @private
         * @ignore
         * @type {me.TMXRenderer}
         * @name tmxRenderer
         * @memberOf me.game
         */
        api.tmxRenderer = null;

        /**
         * Fired when a level is fully loaded and

         * and all entities instantiated.

         * Additionnaly the level id will also be passed
         * to the called function.
         * @public
         * @callback
         * @name onLevelLoaded
         * @memberOf me.game
         * @example
         * // call myFunction () everytime a level is loaded
         * me.game.onLevelLoaded = this.myFunction.bind(this);
         */
        api.onLevelLoaded = function () {};

        /**
         * Provide an object hash with all tag parameters specified in the url.
         * @property {Boolean} [hitbox=false] draw the hitbox in the debug panel (if enabled)
         * @property {Boolean} [velocity=false] draw the entities velocity in the debug panel (if enabled)
         * @property {Boolean} [quadtree=false] draw the quadtree in the debug panel (if enabled)
         * @property {Boolean} [webgl=false] force the renderer to WebGL
         * @public
         * @type {Object}
         * @name HASH
         * @memberOf me.game
         * @example
         * // http://www.example.com/index.html#debug&hitbox=true&mytag=value
         * console.log(me.game.HASH["mytag"]); //> "value"
         */
        api.HASH = null;

        /**
         * Initialize the game manager
         * @name init
         * @memberOf me.game
         * @private
         * @ignore
         * @function
         * @param {Number} [width] width of the canvas
         * @param {Number} [height] width of the canvas
         * init function.
         */
        api.init = function (width, height) {
            if (!initialized) {
                // if no parameter specified use the system size
                width  = width  || me.video.renderer.getWidth();
                height = height || me.video.renderer.getHeight();

                // create a defaut viewport of the same size
                api.viewport = new me.Viewport(0, 0, width, height);

                // the root object of our world is an entity container
                api.world = new me.Container(0, 0, width, height);
                api.world.name = "rootContainer";

                me.event.subscribe(me.event.VIEWPORT_ONRESIZE, function () {
                    var level = me.levelDirector.getCurrentLevel();

                    if (typeof(level) !== "undefined") {
                        // Center the map if smaller than the current viewport
                        me.game.world.pos.set(
                            Math.max(0, ~~((me.game.viewport.width - level.width) / 2)),
                            Math.max(0, ~~((me.game.viewport.height - level.height) / 2)),
                            0
                        );

                        // Translate the display if required
                        api.world.transform.identity();
                        api.world.transform.translateV(me.game.world.pos);
                    }
                });

                // initialize the collision system (the quadTree mostly)
                me.collision.init();

                renderer = me.video.renderer;

                // publish init notification
                me.event.publish(me.event.GAME_INIT);

                // translate global pointer events
                me.input._translatePointerEvents();

                // make display dirty by default
                isDirty = true;

                // set as initialized
                initialized = true;
            }
        };

        /**
         * reset the game Object manager

         * destroy all current objects
         * @name reset
         * @memberOf me.game
         * @public
         * @function
         */
        api.reset = function () {

            // clear the quadtree
            me.collision.quadTree.clear();

            // remove all objects
            api.world.destroy();

            // reset the viewport to zero ?
            if (api.viewport) {
                api.viewport.reset();
            }

            // reset the renderer
            renderer.reset();

            // reset the frame counter
            frameCounter = 0;
            frameRate = ~~(0.5 + 60 / me.sys.fps);

            // set step size based in minimum fps
            stepSize = (1000 / me.sys.fps);
            accumulator = 0.0;
        };

        /**
         * Returns the parent container of the specified Child in the game world
         * @name getParentContainer
         * @memberOf me.game
         * @function
         * @param {me.Renderable} child
         * @return {me.Container}
         */
        api.getParentContainer = function (child) {
            return child.ancestor;
        };

        /**
         * force the redraw (not update) of all objects
         * @name repaint
         * @memberOf me.game
         * @public
         * @function
         */

        api.repaint = function () {
            isDirty = true;
        };

        /**
         * update all objects of the game manager
         * @name update
         * @memberOf me.game
         * @private
         * @ignore
         * @function
         * @param {Number} time current timestamp as provided by the RAF callback
         */
        api.update = function (time) {
            var updateDelta;
            // handle frame skipping if required
            if ((++frameCounter % frameRate) === 0) {
                // reset the frame counter
                frameCounter = 0;

                // update the timer
                me.timer.update(time);

                accumulator += me.timer.getDelta();

                updateDelta = (me.sys.interpolation) ? me.timer.getDelta() : stepSize;

                while (accumulator >= stepSize || me.sys.interpolation) {
                    // clear the quadtree
                    me.collision.quadTree.clear();

                    // insert the world container (children) into the quadtree
                    me.collision.quadTree.insertContainer(api.world);

                    // update all objects (and pass the elapsed time since last frame)
                    isDirty = api.world.update(updateDelta) || isDirty;

                    // update the camera/viewport
                    isDirty = api.viewport.update(updateDelta) || isDirty;

                    accumulator -= stepSize;
                    if (me.sys.interpolation) {
                        break;
                    }
                }
            }
        };

        /**
         * draw all existing objects
         * @name draw
         * @memberOf me.game
         * @private
         * @ignore
         * @function
         */
        api.draw = function () {
            if (isDirty) {
                // cache the viewport rendering position, so that other object
                // can access it later (e,g. entityContainer when drawing floating objects)
                var translateX = api.viewport.pos.x + ~~api.viewport.offset.x;
                var translateY = api.viewport.pos.y + ~~api.viewport.offset.y;

                // translate the world coordinates by default to screen coordinates
                api.world.transform.translate(-translateX, -translateY);

                // prepare renderer to draw a new frame
                me.video.renderer.prepareSurface();

                // update all objects,
                // specifying the viewport as the rectangle area to redraw
                api.world.draw(renderer, api.viewport);

                // translate back
                api.world.transform.translate(translateX, translateY);

                // draw our camera/viewport
                api.viewport.draw(renderer);
            }

            isDirty = false;

            // blit our frame
            me.video.renderer.blitSurface();
        };

        // return our object
        return api;
    })();
})();
<|endoftext|>


<commit_before>import { Game } from "cervus/core";
import { Plane } from "cervus/shapes";
import { Move, Transform, Render } from "cervus/components";
import { basic } from "cervus/materials";
import { quat } from "cervus/math";
import { rgb_to_hex, hsl_to_rgb } from "cervus/utils";

import { ACTIONS } from "./actions";
import { element } from "./level-elements.js";
import * as random from "./random";
import { DummyLookAt, get_score, get_hint } from "./score";

import { distance } from "gl-matrix/src/gl-matrix/vec3";
import { spawn_birds } from "./bird";

const DEBUG = true;
const WORLD_SIZE = 1000;
const SATURATION = 0.7;
const LUMINANCE = 0.6;
const PLAYER_HEIGHT = 1.74;
const BIRD_TRIGGER_DISTANCE = 25;
const BIRD_FLOCK_SIZE = 25;

let props = [];
let birds_positions = [];

function hex(hue, lum) {
  const rgb = hsl_to_rgb(hue, SATURATION, lum);
  return rgb_to_hex(rgb);
}

export function create_level(lvl_number) {
  random.set_seed(Math.pow(random.base_seed / lvl_number, 2));
  props = [];
  birds_positions = [];
  const game = new Game({
    width: window.innerWidth,
    height: window.innerHeight,
    clear_color: "#eeeeee",
    far: WORLD_SIZE
  });

  game.camera.add_component(new Move({
    keyboard_controlled: false,
    mouse_controlled: false,
    move_speed: 25,
    rotate_speed: .5,
  }));

  const hue = random.float(0, 1);
  const color = hex(hue, LUMINANCE);

  const floor = new Plane();
  floor.get_component(Transform).scale = [WORLD_SIZE, 1, WORLD_SIZE];
  floor.get_component(Render).set({
    material: basic,
    color
  });

  game.add(floor);

  for (let i = 0; i < Math.pow(lvl_number, 2) + 1; i++) {
    element(i, color, random.integer(0, 2)).forEach((el) => {
      props.push(el);
      game.add(el);
    });
  }

  game.camera.get_component(Transform).position = random.position([0, 0], WORLD_SIZE / 3);
  game.camera.get_component(Transform).look_at(
    random.element_of(props).get_component(Transform).position
  );
  game.camera.get_component(Transform).look_at(
    random.look_at_target(game.camera.get_component(Transform).matrix)
  );

  if (!DEBUG) {
    delete game.camera.get_component(Move).dir_desc['69'];
    delete game.camera.get_component(Move).dir_desc['81'];
  }

  // game.camera.get_component(Move).dir_desc['81'] = 'l';
  // game.camera.get_component(Move).dir_desc['90'] = 'f';

  const spawners = random.integer(2, 4);
  for (let i = 0; i < spawners; i++) {
    const birds_position = random.position([0, 0], WORLD_SIZE/3, -3);
    birds_positions.push(birds_position);

    if (DEBUG) {
      const bird_spawner = element(1, color, 3)[0];
      bird_spawner.get_component(Transform).set({
        position: birds_position
      });
      game.add(bird_spawner);
    }
  }

  game.on("afterrender", function take_snapshot() {
    game.off("afterrender", take_snapshot);
    const target = {
      snapshot: game.canvas.toDataURL(),
      position: game.camera.get_component(Transform).position,
      rotation: game.camera.get_component(Transform).rotation,
    };
    window['dispatch'](ACTIONS.SAVE_SNAPSHOT, target);
    game.stop();
  });

  return [game, hue];
}

export function start_level(game, hue, target) {
  game.camera.get_component(Transform).set({
    position: [0, PLAYER_HEIGHT, 0],
    rotation: quat.create()
  });

  game.camera.get_component(Move).keyboard_controlled = true;
  game.camera.get_component(Move).mouse_controlled = true;
  game.camera.add_component(new DummyLookAt({target}));

  for (const entity of game.entities) {
    entity.get_component(Render).color = "#000000";
  }

  game.start();

  game.on("tick", () => {
    for (let i = 0; i < birds_positions.length; i++) {
      if (distance(birds_positions[i], game.camera.get_component(Transform).position) < BIRD_TRIGGER_DISTANCE) {
        spawn_birds(
          birds_positions[i],
          hex(hue, LUMINANCE * get_hint(target, game.camera, WORLD_SIZE)),
          WORLD_SIZE/5,
          BIRD_FLOCK_SIZE,
          game
        );
        birds_positions.splice(i, 1);
        break;
      }
    }
  });

  game.on("afterrender", function () {
    const hint = get_hint(target, game.camera, WORLD_SIZE);
    // XXX Change color on the material instance?
    for (const entity of game.entities) {
      entity.get_component(Render).color = hex(hue, LUMINANCE * hint);
    }
  });
}

export function end_level(game, target) {
  game.stop();
  const score = get_score(target, game.camera, WORLD_SIZE);
  return Math.floor(score * 100);
}
<commit_msg>disable debug<commit_after>import { Game } from "cervus/core";
import { Plane } from "cervus/shapes";
import { Move, Transform, Render } from "cervus/components";
import { basic } from "cervus/materials";
import { quat } from "cervus/math";
import { rgb_to_hex, hsl_to_rgb } from "cervus/utils";

import { ACTIONS } from "./actions";
import { element } from "./level-elements.js";
import * as random from "./random";
import { DummyLookAt, get_score, get_hint } from "./score";

import { distance } from "gl-matrix/src/gl-matrix/vec3";
import { spawn_birds } from "./bird";

const DEBUG = false;
const WORLD_SIZE = 1000;
const SATURATION = 0.7;
const LUMINANCE = 0.6;
const PLAYER_HEIGHT = 1.74;
const BIRD_TRIGGER_DISTANCE = 25;
const BIRD_FLOCK_SIZE = 25;

let props = [];
let birds_positions = [];

function hex(hue, lum) {
  const rgb = hsl_to_rgb(hue, SATURATION, lum);
  return rgb_to_hex(rgb);
}

export function create_level(lvl_number) {
  random.set_seed(Math.pow(random.base_seed / lvl_number, 2));
  props = [];
  birds_positions = [];
  const game = new Game({
    width: window.innerWidth,
    height: window.innerHeight,
    clear_color: "#eeeeee",
    far: WORLD_SIZE
  });

  game.camera.add_component(new Move({
    keyboard_controlled: false,
    mouse_controlled: false,
    move_speed: 25,
    rotate_speed: .5,
  }));

  const hue = random.float(0, 1);
  const color = hex(hue, LUMINANCE);

  const floor = new Plane();
  floor.get_component(Transform).scale = [WORLD_SIZE, 1, WORLD_SIZE];
  floor.get_component(Render).set({
    material: basic,
    color
  });

  game.add(floor);

  for (let i = 0; i < Math.pow(lvl_number, 2) + 1; i++) {
    element(i, color, random.integer(0, 2)).forEach((el) => {
      props.push(el);
      game.add(el);
    });
  }

  game.camera.get_component(Transform).position = random.position([0, 0], WORLD_SIZE / 3);
  game.camera.get_component(Transform).look_at(
    random.element_of(props).get_component(Transform).position
  );
  game.camera.get_component(Transform).look_at(
    random.look_at_target(game.camera.get_component(Transform).matrix)
  );

  if (!DEBUG) {
    delete game.camera.get_component(Move).dir_desc['69'];
    delete game.camera.get_component(Move).dir_desc['81'];
  }

  // game.camera.get_component(Move).dir_desc['81'] = 'l';
  // game.camera.get_component(Move).dir_desc['90'] = 'f';

  const spawners = random.integer(2, 4);
  for (let i = 0; i < spawners; i++) {
    const birds_position = random.position([0, 0], WORLD_SIZE/3, -3);
    birds_positions.push(birds_position);

    if (DEBUG) {
      const bird_spawner = element(1, color, 3)[0];
      bird_spawner.get_component(Transform).set({
        position: birds_position
      });
      game.add(bird_spawner);
    }
  }

  game.on("afterrender", function take_snapshot() {
    game.off("afterrender", take_snapshot);
    const target = {
      snapshot: game.canvas.toDataURL(),
      position: game.camera.get_component(Transform).position,
      rotation: game.camera.get_component(Transform).rotation,
    };
    window['dispatch'](ACTIONS.SAVE_SNAPSHOT, target);
    game.stop();
  });

  return [game, hue];
}

export function start_level(game, hue, target) {
  game.camera.get_component(Transform).set({
    position: [0, PLAYER_HEIGHT, 0],
    rotation: quat.create()
  });

  game.camera.get_component(Move).keyboard_controlled = true;
  game.camera.get_component(Move).mouse_controlled = true;
  game.camera.add_component(new DummyLookAt({target}));

  for (const entity of game.entities) {
    entity.get_component(Render).color = "#000000";
  }

  game.start();

  game.on("tick", () => {
    for (let i = 0; i < birds_positions.length; i++) {
      if (distance(birds_positions[i], game.camera.get_component(Transform).position) < BIRD_TRIGGER_DISTANCE) {
        spawn_birds(
          birds_positions[i],
          hex(hue, LUMINANCE * get_hint(target, game.camera, WORLD_SIZE)),
          WORLD_SIZE/5,
          BIRD_FLOCK_SIZE,
          game
        );
        birds_positions.splice(i, 1);
        break;
      }
    }
  });

  game.on("afterrender", function () {
    const hint = get_hint(target, game.camera, WORLD_SIZE);
    // XXX Change color on the material instance?
    for (const entity of game.entities) {
      entity.get_component(Render).color = hex(hue, LUMINANCE * hint);
    }
  });
}

export function end_level(game, target) {
  game.stop();
  const score = get_score(target, game.camera, WORLD_SIZE);
  return Math.floor(score * 100);
}
<|endoftext|>


<commit_before>function MinesweeperGame() {
  this.board = new Board({
    width: 10,
    height: 10,
    parent: $('#board-container')
  });

  this.cursor = new Cursor({
    board: this.board,
    x: 0,
    y: 0
  });

  this.status = "game";
  this.result = $('<div>').attr('id', 'result');

  this.probabilities = [0.15, 0.2, 0.2];
  this.widths = [6, 10, 15];
  this.heights = [8, 10, 12];

  initMenuInput(this);
  initGameInput(this);
}

MinesweeperGame.prototype.start = function() {
  this.board.parent.hide();
}

MinesweeperGame.prototype.startGame = function(difficulty) {

  var probability = this.probabilities[difficulty];
  var width = this.widths[difficulty];
  var height = this.heights[difficulty];

  this.newBoard(width, height, 40);
  this.spawnMines(probability);
  console.log('Probability: ' + probability);

  if (this.board.parent.css('display') === 'none') {
    this.board.parent.fadeIn(500);
  }
  this.cursor.visible = false;
  this.status = "game";
  this.render();
  initGameInput(this);
}

MinesweeperGame.prototype.newBoard = function(width, height, size) {
  if (this.board) {
    this.board.parent.empty();
  }
  this.board = new Board({
    width: width,
    height: height,
    squareSize: size,
    parent: $('#board-container')
  })
  this.cursor = new Cursor({
    board: this.board,
    x: 0,
    y: 0
  });
  this.resetSquares();
}

MinesweeperGame.prototype.resetSquares = function() {
  this.board.eachSquare(function() {
    this.revealed = false;
    this.mine = false;
    $(this.el).empty();
    this.score = $('<div>').addClass('score');
  });
}

MinesweeperGame.prototype.spawnMines = function(probability) {
  this.board.eachSquare(function() {
    if (Math.random() < probability) {
      this.mine = true;
    } else {
      this.mine = false;
    }
  });
}

MinesweeperGame.prototype.revealMines = function() {
  this.board.eachSquare(function() {
    if (this.mine) {
      this.reveal();
    }
  });
}

MinesweeperGame.prototype.render = function() {
  this.board.render();
}

MinesweeperGame.prototype.checkResult = function(){
  var win = true;
  var lose = false;
  this.board.eachSquare(function() {
    win = win && (this.mine || this.revealed);
    lose = lose || (this.mine && this.revealed);
  });

  if (win) {
    this.winGame();
  }

  if (lose) {
    this.loseGame();
  }
}

MinesweeperGame.prototype.winGame = function() {
  this.status = "win";
  this.applyResultStyle();
  this.showResult('w i n');
}

MinesweeperGame.prototype.loseGame = function() {
  this.status = "lose";
  this.revealMines();
  this.render();
  this.applyResultStyle();
  this.showResult('l o s e');
}

MinesweeperGame.prototype.applyResultStyle = function() {
  this.result.css('width', this.board.parent.css('width'))
             .css('height', this.board.parent.css('height'))
             .css('line-height', this.board.parent.css('height'))
}

MinesweeperGame.prototype.showResult = function(text) {
  this.result.text(text)
             .hide()
             .appendTo(this.board.parent)
             .fadeIn(500);
}

// Extending Squares
// -----------------
Square.prototype.reveal = function() {
  if (this.revealed) {
    return;
  }
  this.revealed = true;
  var square;
  if (this.neighborCount() === 0 && !this.mine) {
    this.revealNeighbors();
  }
}

Square.prototype.revealNeighbors = function() {
  square = this.board.square(this.x+1, this.y);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x+1, this.y+1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x, this.y+1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x-1, this.y+1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x-1, this.y);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x-1, this.y-1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x, this.y-1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x+1, this.y-1);
  square.reveal && !square.revealed ? square.reveal() : false;
}

Square.prototype.neighborCount = function() {
  var neighbors = 0;
  this.board.square(this.x+1, this.y).mine ? neighbors++ : false;
  this.board.square(this.x+1, this.y+1).mine ? neighbors++ : false;
  this.board.square(this.x, this.y+1).mine ? neighbors++ : false;
  this.board.square(this.x-1, this.y+1).mine ? neighbors++ : false;
  this.board.square(this.x-1, this.y).mine ? neighbors++ : false;
  this.board.square(this.x-1, this.y-1).mine ? neighbors++ : false;
  this.board.square(this.x, this.y-1).mine ? neighbors++ : false;
  this.board.square(this.x+1, this.y-1).mine ? neighbors++ : false;
  return neighbors;
}

Square.prototype.beforeRender = function() {
  if (this.revealed) {
    if (this.mine) {
      $(this.el).addClass('mine');
    } else {
      $(this.el).addClass('safe');
      this.renderScore();
    }
  } else {
    $(this.el).removeClass('mine');
    $(this.el).removeClass('safe');
  }
}

Square.prototype.renderScore = function() {
  var scoreClasses = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'];
  var neighbors = this.neighborCount();
  this.score.addClass(scoreClasses[neighbors])
  this.score.text(neighbors);
  $(this.el).append(this.score);
}

// UI
Cursor.prototype.beforeRender = function() {
  if (this.board.square(this.x, this.y).revealed) {
    this.visible = false;
  }
}
<commit_msg>mine spawning based on number of mines instead of probability<commit_after>function MinesweeperGame() {
  this.board = new Board({
    width: 10,
    height: 10,
    parent: $('#board-container')
  });

  this.cursor = new Cursor({
    board: this.board,
    x: 0,
    y: 0
  });

  this.status = "game";
  this.result = $('<div>').attr('id', 'result');

  this.mines = [8, 20, 40];
  this.widths = [6, 10, 15];
  this.heights = [8, 10, 12];

  initMenuInput(this);
  initGameInput(this);
}

MinesweeperGame.prototype.start = function() {
  this.board.parent.hide();
}

MinesweeperGame.prototype.startGame = function(difficulty) {

  var probability = this.mines[difficulty];
  var width = this.widths[difficulty];
  var height = this.heights[difficulty];

  this.newBoard(width, height, 40);
  this.spawnMines(probability);
  console.log('Probability: ' + probability);

  if (this.board.parent.css('display') === 'none') {
    this.board.parent.fadeIn(500);
  }
  this.cursor.visible = false;
  this.status = "game";
  this.render();
  initGameInput(this);
}

MinesweeperGame.prototype.newBoard = function(width, height, size) {
  if (this.board) {
    this.board.parent.empty();
  }
  this.board = new Board({
    width: width,
    height: height,
    squareSize: size,
    parent: $('#board-container')
  })
  this.cursor = new Cursor({
    board: this.board,
    x: 0,
    y: 0
  });
  this.resetSquares();
}

MinesweeperGame.prototype.resetSquares = function() {
  this.board.eachSquare(function() {
    this.revealed = false;
    this.mine = false;
    $(this.el).empty();
    this.score = $('<div>').addClass('score');
  });
}

MinesweeperGame.prototype.spawnMines = function(mines) {
  minesRemaining = Math.min(mines, this.board.xSize() * this.board.ySize());
  while (minesRemaining > 0) {
    x = Math.floor(Math.random() * this.board.xSize());
    y = Math.floor(Math.random() * this.board.ySize());
    if (!this.board.square(x, y).mine) {
      this.board.square(x, y).mine = true;
      minesRemaining--;
    }
  }
}

MinesweeperGame.prototype.revealMines = function() {
  this.board.eachSquare(function() {
    if (this.mine) {
      this.reveal();
    }
  });
}

MinesweeperGame.prototype.render = function() {
  this.board.render();
}

MinesweeperGame.prototype.checkResult = function(){
  var win = true;
  var lose = false;
  this.board.eachSquare(function() {
    win = win && (this.mine || this.revealed);
    lose = lose || (this.mine && this.revealed);
  });

  if (win) {
    this.winGame();
  }

  if (lose) {
    this.loseGame();
  }
}

MinesweeperGame.prototype.winGame = function() {
  this.status = "win";
  this.applyResultStyle();
  this.showResult('w i n');
}

MinesweeperGame.prototype.loseGame = function() {
  this.status = "lose";
  this.revealMines();
  this.render();
  this.applyResultStyle();
  this.showResult('l o s e');
}

MinesweeperGame.prototype.applyResultStyle = function() {
  this.result.css('width', this.board.parent.css('width'))
             .css('height', this.board.parent.css('height'))
             .css('line-height', this.board.parent.css('height'))
}

MinesweeperGame.prototype.showResult = function(text) {
  this.result.text(text)
             .hide()
             .appendTo(this.board.parent)
             .fadeIn(500);
}

// Extending Squares
// -----------------
Square.prototype.reveal = function() {
  if (this.revealed) {
    return;
  }
  this.revealed = true;
  var square;
  if (this.neighborCount() === 0 && !this.mine) {
    this.revealNeighbors();
  }
}

Square.prototype.revealNeighbors = function() {
  square = this.board.square(this.x+1, this.y);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x+1, this.y+1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x, this.y+1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x-1, this.y+1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x-1, this.y);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x-1, this.y-1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x, this.y-1);
  square.reveal && !square.revealed ? square.reveal() : false;
  square = this.board.square(this.x+1, this.y-1);
  square.reveal && !square.revealed ? square.reveal() : false;
}

Square.prototype.neighborCount = function() {
  var neighbors = 0;
  this.board.square(this.x+1, this.y).mine ? neighbors++ : false;
  this.board.square(this.x+1, this.y+1).mine ? neighbors++ : false;
  this.board.square(this.x, this.y+1).mine ? neighbors++ : false;
  this.board.square(this.x-1, this.y+1).mine ? neighbors++ : false;
  this.board.square(this.x-1, this.y).mine ? neighbors++ : false;
  this.board.square(this.x-1, this.y-1).mine ? neighbors++ : false;
  this.board.square(this.x, this.y-1).mine ? neighbors++ : false;
  this.board.square(this.x+1, this.y-1).mine ? neighbors++ : false;
  return neighbors;
}

Square.prototype.beforeRender = function() {
  if (this.revealed) {
    if (this.mine) {
      $(this.el).addClass('mine');
    } else {
      $(this.el).addClass('safe');
      this.renderScore();
    }
  } else {
    $(this.el).removeClass('mine');
    $(this.el).removeClass('safe');
  }
}

Square.prototype.renderScore = function() {
  var scoreClasses = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'];
  var neighbors = this.neighborCount();
  this.score.addClass(scoreClasses[neighbors])
  this.score.text(neighbors);
  $(this.el).append(this.score);
}

// UI
Cursor.prototype.beforeRender = function() {
  if (this.board.square(this.x, this.y).revealed) {
    this.visible = false;
  }
}
<|endoftext|>