diff options
author | Konstantin Käfer <github@kkaefer.com> | 2014-01-07 12:10:14 +0100 |
---|---|---|
committer | Konstantin Käfer <github@kkaefer.com> | 2014-01-07 12:10:14 +0100 |
commit | 44b43fe5a608ef0d2f83b2c99ec5b87c6e00f6e0 (patch) | |
tree | a65c62c85ee579e45ae30fd406a81bb7d9f03a0a | |
download | qtlocation-mapboxgl-44b43fe5a608ef0d2f83b2c99ec5b87c6e00f6e0.tar.gz |
glfw version of sample app
28 files changed, 1376 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..106055e55d --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +CXXFLAGS = -Wall -Wextra -std=c++11 -stdlib=libc++ -fno-exceptions +CPPFLAGS = -O3 -DDEBUG +INCLUDE = -Iinclude + + + +SRCS += src/map/map.cpp +SRCS += src/map/tile.cpp +SRCS += src/map/transform.cpp +SRCS += src/geometry/linevertexbuffer.cpp +SRCS += src/renderer/painter.cpp +SRCS += src/renderer/shader.cpp +SRCS += src/renderer/shader-fill.cpp +SRCS += src/renderer/shader-line.cpp +SRCS += src/util/mat4.c + +SRCS += macosx/main.mm + +OBJS = $(patsubst %.mm,%.o,$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,$(SRCS)))) + +main: macosx + +library: $(OBJS) + +macosx: library + $(CXX) $(OBJS) $(INCLUDE) -lglfw3 -framework OpenGL -framework Foundation -o bin/macosx + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE) -c -o $@ $^ + +%.o: %.mm + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE) -c -o $@ $^ + +%.o: %.c + $(CC) $(CPPFLAGS) $(INCLUDE) -c -o $@ $^ + +clean: + rm -rf src/*/*.o + rm -rf bin/macosx + +.PHONY: macosx diff --git a/enable-emscripten b/enable-emscripten new file mode 100644 index 0000000000..d7feba1eab --- /dev/null +++ b/enable-emscripten @@ -0,0 +1,2 @@ +#!/bin/sh +export PATH="`emsdk active_path`:$PATH" diff --git a/include/llmr/geometry/linevertexbuffer.hpp b/include/llmr/geometry/linevertexbuffer.hpp new file mode 100644 index 0000000000..8d5c6b335c --- /dev/null +++ b/include/llmr/geometry/linevertexbuffer.hpp @@ -0,0 +1,26 @@ +#ifndef LLMR_GEOMETRY_LINEVERTEXBUFFER +#define LLMR_GEOMETRY_LINEVERTEXBUFFER + +#include "../platform/gl.hpp" + +#include <vector> + +namespace llmr { + +class linevertexbuffer { +public: + linevertexbuffer(); + + void addDegenerate(); + void addCoordinate(int16_t x, int16_t y); + + uint32_t length(); + void bind(); +private: + std::vector<uint16_t> array; + GLuint buffer; +}; + +} + +#endif diff --git a/include/llmr/llmr.hpp b/include/llmr/llmr.hpp new file mode 100644 index 0000000000..2d9b46b9c1 --- /dev/null +++ b/include/llmr/llmr.hpp @@ -0,0 +1,6 @@ +#ifndef LLMR_MAIN +#define LLMR_MAIN + +#include "map/map.hpp" + +#endif diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp new file mode 100644 index 0000000000..e19236f12e --- /dev/null +++ b/include/llmr/map/map.hpp @@ -0,0 +1,34 @@ +#ifndef LLMR_MAP_MAP +#define LLMR_MAP_MAP + +#include "../platform/platform.hpp" +#include "../renderer/painter.hpp" +#include "transform.hpp" + +namespace llmr { + +class tile; + +class map { +public: + map(class platform *platform, class painter *painter); + ~map(); + + /* callback */ + bool render(); + void moveBy(double dx, double dy); + void scaleBy(double ds, double cx, double cy); + void tileLoaded(tile *tile); + void tileFailed(tile *tile); + +private: + platform *platform; + painter *painter; + transform *transform; + + std::vector<tile *> tiles; +}; + +} + +#endif diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp new file mode 100644 index 0000000000..026810ace4 --- /dev/null +++ b/include/llmr/map/tile.hpp @@ -0,0 +1,35 @@ +#ifndef LLMR_MAP_TILE +#define LLMR_MAP_TILE + +#include "../geometry/linevertexbuffer.hpp" + +#include <stdint.h> +#include <vector> + +namespace llmr { + +class tile { +public: + tile(int32_t z, int32_t x, int32_t y); + + void setData(uint8_t *data, uint32_t bytes); + bool parse(); + void parseLayer(const uint8_t *data, uint32_t bytes); + void parseFeature(const uint8_t *data, uint32_t bytes); + void loadGeometry(const uint8_t *data, uint32_t bytes); + +public: + const int32_t z, x, y; + bool loaded; + linevertexbuffer lineVertex; + +private: + // Source data + uint8_t *data; + uint32_t bytes; + +}; + +} + +#endif diff --git a/include/llmr/map/transform.hpp b/include/llmr/map/transform.hpp new file mode 100644 index 0000000000..26a6683f20 --- /dev/null +++ b/include/llmr/map/transform.hpp @@ -0,0 +1,22 @@ +#ifndef LLMR_MAP_TRANSFORM +#define LLMR_MAP_TRANSFORM + +namespace llmr { + +class tile; + +class transform { +public: + transform(); + + void moveBy(double dx, double dy); + void scaleBy(double ds, double cx, double cy); + +public: + double x, y; + double scale; +}; + +} + +#endif diff --git a/include/llmr/platform/gl.hpp b/include/llmr/platform/gl.hpp new file mode 100644 index 0000000000..4fa0cf4775 --- /dev/null +++ b/include/llmr/platform/gl.hpp @@ -0,0 +1,22 @@ +#ifndef LLMR_RENDERER_GL +#define LLMR_RENDERER_GL + +#ifdef __APPLE__ + #include "TargetConditionals.h" + #if TARGET_OS_IPHONE + #include <OpenGLES/ES2/gl.h> + #include <OpenGLES/ES2/glext.h> + #elif TARGET_IPHONE_SIMULATOR + #include <OpenGLES/ES2/gl.h> + #include <OpenGLES/ES2/glext.h> + #elif TARGET_OS_MAC + #include <GLFW/glfw3.h> + #include <OpenGL/OpenGL.h> + #else + #error Unsupported Apple platform + #endif +#else + #error Unsupported platform +#endif + +#endif diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp new file mode 100644 index 0000000000..46a1383c42 --- /dev/null +++ b/include/llmr/platform/platform.hpp @@ -0,0 +1,24 @@ +#ifndef LLMR_PLATFORM_IOS +#define LLMR_PLATFORM_IOS + +namespace llmr { + +class tile; + +class platform { +public: + platform(void *obj) : obj(obj) {} + + const char *shaderSource(const char *name, const char *extension); + void restart(); + void request(tile *tile); + +private: + void *obj; +}; + +} + + + +#endif diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp new file mode 100644 index 0000000000..ac6012b0d0 --- /dev/null +++ b/include/llmr/renderer/painter.hpp @@ -0,0 +1,55 @@ +#ifndef LLMR_RENDERER_PAINTER +#define LLMR_RENDERER_PAINTER + +#include "../platform/gl.hpp" + +#include "shader-fill.hpp" +#include "shader-line.hpp" + +namespace llmr { + +class platform; +class transform; +class tile; + +class painter { +public: + painter(class platform *platform); + + void setup(); + void teardown(); + + void resize(GLuint new_width, GLuint new_height); + void viewport(); + + + void clear(); + void render(tile *tile); + + void switchShader(Shader *shader, float matrix[16]); + void setTransform(transform *transform); + +private: + void setupShaders(); + void changeMatrix(); + +public: + +private: + platform *platform; + transform *transform; + GLuint width, height; + GLfloat matrix[16]; + + Shader *currentShader; + FillShader *fillShader; + LineShader *lineShader; + + GLuint vertexArray; + GLuint triangleVertexBuffer; + GLuint fillVertexBuffer; +}; + +} + +#endif diff --git a/include/llmr/renderer/shader-fill.hpp b/include/llmr/renderer/shader-fill.hpp new file mode 100644 index 0000000000..165266e4b5 --- /dev/null +++ b/include/llmr/renderer/shader-fill.hpp @@ -0,0 +1,19 @@ +#ifndef LLMR_RENDERER_SHADER_FILL +#define LLMR_RENDERER_SHADER_FILL + +#include "shader.hpp" + +namespace llmr { + +class FillShader : public Shader { +public: + FillShader(const GLchar *vertex, const GLchar *fragment); + + GLint a_pos; + GLint u_matrix; + GLint u_color; +}; + +} + +#endif diff --git a/include/llmr/renderer/shader-line.hpp b/include/llmr/renderer/shader-line.hpp new file mode 100644 index 0000000000..60e27146f9 --- /dev/null +++ b/include/llmr/renderer/shader-line.hpp @@ -0,0 +1,19 @@ +#ifndef LLMR_RENDERER_SHADER_LINE +#define LLMR_RENDERER_SHADER_LINE + +#include "shader.hpp" + +namespace llmr { + +class LineShader : public Shader { +public: + LineShader(const GLchar *vertex, const GLchar *fragment); + + GLint a_pos; + GLint u_matrix; + GLint u_color; +}; + +} + +#endif diff --git a/include/llmr/renderer/shader.hpp b/include/llmr/renderer/shader.hpp new file mode 100644 index 0000000000..d178a1d9c8 --- /dev/null +++ b/include/llmr/renderer/shader.hpp @@ -0,0 +1,23 @@ +#ifndef LLMR_RENDERER_SHADER +#define LLMR_RENDERER_SHADER + +#include "../platform/gl.hpp" +#include <vector> + +namespace llmr { + +class Shader { +public: + Shader(const GLchar *vertex, const GLchar *fragment); + ~Shader(); + bool valid; + GLuint program; + std::vector<GLuint> attributes; + +private: + bool compileShader(GLuint *shader, GLenum type, const GLchar *source); +}; + +} + +#endif diff --git a/include/llmr/util/mat4.h b/include/llmr/util/mat4.h new file mode 100644 index 0000000000..bdfc3b1715 --- /dev/null +++ b/include/llmr/util/mat4.h @@ -0,0 +1,41 @@ +// This is an incomplete port of http://glmatrix.net/ +// +// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a +// product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef llmr_util_mat4_ +#define llmr_util_mat4_ + +#ifdef __cplusplus +extern "C" { +#endif + +void mat4_identity(float out[16]); +void mat4_ortho(float out[16], float left, float right, float bottom, float top, float near, float far); +void mat4_copy(float out[16], float a[16]); +void mat4_translate(float out[16], float a[16], float x, float y, float z); +void mat4_scale(float out[16], float a[16], float x, float y, float z); +void mat4_multiply(float out[16], float a[16], float b[16]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/geometry/linevertexbuffer.cpp b/src/geometry/linevertexbuffer.cpp new file mode 100644 index 0000000000..03cbdb79b1 --- /dev/null +++ b/src/geometry/linevertexbuffer.cpp @@ -0,0 +1,33 @@ +#include <llmr/geometry/linevertexbuffer.hpp> + +using namespace llmr; + +linevertexbuffer::linevertexbuffer() + : buffer(0) { +} + +void linevertexbuffer::addDegenerate() { + array.push_back(32767); + array.push_back(0); +} + +void linevertexbuffer::addCoordinate(int16_t x, int16_t y) { + array.push_back(x); + array.push_back(y); +} + +uint32_t linevertexbuffer::length() { + // We store 2 coordinates per vertex + return array.size() / 2; +} + +void linevertexbuffer::bind() { + if (buffer == 0) { + glGenBuffers(1, &buffer); + fprintf(stderr, "new buffer id: %d\n", buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, array.size() * sizeof(uint16_t), array.data(), GL_STATIC_DRAW); + } else { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + } +} diff --git a/src/map/map.cpp b/src/map/map.cpp new file mode 100644 index 0000000000..397ba384d8 --- /dev/null +++ b/src/map/map.cpp @@ -0,0 +1,64 @@ +#include <llmr/map/map.hpp> +#include <llmr/map/tile.hpp> + +#include <iostream> +#include <thread> + +using namespace llmr; + +map::map(class platform *platform, class painter *painter) + : platform(platform), + painter(painter), + transform(new class transform()) { + + painter->setTransform(transform); + + + tile *tile = new class tile(0, 0, 0); + tiles.push_back(tile); + platform->request(tile); + +} + +map::~map() { + delete transform; +} + + +void map::moveBy(double dx, double dy) { + transform->moveBy(dx, dy); + platform->restart(); +} + +void map::scaleBy(double ds, double cx, double cy) { + transform->scaleBy(ds, cx, cy); + platform->restart(); +} + + +bool map::render() { + painter->clear(); + + for (tile *tile : tiles) { + // painter->viewport(); + if (tile->loaded) { + painter->render(tile); + } + } + + return false; +} + +void map::tileLoaded(tile *tile) { + platform->restart(); + // fprintf(stderr, "[%8zx] tile loaded %d/%d/%d\n", + // std::hash<std::thread::id>()(std::this_thread::get_id()), + // tile->z, tile->x, tile->y); + // schedule rerender +} + +void map::tileFailed(tile *tile) { + fprintf(stderr, "[%8zx] tile failed to load %d/%d/%d\n", + std::hash<std::thread::id>()(std::this_thread::get_id()), + tile->z, tile->x, tile->y); +}
\ No newline at end of file diff --git a/src/map/pbf.hpp b/src/map/pbf.hpp new file mode 100644 index 0000000000..faf0aadf91 --- /dev/null +++ b/src/map/pbf.hpp @@ -0,0 +1,178 @@ +#pragma once + +/* + * Some parts are from upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2008-2011 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + */ + +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <string> +// #include <cassert> + +namespace llmr { + +struct pbf { + inline pbf(const unsigned char *data, uint32_t length); + inline pbf(const char *data, uint32_t length); + // inline pbf(const std::string& buffer); + + inline bool next(); + inline uint64_t varint(); + inline int64_t svarint(); + inline std::string string(); + inline float float32(); + inline double float64(); + inline int64_t int64(); + inline bool boolean(); + + template <typename T, typename... Args> + inline T *message(const Args&... args); + + inline void skip(); + inline void skipValue(uint32_t val); + inline void skipBytes(uint32_t bytes); + + const uint8_t *data; + const uint8_t *end; + uint32_t value; + uint32_t tag; +}; + +pbf::pbf(const unsigned char *data, uint32_t length) + : data(data), + end(data + length) +{} + +pbf::pbf(const char *data, uint32_t length) + : data((const unsigned char *)data), + end((const unsigned char *)data + length) +{} + +// pbf::pbf(const std::string& buffer) +// : data((const unsigned char *)buffer.data()), +// end((const unsigned char *)buffer.data() + buffer.size()) +// {} + +bool pbf::next() +{ + if (data < end) { + value = (uint32_t)varint(); + tag = value >> 3; + return true; + } + return false; +} + + +uint64_t pbf::varint() +{ + uint8_t byte = 0x80; + uint64_t result = 0; + int bitpos; + for (bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { + if (data >= end) { + fprintf(stderr, "unterminated varint, unexpected end of buffer"); + exit(1); + } + result |= ((uint64_t)(byte = *data) & 0x7F) << bitpos; + + data++; + } + if (bitpos == 70 && (byte & 0x80)) { + fprintf(stderr, "unterminated varint (too long)"); + exit(1); + } + + return result; +} + +int64_t pbf::svarint() +{ + uint64_t n = varint(); + return (n >> 1) ^ -(int64_t)(n & 1); +} + +std::string pbf::string() +{ + uint32_t bytes = (uint32_t)varint(); + const char *string = (const char *)data; + skipBytes(bytes); + return std::string(string, bytes); +} + +float pbf::float32() +{ + skipBytes(4); + float result; + memcpy(&result, data - 4, 4); + return result; +} +double pbf::float64() +{ + skipBytes(8); + double result; + memcpy(&result, data - 8, 8); + return result; +} + +int64_t pbf::int64() +{ + return (int64_t)varint(); +} + +bool pbf::boolean() +{ + skipBytes(1); + return *(bool *)(data - 1); +} + + +template <typename T, typename... Args> T *pbf::message(const Args&... args) +{ + uint32_t bytes = (uint32_t)varint(); + T *result = new T(data, bytes, args...); + skipBytes(bytes); + return result; +} + +void pbf::skip() +{ + skipValue(value); +} + +void pbf::skipValue(uint32_t val) +{ + switch (val & 0x7) { + case 0: // varint + varint(); + break; + case 1: // 64 bit + skipBytes(8); + break; + case 2: // string/message + skipBytes((uint32_t)varint()); + break; + case 5: // 32 bit + skipBytes(4); + break; + default: + fprintf(stderr, "cannot skip unknown type %d", val & 0x7); + exit(1); + } +} + +void pbf::skipBytes(uint32_t bytes) +{ + data += bytes; + if (data > end) { + fprintf(stderr, "unexpected end of buffer"); + exit(1); + } +} + +} // end namespace llmr + diff --git a/src/map/tile.cpp b/src/map/tile.cpp new file mode 100644 index 0000000000..a27f6e5ba8 --- /dev/null +++ b/src/map/tile.cpp @@ -0,0 +1,138 @@ +#include <llmr/map/tile.hpp> + +#include <stdint.h> +// #include <iostream> +#include <thread> + +#include "pbf.hpp" + +using namespace llmr; + +tile::tile(int32_t z, int32_t x, int32_t y) + : z(z), + x(x), + y(y), + loaded(false), + data(0), + bytes(0) { +} + +void tile::setData(uint8_t *data, uint32_t bytes) { + this->data = (uint8_t *)malloc(bytes); + this->bytes = bytes; + memcpy(this->data, data, bytes); +} + +bool tile::parse() +{ + fprintf(stderr, "[%8zx] parsing tile\n", + std::hash<std::thread::id>()(std::this_thread::get_id()) + ); + + // try { + pbf tile(data, bytes); + while (tile.next()) { + if (tile.tag == 3) { // layer + uint32_t bytes = (uint32_t)tile.varint(); + parseLayer(tile.data, bytes); + tile.skipBytes(bytes); + } else { + tile.skip(); + } + } + // } catch (std::exception& ex) { + // std::cerr << ex.what(); + // return false; + // } + + loaded = true; + return true; +} + +void tile::parseLayer(const uint8_t *data, uint32_t bytes) { + pbf layer(data, bytes); + std::string name; + while (layer.next()) { + if (layer.tag == 1) { + name = layer.string(); + } else if (layer.tag == 2) { + uint32_t bytes = (uint32_t)layer.varint(); + parseFeature(layer.data, bytes); + layer.skipBytes(bytes); + } else { + layer.skip(); + } + } +} + +void tile::parseFeature(const uint8_t *data, uint32_t bytes) { + pbf feature(data, bytes); + while (feature.next()) { + if (feature.tag == 1) { + uint64_t id = feature.varint(); + } else if (feature.tag == 2) { + const uint8_t *tag_end = feature.data + feature.varint(); + while (feature.data < tag_end) { + uint32_t key = (uint32_t)feature.varint(); + uint32_t value = (uint32_t)feature.varint(); + } + } else if (feature.tag == 3) { + uint32_t type = (uint32_t)feature.varint(); + } else if (feature.tag == 4) { + uint32_t bytes = (uint32_t)feature.varint(); + loadGeometry(feature.data, bytes); + feature.skipBytes(bytes); + } else { + feature.skip(); + } + } +} + +void tile::loadGeometry(const uint8_t *data, uint32_t bytes) { + pbf geometry(data, bytes); + + uint32_t cmd = 1; + uint32_t length = 0; + int32_t x = 0, y = 0; + + // var lines = []; + // var line = null; + int32_t ox = 0, oy = 0; + + while (geometry.data < geometry.end) { + if (!length) { + uint32_t cmd_length = (uint32_t)geometry.varint(); + cmd = cmd_length & 0x7; + length = cmd_length >> 3; + } + + length--; + + if (cmd == 1 || cmd == 2) { + x += geometry.svarint(); + y += geometry.svarint(); + + if (cmd == 1) { + // moveTo + // fprintf(stderr, "[m %d/%d] ", x, y); + // degenerate vertex + lineVertex.addDegenerate(); + ox = x; + oy = y; + } else { + // lineTo + // fprintf(stderr, "[l %d/%d] ", x, y); + } + lineVertex.addCoordinate(x, y); + } else if (cmd == 7) { + // closePolygon + // fprintf(stderr, "[c]\n"); + lineVertex.addCoordinate(ox, oy); + } else { + // throw new Error('unknown command ' + cmd); + // throw std::runtime_error("unknown command"); + fprintf(stderr, "unknown command"); + exit(1); + } + } +} diff --git a/src/map/transform.cpp b/src/map/transform.cpp new file mode 100644 index 0000000000..61d982192d --- /dev/null +++ b/src/map/transform.cpp @@ -0,0 +1,21 @@ +#include <llmr/map/transform.hpp> + +using namespace llmr; + +transform::transform() + : x(0.0f), + y(0.0f), + scale(1.0f) { + +} + +void transform::moveBy(double dx, double dy) { + x += dx; + y += dy; +} + +void transform::scaleBy(double ds, double cx, double cy) { + scale *= ds; + x = x * ds + cx * (1 - ds); + y = y * ds + cy * (1 - ds); +} diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp new file mode 100644 index 0000000000..b43e92d5ea --- /dev/null +++ b/src/renderer/painter.cpp @@ -0,0 +1,226 @@ +#include <llmr/renderer/painter.hpp> +#include <iostream> +#include <assert.h> +#include <llmr/util/mat4.h> +#include <llmr/platform/platform.hpp> +#include <llmr/map/transform.hpp> +#include <llmr/map/tile.hpp> + +using namespace llmr; + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + +GLfloat triangle_vertices[] = { + 100, 100, + 100, 300, + 150, 150 +}; + +GLfloat fill_vertices[] = { + 0, 0, + 300, 0, + 0, 300, + 300, 300 +}; + + +painter::painter(class platform *platform) + : platform(platform), + transform(NULL), + width(0), + height(0), + currentShader(NULL), + fillShader(NULL) { + +} + +void painter::setTransform(class transform *transform) { + this->transform = transform; +} + + +void painter::setup() { + setupShaders(); + + + assert(fillShader); + + + + glGenBuffers(1, &triangleVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW); + + glGenBuffers(1, &fillVertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, fillVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(fill_vertices), fill_vertices, GL_STATIC_DRAW); + + + // glGenVertexArraysOES(1, &vertexArray); + // glBindVertexArrayOES(vertexArray); + // glBindVertexArrayOES(0); +} + +void painter::setupShaders() { + const GLchar *vertexSource, *fragmentSource; + + vertexSource = platform->shaderSource("fill", "vertex.glsl"); + assert((vertexSource, "Missing fill vertex shader source")); + fragmentSource = platform->shaderSource("fill", "fragment.glsl"); + assert((fragmentSource, "Missing fill fragment shader source")); + + fillShader = new FillShader(vertexSource, fragmentSource); + + vertexSource = platform->shaderSource("line", "vertex.glsl"); + assert((vertexSource, "Missing line vertex shader source")); + fragmentSource = platform->shaderSource("line", "fragment.glsl"); + assert((fragmentSource, "Missing line fragment shader source")); + lineShader = new LineShader(vertexSource, fragmentSource); +} + +void painter::teardown() { + glDeleteBuffers(1, &triangleVertexBuffer); + glDeleteBuffers(1, &fillVertexBuffer); + + // glDeleteVertexArraysOES(1, &vertexArray); + + if (fillShader) { + delete fillShader; + fillShader = NULL; + } + + if (lineShader) { + delete lineShader; + lineShader = NULL; + } + +} + +void painter::resize(GLuint new_width, GLuint new_height) { + if (width == new_width && height == new_height) { + return; + } + + fprintf(stderr, "changing viewport size to %d/%d\n", new_width, new_height); + width = new_width; + height = new_height; +} + +void painter::changeMatrix() { + assert(transform); + + // Initialize projection matrix + float projMatrix[16]; + mat4_ortho(projMatrix, 0, width, height, 0, 1, 10); + + float mvMatrix[16]; + mat4_identity(mvMatrix); + mat4_translate(mvMatrix, mvMatrix, transform->x, transform->y, -1); + mat4_scale(mvMatrix, mvMatrix, transform->scale / 8, transform->scale / 8, 1); + + mat4_multiply(matrix, projMatrix, mvMatrix); +} + +void painter::clear() { + glClearColor(1.0f, 1.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +void painter::render(tile *tile) { + changeMatrix(); + + glDisable(GL_STENCIL_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // fprintf(stderr, "render tile\n"); + switchShader(lineShader, matrix); + glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix); + + // glEnable(GL_BLEND); + + // glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); + // glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0)); + // glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer); + tile->lineVertex.bind(); + glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0)); + glUniform4f(lineShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f); + glLineWidth(1.0f); + glDrawArrays(GL_LINE_STRIP, 0, tile->lineVertex.length()); + + // switchShader(fillShader, matrix); + // glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer); + // glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); + // glUniform4f(fillShader->u_color, 0.0f, 1.0f, 0.0f, 1.0f); + // glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + + + + + // glBindVertexArrayOES(vertexArray); + // switchShader(fillShader, matrix); + // glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix); + + // glEnable(GL_STENCIL_TEST); + + // Draw stencil mask. + // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + // glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); + // glStencilFunc(GL_EQUAL, 0xFF, 0xFF); + // glStencilMask(0xFF); + + // glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer); + // glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); + // glUniform4f(fillShader->u_color, 0.0f, 1.0f, 0.0f, 1.0f); + // glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + + + // // Draw covering fill. + // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + // glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + // glStencilFunc(GL_EQUAL, 0xFF, 0xFF); + + // glBindBuffer(GL_ARRAY_BUFFER, fillVertexBuffer); + // glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); + // glUniform4f(fillShader->u_color, 1.0f, 0.0f, 0.0f, 1.0f); + // glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +void painter::viewport() { + +} + +// Switches to a different shader program. +void painter::switchShader(Shader *shader, float matrix[16]) { + if (currentShader != shader) { + glUseProgram(shader->program); + + // Disable all attributes from the existing shader that aren't used in + // the new shader. Note: attribute indices are *not* program specific! + if (currentShader) { + // const std::vector<GLuint> &enabled = currentShader->attributes; + // const std::vector<GLuint> &required = shader->attributes; + // TODO + + // for (var i = 0; i < enabled.length; i++) { + // if (required.indexOf(enabled[i]) < 0) { + // gl.disableVertexAttribArray(enabled[i]); + // } + // } + + // // Enable all attributes for the new shader. + // for (var j = 0; j < required.length; j++) { + // if (enabled.indexOf(required[j]) < 0) { + // gl.enableVertexAttribArray(required[j]); + // } + // } + } else { + // Enable all attributes for the new shader. + for (GLuint index : shader->attributes) { + glEnableVertexAttribArray(index); + } + } + } + + currentShader = shader; +} diff --git a/src/renderer/shader-fill.cpp b/src/renderer/shader-fill.cpp new file mode 100644 index 0000000000..763c7e2fcf --- /dev/null +++ b/src/renderer/shader-fill.cpp @@ -0,0 +1,14 @@ +#include <llmr/renderer/shader-fill.hpp> + +using namespace llmr; + +FillShader::FillShader(const GLchar *vertSource, const GLchar *fragSource) + : Shader(vertSource, fragSource) { + if (!valid) return; + + a_pos = glGetAttribLocation(program, "a_pos"); + attributes.push_back(a_pos); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_color = glGetUniformLocation(program, "u_color"); +} diff --git a/src/renderer/shader-line.cpp b/src/renderer/shader-line.cpp new file mode 100644 index 0000000000..2f3381bf5b --- /dev/null +++ b/src/renderer/shader-line.cpp @@ -0,0 +1,14 @@ +#include <llmr/renderer/shader-line.hpp> + +using namespace llmr; + +LineShader::LineShader(const GLchar *vertSource, const GLchar *fragSource) + : Shader(vertSource, fragSource) { + if (!valid) return; + + a_pos = glGetAttribLocation(program, "a_pos"); + attributes.push_back(a_pos); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_color = glGetUniformLocation(program, "u_color"); +} diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp new file mode 100644 index 0000000000..d05fb2a65f --- /dev/null +++ b/src/renderer/shader.cpp @@ -0,0 +1,134 @@ + #include <llmr/renderer/shader.hpp> + +#include <cstdlib> + +using namespace llmr; + +Shader::Shader(const GLchar *vertSource, const GLchar *fragSource) + : valid(false), + program(0) { + + GLuint vertShader; + if (!compileShader(&vertShader, GL_VERTEX_SHADER, vertSource)) { + fprintf(stderr, "Vertex shader failed to compile: %s\n", vertSource); + return; + } + + GLuint fragShader; + if (!compileShader(&fragShader, GL_FRAGMENT_SHADER, fragSource)) { + fprintf(stderr, "Fragment shader failed to compile: %s\n", fragSource); + return; + } + + program = glCreateProgram(); + + // Attach shaders + glAttachShader(program, vertShader); + glAttachShader(program, fragShader); + + + { + // Link program + GLint status; + glLinkProgram(program); + +#if defined(DEBUG) + GLint logLength; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar *)malloc(logLength); + glGetProgramInfoLog(program, logLength, &logLength, log); + fprintf(stderr, "Program link log:\n%s", log); + free(log); + } +#endif + + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == 0) { + fprintf(stderr, "Program failed to link\n"); + glDeleteShader(vertShader); + vertShader = 0; + glDeleteShader(fragShader); + fragShader = 0; + glDeleteProgram(program); + program = 0; + return; + } + } + + { + // Validate program + GLint status; + glValidateProgram(program); + +#if defined(DEBUG) + GLint logLength; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar *)malloc(logLength); + glGetProgramInfoLog(program, logLength, &logLength, log); + fprintf(stderr, "Program validate log:\n%s", log); + free(log); + } +#endif + + glGetProgramiv(program, GL_VALIDATE_STATUS, &status); + if (status == 0) { + fprintf(stderr, "Program failed to validate\n"); + glDeleteShader(vertShader); + vertShader = 0; + glDeleteShader(fragShader); + fragShader = 0; + glDeleteProgram(program); + program = 0; + } + + } + + // Remove the compiled shaders; they are now part of the program. + glDetachShader(program, vertShader); + glDeleteShader(vertShader); + glDetachShader(program, fragShader); + glDeleteShader(fragShader); + + + fprintf(stderr, "successfully compiled shader\n"); + valid = true; +} + + +bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) { + GLint status; + + *shader = glCreateShader(type); + glShaderSource(*shader, 1, &source, NULL); + glCompileShader(*shader); + +#if defined(DEBUG) + GLint logLength; + glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar *)malloc(logLength); + glGetShaderInfoLog(*shader, logLength, &logLength, log); + fprintf(stderr, "Shader compile log:\n%s", log); + free(log); + } +#endif + + glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); + if (status == 0) { + glDeleteShader(*shader); + *shader = 0; + return false; + } + + return true; +} + +Shader::~Shader() { + if (program) { + glDeleteProgram(program); + program = 0; + valid = false; + } +} diff --git a/src/shader/fill.fragment.glsl b/src/shader/fill.fragment.glsl new file mode 100644 index 0000000000..8df552c171 --- /dev/null +++ b/src/shader/fill.fragment.glsl @@ -0,0 +1,5 @@ +uniform vec4 u_color; + +void main() { + gl_FragColor = u_color; +} diff --git a/src/shader/fill.vertex.glsl b/src/shader/fill.vertex.glsl new file mode 100644 index 0000000000..866c3cd2f3 --- /dev/null +++ b/src/shader/fill.vertex.glsl @@ -0,0 +1,7 @@ +attribute vec2 a_pos; + +uniform mat4 u_matrix; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); +} diff --git a/src/shader/line.fragment.glsl b/src/shader/line.fragment.glsl new file mode 100644 index 0000000000..8df552c171 --- /dev/null +++ b/src/shader/line.fragment.glsl @@ -0,0 +1,5 @@ +uniform vec4 u_color; + +void main() { + gl_FragColor = u_color; +} diff --git a/src/shader/line.vertex.glsl b/src/shader/line.vertex.glsl new file mode 100644 index 0000000000..547576757e --- /dev/null +++ b/src/shader/line.vertex.glsl @@ -0,0 +1,8 @@ +attribute vec2 a_pos; + +uniform mat4 u_matrix; + +void main() { + float z = step(32767.0, a_pos.x) * 2.0; + gl_Position = u_matrix * vec4(a_pos, z, 1); + } diff --git a/src/util/mat4.c b/src/util/mat4.c new file mode 100644 index 0000000000..e3925ab3a1 --- /dev/null +++ b/src/util/mat4.c @@ -0,0 +1,160 @@ +// This is an incomplete port of http://glmatrix.net/ +// +// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a +// product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#include <llmr/util/mat4.h> + +void mat4_identity(float out[16]) { + out[0] = 1.0f; + out[1] = 0.0f; + out[2] = 0.0f; + out[3] = 0.0f; + out[4] = 0.0f; + out[5] = 1.0f; + out[6] = 0.0f; + out[7] = 0.0f; + out[8] = 0.0f; + out[9] = 0.0f; + out[10] = 1.0f; + out[11] = 0.0f; + out[12] = 0.0f; + out[13] = 0.0f; + out[14] = 0.0f; + out[15] = 1.0f; +} + +void mat4_ortho(float out[16], float left, float right, float bottom, float top, float near, float far) { + float lr = 1.0f / (left - right), + bt = 1.0f / (bottom - top), + nf = 1.0f / (near - far); + out[0] = -2.0f * lr; + out[1] = 0.0f; + out[2] = 0.0f; + out[3] = 0.0f; + out[4] = 0.0f; + out[5] = -2.0f * bt; + out[6] = 0.0f; + out[7] = 0.0f; + out[8] = 0.0f; + out[9] = 0.0f; + out[10] = 2.0f * nf; + out[11] = 0.0f; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1.0f; +} + +void mat4_copy(float out[16], float a[16]) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; +} + +void mat4_translate(float out[16], float a[16], float x, float y, float z) { + float a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + out[0] = a00 + a03 * x; + out[1] = a01 + a03 * y; + out[2] = a02 + a03 * z; + out[3] = a03; + + out[4] = a10 + a13 * x; + out[5] = a11 + a13 * y; + out[6] = a12 + a13 * z; + out[7] = a13; + + out[8] = a20 + a23 * x; + out[9] = a21 + a23 * y; + out[10] = a22 + a23 * z; + out[11] = a23; + out[12] = a30 + a33 * x; + out[13] = a31 + a33 * y; + out[14] = a32 + a33 * z; + out[15] = a33; +} + +void mat4_scale(float out[16], float a[16], float x, float y, float z) { + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; +} + +void mat4_multiply(float out[16], float a[16], float b[16]) { + float a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + // Cache only the current line of the second matrix + float b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; +} |