Browse Source

CMake files to build the app

Phyks (Lucas Verney) 4 years ago
commit
08bc5e0b53

+ 3
- 0
.gitmodules View File

@@ -0,0 +1,3 @@
1
+[submodule "src/3rdparty/linmath"]
2
+	path = src/3rdparty/linmath
3
+	url = https://github.com/datenwolf/linmath.h.git

+ 4
- 0
CMakeLists.txt View File

@@ -0,0 +1,4 @@
1
+cmake_minimum_required (VERSION 2.8.11)
2
+project (SkiMap)
3
+
4
+add_subdirectory(src)

+ 61
- 0
res/raw/f_shader.txt View File

@@ -0,0 +1,61 @@
1
+// Fragment shader based on http://antonholmquist.com/blog/opengl-es-2-0-shader-lighting-examples/
2
+// Light is computed per fragment for better render
3
+
4
+precision highp float;
5
+
6
+struct DirectionalLight {
7
+    vec3 direction;
8
+    vec3 halfplane;
9
+    vec4 ambient_color;
10
+    vec4 diffuse_color;
11
+    vec4 specular_color;
12
+};
13
+
14
+struct Material {
15
+    vec4 ambient_factor;
16
+    vec4 diffuse_factor;
17
+    vec4 specular_factor;
18
+    float shininess;
19
+};
20
+
21
+// Light
22
+uniform DirectionalLight u_directional_light;
23
+
24
+// Material
25
+uniform Material u_material;
26
+
27
+// Normal vector in eye space, assumed to be normalized
28
+varying vec3 v_ec_normal;
29
+
30
+void main() {
31
+    float ec_normal_dot_light_direction = max(
32
+            0.0,
33
+            dot(v_ec_normal, u_directional_light.direction));
34
+    float ec_normal_dot_light_halfplane = max(
35
+            0.0,
36
+            dot(ec_normal, u_directional_light.halfplane));
37
+
38
+    // Calculate ambient light
39
+    vec4 ambient_light = (
40
+            u_directional_light.ambient_color *
41
+            u_material.ambient_factor);
42
+
43
+    // Calculate diffuse light
44
+    vec4 diffuse_light = (
45
+            ec_normal_dot_light_direction *
46
+            u_directional_light.diffuse_color *
47
+            u_material.diffuse_factor);
48
+
49
+    // Calculate specular light
50
+    vec4 specular_light = vec4(0.0);
51
+    if (ec_normal_dot_light_halfplane > 0.0) {
52
+        specular_light = (
53
+                pow(ec_normal_dot_light_halfplane, u_material.shininess) *
54
+                u_directionalLight.specularColor *
55
+                u_material.specularFactor);
56
+    }
57
+
58
+    vec4 light = ambient_light + diffuse_light + specular_light;
59
+
60
+    gl_FragColor = light;
61
+}

+ 23
- 0
res/raw/v_shader.txt View File

@@ -0,0 +1,23 @@
1
+// Based on http://antonholmquist.com/blog/opengl-es-2-0-shader-lighting-examples/
2
+precision highp float;
3
+
4
+uniform mat4 u_MV_matrix;  // Model - View matrix
5
+uniform mat4 u_MVP_matrix;  // Model - View - Projection matrix
6
+
7
+// Vertex position in model coordinates, vec4 but latest coordinate
8
+// (used for clipping) is set to 1.0 if only 3 coordinates are given
9
+attribute vec4 a_position;
10
+// Normal in model coordinates
11
+attribute vec3 a_normal;
12
+
13
+// Eye space normal
14
+varying vec3 v_ec_normal;
15
+
16
+void main() {
17
+    // Calculate and normalize eye space normal
18
+    vec3 ec_normal = vec3(u_MV_matrix * vec4(a_normal, 0.0));
19
+    v_ec_normal = normalize(ec_normal);
20
+
21
+    // Set vertex position
22
+	gl_Position = u_MVP_matrix * a_position;
23
+}

+ 123
- 0
scripts/bd_alti.py View File

@@ -0,0 +1,123 @@
1
+#!/usr/bin/env python3
2
+import math
3
+import os
4
+import pyproj
5
+import sys
6
+
7
+"""
8
+This script filters the BD ALTI from IGN (ESRI grid) to keep only the relevant
9
+files for the specified area.
10
+
11
+Input is an Arc/Info E00 (ASCII) file from the IGN BD ALTI database.
12
+Output is an ASCII XYZ gridded file, sorted by increasing X and decreasing Y.
13
+"""
14
+
15
+
16
+def has_overlap(a, b):
17
+    """
18
+    Returns
19
+    * False if no overlap between the intervals represented by a and b,
20
+    * True otherwise
21
+    """
22
+    return (max(0, min(a[1], b[1]) - max(a[0], b[0])) > 0)
23
+
24
+
25
+def parse_header(fh):
26
+    """
27
+    Parses the header of an Arc/Info E00 (ASCII) altitude file.
28
+    """
29
+    ncols = int(fh.readline().strip().split(" ")[-1])
30
+    nrows = int(fh.readline().strip().split(" ")[-1])
31
+    xllcorner = float(fh.readline().strip().split(" ")[-1])
32
+    yllcorner = float(fh.readline().strip().split(" ")[-1])
33
+    cellsize = float(fh.readline().strip().split(" ")[-1])
34
+
35
+    return ncols, nrows, xllcorner, yllcorner, cellsize
36
+
37
+
38
+if len(sys.argv) < 6:
39
+    print("Usage: "+sys.argv[0]+" LAT_MIN LNG_MIN LAT_MAX LNG_MAX DATA_FOLDER")
40
+    sys.exit()
41
+
42
+lat_min = float(sys.argv[1])
43
+lng_min = float(sys.argv[2])
44
+lat_max = float(sys.argv[3])
45
+lng_max = float(sys.argv[4])
46
+data_folder = os.path.expanduser(sys.argv[5])
47
+
48
+if len(sys.argv) > 6:
49
+    out_file = sys.argv[6]
50
+else:
51
+    out_file = "out.xyz"
52
+
53
+print(("Looking for data between latitudes and longitudes " +
54
+       "({0}, {1}) and ({2}, {3})").format(lat_min, lng_min, lat_max, lng_max))
55
+
56
+wgs84 = pyproj.Proj("+init=EPSG:4326")
57
+lambert = pyproj.Proj("+init=EPSG:2154")
58
+x_min, y_min = pyproj.transform(wgs84, lambert, lng_min, lat_min)
59
+x_max, y_max = pyproj.transform(wgs84, lambert, lng_max, lat_max)
60
+
61
+if x_min > x_max:
62
+    x_min, x_max = x_max, x_min
63
+if y_min > y_max:
64
+    y_min, y_max = y_max, y_min
65
+
66
+print(("Looking for data between map coordinates " +
67
+       "({0}, {1}) and ({2}, {3})").format(x_min, y_min, x_max, y_max))
68
+
69
+founds = []
70
+for f in os.listdir(data_folder):
71
+    if not(f.endswith(".asc")):
72
+        continue
73
+    file = os.path.join(data_folder, f)
74
+    with open(file, 'r') as fh:
75
+        ncols, nrows, xllcorner, yllcorner, cellsize = parse_header(fh)
76
+
77
+        if has_overlap([x_min, x_max],
78
+                       [xllcorner, xllcorner + cellsize * ncols]):
79
+            if has_overlap([y_min, y_max],
80
+                           [yllcorner, yllcorner + cellsize * nrows]):
81
+                founds.append(file)
82
+
83
+if len(founds) == 0:
84
+    print("No matching dataset found =(.")
85
+else:
86
+    print("Matching datasets:")
87
+    print("\n".join(founds))
88
+
89
+
90
+# Extract relevant parts from the datasets and output it as xyz values
91
+out = "X\tY\tZ\n"
92
+for f in founds:
93
+    with open(f, 'r') as fh:
94
+        ncols, nrows, xllcorner, yllcorner, cellsize = parse_header(fh)
95
+
96
+        col_min = math.floor((x_min - xllcorner) / cellsize)
97
+        col_max = math.ceil((x_max - xllcorner) / cellsize)
98
+        # The (0, 0) point is the lower left one, that is on the last line.
99
+        row_max = nrows - math.floor((y_min - yllcorner) / cellsize)
100
+        row_min = nrows - math.ceil((y_max - yllcorner) / cellsize)
101
+
102
+        i = 0
103
+        for line in fh.readlines():
104
+            if i >= row_min and i <= row_max:
105
+                row = [float(j) for j in line.strip().split(" ")]
106
+                for j in range(col_min, col_max):
107
+                    out += "{0}\t{1}\t{2}\n".format(xllcorner + j * cellsize,
108
+                                                    (yllcorner +
109
+                                                     (nrows - i) * cellsize),
110
+                                                    row[j])
111
+            i += 1
112
+
113
+out = out.strip()
114
+
115
+# Write it to out.xyz file
116
+with open(out_file, 'w') as fh:
117
+    fh.write(out)
118
+
119
+if len(sys.argv) < 7:
120
+    print("Found data (also exported to "+out_file+"):")
121
+    print(out)
122
+else:
123
+    print("Found data exported to "+out_file+".")

+ 118
- 0
scripts/osm_filter.py View File

@@ -0,0 +1,118 @@
1
+#!/usr/bin/env python3
2
+import json
3
+import pyproj
4
+import os
5
+import sys
6
+import xml.etree.ElementTree as ET
7
+
8
+"""
9
+This script filters the OpenStreetMap XML data file. It exports only the
10
+geographically relevant informations in a JSON file.
11
+"""
12
+
13
+wgs84 = pyproj.Proj("+init=EPSG:4326")
14
+lambert = pyproj.Proj("+init=EPSG:2154")
15
+
16
+
17
+if len(sys.argv) < 6:
18
+    print("Usage: "+sys.argv[0]+" LAT_MIN LNG_MIN LAT_MAX LNG_MAX DATA_FILE")
19
+    sys.exit()
20
+
21
+lat_min = float(sys.argv[1])
22
+lng_min = float(sys.argv[2])
23
+lat_max = float(sys.argv[3])
24
+lng_max = float(sys.argv[4])
25
+data_file = os.path.expanduser(sys.argv[5])
26
+
27
+if len(sys.argv) > 6:
28
+    out_file = sys.argv[6]
29
+else:
30
+    out_file = data_file.replace(".xml", ".json")
31
+
32
+print(("Looking for data between latitudes and longitudes " +
33
+       "({0}, {1}) and ({2}, {3})").format(lat_min, lng_min, lat_max, lng_max))
34
+
35
+if lat_min > lat_max:
36
+    lat_min, lat_max = lat_max, lat_min
37
+if lng_min > lng_max:
38
+    lng_min, lng_max = lng_max, lng_min
39
+
40
+# Extract relevant parts from the dataset
41
+ways = []
42
+xml = ET.parse(data_file)
43
+root = xml.getroot()
44
+
45
+nodes = {}
46
+for node in root.iter("node"):
47
+    lat = float(node.attrib["lat"])
48
+    lng = float(node.attrib["lon"])
49
+    if lat_min <= lat and lat <= lat_max and lng_min <= lng and lng <= lng_max:
50
+        x, y = pyproj.transform(wgs84, lambert, lng, lat)
51
+        id = node.attrib["id"]
52
+        nodes[id] = {"id": id,
53
+                     "lat": lat,
54
+                     "lng": lng,
55
+                     "x": x,
56
+                     "y": y}
57
+
58
+for way in root.iter("way"):
59
+    way_nodes = []
60
+    name = ""
61
+    type = ""
62
+    # Slopes
63
+    difficulty = ""
64
+    # Aerial ways
65
+    bubble = ""
66
+    capacity = ""
67
+    duration = ""
68
+    heating = ""
69
+    occupancy = ""
70
+    for nd in way.iter("nd"):
71
+        if nd.attrib["ref"] in nodes:
72
+            way_nodes.append(nodes[nd.attrib["ref"]])
73
+    for tag in way.iter("tag"):
74
+        if tag.attrib["k"] == "name":
75
+            name = tag.attrib["v"]
76
+        elif tag.attrib["k"] == "piste:difficulty":
77
+            difficulty = tag.attrib["v"]
78
+        elif tag.attrib["k"] == "piste:type":
79
+            type = tag.attrib["v"]
80
+        elif tag.attrib["k"] == "aerialway":
81
+            type = tag.attrib["v"]
82
+        elif tag.attrib["k"] == "aerialway:bubble":
83
+            bubble = tag.attrib["v"]
84
+        elif tag.attrib["k"] == "aerialway:capacity":
85
+            capacity = tag.attrib["v"]
86
+        elif tag.attrib["k"] == "aerialway:duration":
87
+            duration = tag.attrib["v"]
88
+        elif tag.attrib["k"] == "aerialway:heating":
89
+            heating = tag.attrib["v"]
90
+        elif tag.attrib["k"] == "aerialway:occupancy":
91
+            occupancy = tag.attrib["v"]
92
+    if len(way_nodes) > 0:
93
+        append = {"name": name,
94
+                  "type": type,
95
+                  "nodes": way_nodes}
96
+        if difficulty != "":
97
+            append["difficulty"] = difficulty
98
+        if(bubble != "" or capacity != "" or duration != "" or
99
+           heating != "" or occupancy != ""):
100
+            append["bubble"] = bubble
101
+            append["capacity"] = capacity
102
+            append["duration"] = duration
103
+            append["heating"] = heating
104
+            append["occupancy"] = occupancy
105
+        ways.append(append)
106
+
107
+
108
+# Write it to output file
109
+with open(out_file, 'w') as fh:
110
+    fh.write(json.dumps(ways, sort_keys=True,
111
+             indent=4, separators=(',', ': ')))
112
+
113
+if len(sys.argv) < 7:
114
+    print("Found data (also exported to "+out_file+"):")
115
+    print(json.dumps(ways, sort_keys=True,
116
+          indent=4, separators=(',', ': ')))
117
+else:
118
+    print("Found data exported to "+out_file+".")

+ 70
- 0
scripts/srtm_alti.py View File

@@ -0,0 +1,70 @@
1
+#!/usr/bin/env python3
2
+import struct
3
+import sys
4
+
5
+"""
6
+This script filters the SRTM altimetry dataset from NASA to keep only the
7
+relevant files for the specified area.
8
+
9
+Input is an HGT file from the SRTM dataset.
10
+Output is an ASCII XYZ gridded file, sorted by increasing X and decreasing Y.
11
+"""
12
+
13
+
14
+def lat_lng_to_row_col(lat, lng):
15
+    return 1201 - round((lng % 1) * 3600 / 3), round((lat % 1) * 3600 / 3)
16
+
17
+
18
+if len(sys.argv) < 6:
19
+    print("Usage: "+sys.argv[0]+" LAT_MIN LNG_MIN LAT_MAX LNG_MAX HGT_FILE")
20
+    sys.exit()
21
+
22
+lat_min = float(sys.argv[1])
23
+lng_min = float(sys.argv[2])
24
+lat_max = float(sys.argv[3])
25
+lng_max = float(sys.argv[4])
26
+hgt_file = sys.argv[5]
27
+
28
+if len(sys.argv) > 6:
29
+    out_file = sys.argv[6]
30
+else:
31
+    out_file = "out.xyz"
32
+
33
+print(("Looking for data between latitudes and longitudes " +
34
+       "({0}, {1}) and ({2}, {3})").format(lat_min, lng_min, lat_max, lng_max))
35
+
36
+# Extract relevant parts from the dataset and output it as xyz values
37
+# X and Y are pixels coordinates in this case
38
+out = "X\tY\tZ\n"
39
+with open(hgt_file, "rb") as fh:
40
+    # The first row in the file is very likely the northernmost one and there
41
+    # are 1200 rows. 3 arc-seconds sampling
42
+    row_min, col_min = lat_lng_to_row_col(lat_min, lng_min)
43
+    row_max, col_max = lat_lng_to_row_col(lat_max, lng_max)
44
+    print("Corresponding rectangle in the image is " +
45
+          "({0}, {1}), ({2}, {3})".format(row_min, col_min, row_max, col_max))
46
+
47
+    if col_min > col_max:
48
+        col_min, col_max = col_max, col_min
49
+    if row_min > row_max:
50
+        row_min, row_max = row_max, row_min
51
+
52
+    for i in range(row_max, row_min - 1, -1):
53
+        for j in range(col_min, col_max + 1):
54
+            fh.seek(((i - 1) * 1201 + (j - 1)) * 2)  # Find the right spot
55
+            buf = fh.read(2)  # read two bytes and convert them
56
+            val = struct.unpack('>h', buf)  # ">h" is a signed two byte integer
57
+            out += "{0}\t{1}\t{2}\n".format(j,
58
+                                            i,
59
+                                            val[0])
60
+out = out.strip()
61
+
62
+# Write it to out.xyz file
63
+with open(out_file, 'w') as fh:
64
+    fh.write(out)
65
+
66
+if len(sys.argv) < 7:
67
+    print("Found data (also exported to "+out_file+"):")
68
+    print(out)
69
+else:
70
+    print("Found data exported to "+out_file+".")

+ 0
- 0
src/3rdparty/CMakeLists.txt View File


+ 1
- 0
src/3rdparty/linmath

@@ -0,0 +1 @@
1
+Subproject commit a9b12ac7c333e52ca0a28664f5fa50d5a93a89db

+ 6
- 0
src/CMakeLists.txt View File

@@ -0,0 +1,6 @@
1
+add_subdirectory (3rdparty)
2
+
3
+FILE (GLOB SKIMAP_CORE_SRC core/*.cc)
4
+FILE (GLOB SKIMAP_FRAMEWORK_SRC framework/*.cc)
5
+
6
+add_subdirectory (platform)

+ 67
- 0
src/core/SkiMapRenderer.cc View File

@@ -0,0 +1,67 @@
1
+// Associated header
2
+#include "SkiMapRenderer.h"
3
+
4
+// System includes
5
+#include <cmath>
6
+
7
+// Local headers
8
+#include "config.h"
9
+#include "platform_gl.h"
10
+
11
+
12
+SkiMapRenderer::SkiMapRenderer(int width, int height)
13
+    : Renderer(width, height)
14
+    , terrain_(config::VERTEX_SHADER_FILENAME, config::VERTEX_SHADER_FILENAME)
15
+    , directional_light_()
16
+{
17
+    directional_light_ = config::DIRECTIONAL_LIGHT;
18
+
19
+    on_surface_created();
20
+    on_surface_changed();
21
+}
22
+
23
+
24
+void SkiMapRenderer::on_surface_created(void) {
25
+    // Set background color
26
+    glClearColor(
27
+            config::CLEAR_COLOR[0],
28
+            config::CLEAR_COLOR[1],
29
+            config::CLEAR_COLOR[2],
30
+            config::CLEAR_COLOR[3]);
31
+
32
+    // Enable depth
33
+    glEnable(GL_DEPTH_TEST);
34
+
35
+    // Load shaders
36
+}
37
+
38
+
39
+void SkiMapRenderer::on_surface_changed(void) {
40
+    // Set the viewport
41
+    glViewport(0, 0, width_, height_);
42
+
43
+    // Set the projection matrix (perspective)
44
+    const float fov = config::FOV * 180 / M_PI;
45
+    const float aspect = static_cast<float>(width_) / static_cast<float>(height_);
46
+    mat4x4_perspective(projection_matrix_, fov, aspect, config::NEAR, config::FAR);
47
+
48
+    // Set the camera position and orientation
49
+    mat4x4_look_at(
50
+            view_matrix_,
51
+            config::DEFAULT_EYE,
52
+            config::DEFAULT_CENTER,
53
+            config::DEFAULT_UP);
54
+
55
+    // Enable culling
56
+    glEnable(GL_CULL_FACE);
57
+    glFrontFace(GL_CW);
58
+    glCullFace(GL_BACK);
59
+}
60
+
61
+
62
+void SkiMapRenderer::on_draw_frame(void) {
63
+    // Clear the buffers
64
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
65
+
66
+    terrain_.draw(view_matrix_, projection_matrix, directional_light_);
67
+};

+ 25
- 0
src/core/SkiMapRenderer.h View File

@@ -0,0 +1,25 @@
1
+#ifndef SKIMAP_CORE_RENDERER_H_
2
+#define SKIMAP_CORE_RENDERER_H_
3
+
4
+// 3rd party libraries
5
+#include "linmath/linmath.h"
6
+
7
+// Local includes
8
+#include "Renderer.h"
9
+#include "TerrainProgram.h"
10
+
11
+
12
+class SkiMapRenderer: public Renderer {
13
+    public:
14
+        explicit SkiMapRenderer(int width, int height);
15
+
16
+        virtual void on_surface_created(void);
17
+
18
+        virtual void on_surface_changed(void);
19
+
20
+        virtual void on_draw_frame(void);
21
+    private:
22
+        Terrain terrain_;
23
+        terrain_shader::DirectionalLight_t directional_light_;
24
+};
25
+#endif  // SKIMAP_CORE_RENDERER_H_

+ 156
- 0
src/core/Terrain.cc View File

@@ -0,0 +1,156 @@
1
+// Associated header file
2
+#include "Terrain.h"
3
+
4
+// Local includes
5
+#include "config.h"
6
+
7
+
8
+TerrainProgram::TerrainProgram(
9
+        const std::string vertex_shader_filename,
10
+        const std::string fragment_shader_filename)
11
+    : Program(vertex_shader_filename, fragment_shader_filename) {
12
+    // Empty on purpose
13
+}
14
+
15
+
16
+GLint TerrainProgram::get_location(const GLchar* uniform) const {
17
+    return glGetUniformLocation(program_id_, uniform);
18
+}
19
+
20
+
21
+Terrain::Terrain(
22
+        const std::string vertex_shader_filename,
23
+        const std::string fragment_shader_filename)
24
+    : program_(vertex_shader_filename, fragment_shader_filename)
25
+    , material(config::TERRAIN_MATERIAL)
26
+    , model_matrix_()
27
+    , terrainData_()
28
+    , buffer_id_(0)
29
+    , buffer_length_(0)
30
+{
31
+    // Set the model_matrix_ to identity as a safe default value
32
+    mat4x4_identity(model_matrix_);
33
+
34
+    // TODO[Lucas] Handle terrain data + buffer initialization + compute normal
35
+
36
+    // Initialize the buffer
37
+    buffer_length_ = sizeof(table_data);
38
+    // The buffer pointer by buffer_id_ contains X, Y, Z components for a
39
+    // vertex, followed by X, Y, Z component for the normal associated to this
40
+    // vertex, tightly packed in a 1D array.
41
+    buffer_id_ = create_vbo(buffer_length_, table_data, GL_STATIC_DRAW);
42
+}
43
+
44
+
45
+void Terrain::draw(
46
+        mat4x4 view_matrix,
47
+        mat4x4 projection_matrix,
48
+        terrain_shader::DirectionalLight_t directional_light) {
49
+    // Compute the necessary matrices
50
+    mat4x4 model_view_projection_matrix = {};
51
+    mat4x4 model_view_matrix = {};
52
+    mat4x4_mul(model_view_matrix, view_matrix_, model_matrix_);
53
+    mat4x4_mul(model_view_projection_matrix, projection_matrix_, model_view_matrix_);
54
+
55
+    // Use the TerrainProgram
56
+    glUseProgram(program_.get_program_id());
57
+
58
+    // Load computed Model-View-Projection matrix
59
+    glUniformMatrix4fv(
60
+            program_.get_location("u_mvp_matrix"),  // location
61
+            1,  // count
62
+            GL_FALSE,  // transpose? must be GL_FALSE
63
+            (GLfloat*) model_view_projection_matrix);  // values
64
+    glUniformMatrix4fv(
65
+            program_.get_location("u_mv_matrix"),  // location
66
+            1,  // count
67
+            GL_FALSE,  // transpose? must be GL_FALSE
68
+            (GLfloat*) model_view_matrix);  // values
69
+    // Directional light uniform
70
+    {
71
+        GLint loc = get_location("u_directional_light.direction");
72
+        glUniform3f(
73
+                loc,
74
+                directional_light.direction[0],
75
+                directional_light.direction[1],
76
+                directional_light.direction[2]);
77
+        loc = get_location("u_directional_light.halfplane");
78
+        glUniform3f(
79
+                loc,
80
+                directional_light.halfplane[0],
81
+                directional_light.halfplane[1],
82
+                directional_light.halfplane[2]);
83
+        loc = get_location("u_directional_light.ambient_color");
84
+        glUniform4f(
85
+                loc,
86
+                directional_light.ambient_color[0],
87
+                directional_light.ambient_color[1],
88
+                directional_light.ambient_color[2],
89
+                directional_light.ambient_color[3]);
90
+        loc = get_location("u_directional_light.diffuse_color");
91
+        glUniform4f(
92
+                loc,
93
+                directional_light.diffuse_color[0],
94
+                directional_light.diffuse_color[1],
95
+                directional_light.diffuse_color[2],
96
+                directional_light.diffuse_color[3]);
97
+        loc = get_location("u_directional_light.specular_color");
98
+        glUniform4f(
99
+                loc,
100
+                directional_light.specular_color[0],
101
+                directional_light.specular_color[1],
102
+                directional_light.specular_color[2],
103
+                directional_light.specular_color[3]);
104
+    }
105
+    // Material uniform
106
+    {
107
+        GLint loc = get_location("u_material.ambient_factor");
108
+        glUniform4f(
109
+                loc,
110
+                material_.ambient_factor[0],
111
+                material_.ambient_factor[1],
112
+                material_.ambient_factor[2]);
113
+        GLint loc = get_location("u_material.diffuse_factor");
114
+        glUniform4f(
115
+                loc,
116
+                material_.diffuse_factor[0],
117
+                material_.diffuse_factor[1],
118
+                material_.diffuse_factor[2]);
119
+        GLint loc = get_location("u_material.specular_factor");
120
+        glUniform4f(
121
+                loc,
122
+                material_.specular_factor[0],
123
+                material_.specular_factor[1],
124
+                material_.specular_factor[2]);
125
+        GLint loc = get_location("u_material.shininess");
126
+        glUniform1f(loc, material_.shininess);
127
+    }
128
+
129
+    // Use a VBO as terrain is not expected to change
130
+    // See https://gamedev.stackexchange.com/questions/11438/when-to-use-vertex-array-and-when-to-use-vbo
131
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
132
+    // Pass position attribute
133
+    glVertexAttribPointer(
134
+            program_.get_location("a_position"),  // attribute index
135
+            3,  // number of components per generic vertex attribute
136
+            GL_FLOAT,  // data type of each component
137
+            GL_FALSE,  // whether data should be normalized or not
138
+            // buffer contains X, Y, Z for a vertex, followed by X, Y, Z for the associated vertex, leading to 6 values offset
139
+            6 * sizeof(GLfloat),
140
+            BUFFER_OFFSET(0));  // offset for the first component
141
+    glEnableVertexAttribArray(program_.get_location("a_position"));
142
+    // Pass normal attribute
143
+    glVertexAttribPointer(
144
+            program_.get_location("a_normal"),  // attribute index
145
+            3,  // number of components per generic vertex attribute
146
+            GL_FLOAT,  // data type of each component
147
+            GL_FALSE,  // whether data should be normalized or not
148
+            // buffer contains X, Y, Z for a vertex, followed by X, Y, Z for the associated vertex, leading to 6 values offset
149
+            6 * sizeof(GLfloat),
150
+            BUFFER_OFFSET(3 * sizeof(GLfloat)));  // offset for the first component
151
+    glEnableVertexAttribArray(program_.get_location("a_normal"));
152
+    // Draw the points in the buffer
153
+    glDrawArrays(GL_TRIANGLE, 0, buffer_length_);
154
+    // Unbind buffer
155
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
156
+}

+ 85
- 0
src/core/Terrain.h View File

@@ -0,0 +1,85 @@
1
+#ifndef SKIMAP_CORE_TERRAIN_H_
2
+#define SKIMAP_CORE_TERRAIN_H_
3
+
4
+// 3rd party includes
5
+#include "linmath/linmath.h"
6
+
7
+// Local haders
8
+#include "platform_gl.h"
9
+
10
+namespace terrain_shader {
11
+    typedef struct {
12
+        vec3 direction;
13
+        vec3 halfplane;
14
+        vec4 ambient_color;
15
+        vec4 diffuse_color;
16
+        vec4 specular_color;
17
+    } DirectionalLight_t;
18
+
19
+    typedef struct {
20
+        vec4 ambient_factor;
21
+        vec4 diffuse_factor;
22
+        vec4 specular_factor;
23
+        GLfloat shininess;
24
+    } Material_t;
25
+}
26
+
27
+
28
+class TerrainProgram: public Program {
29
+    public:
30
+        /**
31
+         * Construct a TerrainProgram object, loading shaders from the given
32
+         * source files.
33
+         *
34
+         * @param  vertex_shader_filename    Path to the vertex shader file.
35
+         * @param  fragment_shader_filename  Path to the fragment shader file.
36
+         */
37
+        explicit TerrainProgram(
38
+                const std::string vertex_shader_filename,
39
+                const std::string fragment_shader_filename);
40
+
41
+        /**
42
+         * Getter for the locations of the uniforms and attributes in the shader.
43
+         */
44
+        GLint get_location(const GLchar* uniform) const;
45
+};
46
+
47
+
48
+class Terrain {
49
+    public:
50
+        /**
51
+         * Construct a Terrain object.
52
+         *
53
+         * @param  vertex_shader_filename    Path to the vertex shader file, to
54
+         *                                   pass to the TerrainProgram constructor.
55
+         * @param  fragment_shader_filename  Path to the fragment shader file, to
56
+         *                                   pass to the TerrainProgram constructor.
57
+         * @see TerrainProgram::TerrainProgram
58
+         */
59
+        explicit Terrain(
60
+                const std::string vertex_shader_filename,
61
+                const std::string fragment_shader_filename);
62
+
63
+
64
+        /**
65
+         * Actually draw the terrain.
66
+         *
67
+         * @param  view_matrix        the view matrix passed by the renderer.
68
+         * @param  projection_matrix  the view matrix passed by the renderer.
69
+         * @param  directional_light  the directional light structure to pass
70
+         *                            to the shader.
71
+         */
72
+        void draw(
73
+                mat4x4 view_matrix,
74
+                mat4x4 projection_matrix,
75
+                terrain_shader::DirectionalLight_t directional_light);
76
+    private:
77
+        TerrainProgram program_;  /**< Shaders program associated with terrain. */
78
+        terrain_shader::Material_t material_;  /**< Terrain material. */
79
+        mat4x4 model_matrix_;  /**< Model matrix to position the terrain. */
80
+        std::vector<float> terrainData_;  /** The actual terrain data. */
81
+        GLuint buffer_id_;  /**< GL id of the buffer to store the terrain data. */
82
+        int buffer_length_;  /**< The length of the buffer to store the terrain data. */
83
+};
84
+
85
+#endif  // SKIMAP_CORE_TERRAIN_H_

+ 33
- 0
src/core/config.h View File

@@ -0,0 +1,33 @@
1
+#ifndef SKIMAP_CORE_CONFIG_H_
2
+#define SKIMAP_CORE_CONFIG_H_
3
+
4
+// 3rd party includes
5
+#include <linmath/linmath.h>
6
+
7
+// Local includes
8
+#include "Terrain.h"
9
+
10
+
11
+namespace config {
12
+    const char* VERTEX_SHADER_FILENAME = "";
13
+    const char* FRAGMENT_SHADER_FILENAME = "";
14
+
15
+    const vec4 CLEAR_COLOR = {0.0f, 0.63f, 0.9f, 1.0f};
16
+
17
+    const float FOV = 45;
18
+    const float NEAR = 1.0f;
19
+    const float FAR = 100.0f;
20
+
21
+    const vec3 DEFAULT_EYE = {0.0f, 1.2f, 2.2f};
22
+    const vec3 DEFAULT_CENTER = {0.0f, 0.0f, 0.0f};
23
+    const vec3 DEFAULT_UP = {0.0f, 1.0f, 0.0f};  // Traditionnally, y is the camera vertical
24
+
25
+    const terrain_shader::Material_t TERRAIN_MATERIAL = {
26
+        {1.0f, 1.0f, 1.0f},  // ambient factor
27
+        {1.0f, 1.0f, 1.0f},  // diffuse factor
28
+        {0.0f, 0.0f, 0.0f},  // specular factor
29
+        0.0f  // shininess
30
+    };
31
+}
32
+
33
+#endif  // SKIMAP_CORE_CONFIG_H_

+ 24
- 0
src/framework/Buffer.cc View File

@@ -0,0 +1,24 @@
1
+// Associated header
2
+#include "buffer.h"
3
+
4
+// System includes
5
+#include <cstddef>
6
+
7
+
8
+GLuint create_vbo(const GLsizeiptr size, const GLvoid* data, const GLenum usage) {
9
+    if (NULL == data) {
10
+        // TODO[Error]
11
+    }
12
+	GLuint vbo_object;
13
+	glGenBuffers(1, &vbo_object);
14
+
15
+    if (0 == vbo_object) {
16
+        // TODO[Error]
17
+    }
18
+
19
+	glBindBuffer(GL_ARRAY_BUFFER, vbo_object);
20
+	glBufferData(GL_ARRAY_BUFFER, size, data, usage);
21
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
22
+
23
+	return vbo_object;
24
+}

+ 67
- 0
src/framework/Heightmap.cc View File

@@ -0,0 +1,67 @@
1
+// System includes
2
+#include <cstddef>
3
+#include <iostream>
4
+
5
+// 3rd party includes
6
+#include <xtiffio.h>
7
+#include <geotiffio.h>
8
+
9
+enum {
10
+    VERSION = 0, MAJOR, MINOR
11
+};
12
+
13
+
14
+int main(int argc, char*argv[]) {
15
+    if(argc < 2)
16
+    {
17
+        std::cerr << "Required arguments: filename" << std::endl;
18
+        return -1;
19
+    }
20
+
21
+    // Open TIFF descriptor to read GeoTIFF tags
22
+    TIFF *tif = XTIFFOpen(argv[1], "r");  // TIFF-level description
23
+    if (NULL == tif) {
24
+        // TODO[Error]
25
+    }
26
+
27
+    // Open GTIF Key parser; keys will be read at this time.
28
+    GTIF *gtif = GTIFNew(tif);  // GeoTIFF-level description
29
+    if (NULL == gtif) {
30
+        // TODO[Error]
31
+    }
32
+
33
+    // Get the GeoTIFF directory info
34
+    int versions[3] = {};
35
+    GTIFFDirectoryInfo(gtif, versions, 0);
36
+    if (versions[MAJOR] > 1) {
37
+        // TODO[Error] This file is too new
38
+    }
39
+    geocode_t model;  // All key-codes are of this type
40
+    if (0 != GTIFKeyGet(gtif, GTModelTypeGeoKey, &model, 0, 1)) {
41
+        // TODO[Error] Unable to find a model type
42
+    }
43
+
44
+    // ASCII keys are variable-length; compute size
45
+    int size = 0;
46
+    int cit_length = GTIFKeyInfo(gtif, GTCitationGeoKey, &size, &type);
47
+    if (cit_length > 0) {
48
+        char *citation = (char *) malloc(size * cit_length);
49
+        if (NULL == citation) {
50
+            // TODO[Error]
51
+        }
52
+        GTIFKeyGet(gtif, GTCitationGeoKey, citation, 0, cit_length);
53
+        printf("Citation:%s\n", citation);
54
+    }
55
+
56
+    // Get some TIFF info on this image
57
+    int width = 0;
58
+    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
59
+
60
+    // Get rid of the key parser
61
+    GTIFFree(gtif);
62
+
63
+    // Close the TIFF file descriptor
64
+    XTIFFClose(tif);
65
+
66
+    return 0;
67
+}

+ 105
- 0
src/framework/Program.cc View File

@@ -0,0 +1,105 @@
1
+// Associated header file
2
+#include "Program.h"
3
+
4
+// System headers
5
+#include <fstream>
6
+#include <sstream>
7
+
8
+
9
+Program::Program(
10
+        std::string vertex_shader_source_file,
11
+        std::string fragment_shader_source_file) {
12
+    // TODO[Lucas] Loading of vertex / fragment shader
13
+    // Load vertex shader from file
14
+    std::ifstream ifs(vertex_shader_source_file);
15
+    std::stringstream vertex_shader_source;
16
+    vertex_shader_source << ifs.rdbuf();
17
+
18
+    // Load fragment shader from file
19
+    ifs.open(fragment_shader_source_file);
20
+    std::stringstream fragment_shader_source;
21
+    fragment_shader_source << ifs.rdbuf();
22
+
23
+    // Build the program
24
+    build_program(
25
+            vertex_shader_source.str().c_str(),
26
+            fragment_shader_source.str().c_str());
27
+};
28
+
29
+
30
+GLuint get_program_id(void) const {
31
+    return program_id_;
32
+}
33
+
34
+
35
+GLuint Program::compile_shader(const GLenum type, const GLchar* source) {
36
+    if (NULL == source) {
37
+        // TODO[Error]
38
+    }
39
+
40
+    // Create a shader object of the correct type
41
+    GLuint shader_object_id = glCreateShader(type);
42
+    if (0 == shader_object_id) {
43
+        // TODO[Error]
44
+    }
45
+
46
+    // Compile the shader
47
+    glShaderSource(shader_object_id, 1, (const GLchar**)&source, NULL);
48
+    glCompileShader(shader_object_id);
49
+
50
+    // Check the compilation status
51
+    GLint compile_status;
52
+    glGetShaderiv(shader_object_id, GL_COMPILE_STATUS, &compile_status);
53
+    if (0 == compile_status) {
54
+        // TODO[Error]
55
+    }
56
+
57
+    // Return the id of the compiled shader
58
+    return shader_object_id;
59
+}
60
+
61
+
62
+GLuint Program::link(const GLuint vertex_shader, const GLuint fragment_shader) {
63
+    // Create a new program
64
+    GLuint program_object_id = glCreateProgram();
65
+    if (0 == program_object_id) {
66
+        // TODO[Error]
67
+    }
68
+
69
+    // Attach shaders to the program object
70
+    glAttachShader(program_object_id, vertex_shader);
71
+    glAttachShader(program_object_id, fragment_shader);
72
+    glLinkProgram(program_object_id);
73
+
74
+    // Check link status
75
+    GLint link_status;
76
+    glGetProgramiv(program_object_id, GL_LINK_STATUS, &link_status);
77
+    if (0 == link_status) {
78
+        // TODO[Error]
79
+    }
80
+
81
+    // Return the id of the linked program
82
+    return program_object_id;
83
+}
84
+
85
+
86
+void Program::build(
87
+        const GLchar* vertex_shader_source;
88
+        const GLchar* fragment_shader_source) {
89
+    if ((NULL == vertex_shader_source) || (NULL == fragment_shader_source)) {
90
+        // TODO[Error]
91
+    }
92
+
93
+    // Compile vertex shader
94
+    GLuint vertex_shader = compile_shader(
95
+            GL_VERTEX_SHADER,
96
+            vertex_shader_source);
97
+
98
+    // Compile fragment shader
99
+    GLuint fragment_shader = compile_shader(
100
+            GL_FRAGMENT_SHADER,
101
+            fragment_shader_source);
102
+
103
+    // Link both of them and set the program id
104
+    program_id_ = link_program(vertex_shader, fragment_shader);
105
+};

+ 72
- 0
src/framework/Program.h View File

@@ -0,0 +1,72 @@
1
+#ifndef SKIMAP_FRAMEWORK_PROGRAM_H_
2
+#define SKIMAP_FRAMEWORK_PROGRAM_H_
3
+
4
+// Local haders
5
+#include "platform_gl.h"
6
+
7
+
8
+class Program {
9
+    public:
10
+        /**
11
+         * Constructs a program made of both a vertex shader and a fragment
12
+         * shader. It compiles the shaders and link them together in a program.
13
+         *
14
+         * @param vertex_shader_source_file is the filename of the vertex
15
+         * shader.
16
+         * @param fragment_shader_source_file is the filename of the associated
17
+         * fragment shader.
18
+         */
19
+        explicit Program(
20
+                std::string vertex_shader_source_file,
21
+                std::string fragment_shader_source_file);
22
+
23
+
24
+        /**
25
+         * Getter for the program_id_ data member.
26
+         */
27
+        GLuint get_program_id(void) const;
28
+    protected:
29
+        GLuint program_id_;  /**< The linked program id. */
30
+    private:
31
+        /**
32
+         * This private method is a handler for shader compilation. It compiles
33
+         * the shader passed as argument as a string.
34
+         *
35
+         * @param type is the type of the compiled shader.
36
+         * @param source is the string containing the shader source (assumed to
37
+         * be NULL-terminated).
38
+         *
39
+         * @return the id of the compiled shader.
40
+         */
41
+        GLuint compile_shader(const GLenum type, const GLchar* source);
42
+
43
+
44
+        /**
45
+         * This private method is a handler for linking together a vertex and a
46
+         * fragment shader.
47
+         *
48
+         * @param vertex_shader is the id of the compiled vertex shader.
49
+         * @param fragment_shader is the id of the compiled fragment shader.
50
+         *
51
+         * @return the id of the linked program.
52
+         */
53
+        GLuint link(const GLuint vertex_shader, const GLuint fragment_shader);
54
+
55
+
56
+        /**
57
+         * This private method is a handler for compiling shaders and linking
58
+         * them together in a program. It calls Program::compile_shader and
59
+         * Program::link under the hood. It sets the private attribute
60
+         * program_id_ to the id of the linked program.
61
+         *
62
+         * @param vertex_shader_source is a string containing the shader source
63
+         * (assumed to be NULL-terminated).
64
+         * @param fragment_shader_source is a string containing the shader source
65
+         * (assumed to be NULL-terminated).
66
+         */
67
+        void build(
68
+                const GLchar* vertex_shader_source;
69
+                const GLchar* fragment_shader_source);
70
+};
71
+
72
+#endif  // SKIMAP_FRAMEWORK_PROGRAM_H_

+ 16
- 0
src/framework/Renderer.cc View File

@@ -0,0 +1,16 @@
1
+// Associated header
2
+#include "Renderer.h"
3
+
4
+
5
+Renderer::Renderer(int width, int height)
6
+    : width_(width), height_(height), projection_matrix_(), view_matrix_()
7
+{
8
+    // Initialize matrices with identity
9
+    mat4x4_identity(projection_matrix_);
10
+    mat4x4_identity(view_matrix_);
11
+};
12
+
13
+
14
+Renderer::~Renderer(void) {
15
+    // Empty on purpose
16
+}

+ 22
- 0
src/framework/Renderer.h View File

@@ -0,0 +1,22 @@
1
+#ifndef SKIMAP_FRAMEWORK_RENDERER_H_
2
+#define SKIMAP_FRAMEWORK_RENDERER_H_
3
+
4
+#include "linmath/linmath.h"
5
+
6
+class Renderer {
7
+    public:
8
+        explicit Renderer(int width, int height);
9
+
10
+        virtual ~Renderer(void);
11
+
12
+        virtual void on_surface_created(void) = 0;
13
+
14
+        virtual void on_surface_changed() = 0;
15
+
16
+        virtual void on_draw_frame(void) = 0;
17
+    protected:
18
+        int width_, height_;
19
+        mat4x4 projection_matrix_, view_matrix_;
20
+};
21
+
22
+#endif  // SKIMAP_FRAMEWORK_RENDERER_H_

+ 10
- 0
src/framework/buffer.h View File

@@ -0,0 +1,10 @@
1
+#ifndef SKIMAP_FRAMEWORK_BUFFER_H_
2
+#define SKIMAP_FRAMEWORK_BUFFER_H_
3
+
4
+// Local includes
5
+#include "platform_gl.h"
6
+
7
+
8
+GLuint create_vbo(const GLsizeiptr size, const GLvoid* data, const GLenum usage);
9
+
10
+#endif  // SKIMAP_FRAMEWORK_BUFFER_H_

+ 1
- 0
src/platform/CMakeLists.txt View File

@@ -0,0 +1 @@
1
+add_subdirectory (emscripten)

+ 11
- 0
src/platform/emscripten/CMakeLists.txt View File

@@ -0,0 +1,11 @@
1
+SET (CMAKE_CXX_COMPILER "em++")
2
+SET (CMAKE_USE_RELATIVE_PATHS TRUE)
3
+
4
+FILE (GLOB SKIMAP_PLATFORM_EMSCRIPTEN_SRC *.cc)
5
+
6
+add_executable (out.html
7
+    ${SKIMAP_FRAMEWORK_SRC}
8
+    ${SKIMAP_CORE_SRC}
9
+    ${SKIMAP_PLATFORM_EMSCRIPTEN_SRC})
10
+
11
+target_include_directories (out.html PUBLIC "../../3rdparty" "../../framework" "../../core" ".")

+ 54
- 0
src/platform/emscripten/main.cc View File

@@ -0,0 +1,54 @@
1
+// System includes
2
+#include <cstdlib>
3
+#include <cstdio>
4
+#include <GL/glfw.h>
5
+#include <emscripten/emscripten.h>
6
+
7
+// Local includes
8
+#include "Surface.h"
9
+
10
+namespace {
11
+    SkiMapSurface* surface = NULL;
12
+
13
+    int init_gl(int width, int height) {
14
+        if (glfwInit() != GL_TRUE) {
15
+            printf("glfwInit() failed\n");
16
+            return GL_FALSE;
17
+        }
18
+
19
+        if (glfwOpenWindow(width, height, 8, 8, 8, 8, 16, 0, GLFW_WINDOW) != GL_TRUE) {
20
+            printf("glfwOpenWindow() failed\n");
21
+            return GL_FALSE;
22
+        }
23
+
24
+        return GL_TRUE;
25
+    }
26
+
27
+
28
+    void do_frame(void) {
29
+        if (NULL != surface) {
30
+            surface->on_draw_frame();
31
+            glfwSwapBuffers();
32
+        }
33
+    }
34
+
35
+
36
+    void shutdown_gl(void) {
37
+        glfwTerminate();
38
+    }
39
+}
40
+
41
+
42
+int main()
43
+{
44
+    const int width = 480, height = 800;
45
+
46
+	if (GL_TRUE == init_gl(width, height)) {
47
+        surface = new SkiMapSurface(width, height);
48
+		emscripten_set_main_loop(do_frame, 0, 1);
49
+	}
50
+
51
+	shutdown_gl();
52
+
53
+	return 0;
54
+}

+ 2
- 0
src/platform/emscripten/platform_gl.h View File

@@ -0,0 +1,2 @@
1
+// Contains the path where the OpenGL headers are stored
2
+#include <GLES2/gl2.h>