glfw version of sample app

This commit is contained in:
Konstantin Käfer
2014-01-07 12:10:14 +01:00
commit 44b43fe5a6
28 changed files with 1376 additions and 0 deletions

41
Makefile Normal file
View File

@@ -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

2
enable-emscripten Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
export PATH="`emsdk active_path`:$PATH"

View File

@@ -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

6
include/llmr/llmr.hpp Normal file
View File

@@ -0,0 +1,6 @@
#ifndef LLMR_MAIN
#define LLMR_MAIN
#include "map/map.hpp"
#endif

34
include/llmr/map/map.hpp Normal file
View File

@@ -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

35
include/llmr/map/tile.hpp Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

41
include/llmr/util/mat4.h Normal file
View File

@@ -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

View File

@@ -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);
}
}

64
src/map/map.cpp Normal file
View File

@@ -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);
}

178
src/map/pbf.hpp Normal file
View File

@@ -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

138
src/map/tile.cpp Normal file
View File

@@ -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);
}
}
}

21
src/map/transform.cpp Normal file
View File

@@ -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);
}

226
src/renderer/painter.cpp Normal file
View File

@@ -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;
}

View File

@@ -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");
}

View File

@@ -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");
}

134
src/renderer/shader.cpp Normal file
View File

@@ -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;
}
}

View File

@@ -0,0 +1,5 @@
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}

View File

@@ -0,0 +1,7 @@
attribute vec2 a_pos;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
}

View File

@@ -0,0 +1,5 @@
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}

View File

@@ -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);
}

160
src/util/mat4.c Normal file
View File

@@ -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;
}