Joshua Moerman
11 years ago
20 changed files with 865 additions and 193 deletions
@ -0,0 +1,257 @@ |
|||
//
|
|||
// Car.cpp
|
|||
// OSXGLEssentials
|
|||
//
|
|||
// Created by Joshua Moerman on 10/03/14.
|
|||
//
|
|||
//
|
|||
|
|||
#include "Car.h" |
|||
|
|||
#include <vector> |
|||
#include <random> |
|||
#include <functional> |
|||
#include <iostream> |
|||
|
|||
static float get_rand(float min, float max){ |
|||
return min + (rand() / float(RAND_MAX)) * (max - min); |
|||
} |
|||
|
|||
struct WheelGenome { |
|||
float speed; |
|||
float radius; |
|||
}; |
|||
|
|||
std::ostream & operator<<(std::ostream& out, WheelGenome const & g){ |
|||
return out << "(W speed=" << g.speed << " radius=" << g.radius << ")"; |
|||
} |
|||
|
|||
struct StickGenome { |
|||
float angle; |
|||
float limit; |
|||
float width; |
|||
float length; |
|||
|
|||
std::vector<WheelGenome> wheel; |
|||
std::vector<StickGenome> sticks; |
|||
}; |
|||
|
|||
std::ostream & operator<<(std::ostream& out, StickGenome const & g){ |
|||
out << "(S angle=" << g.angle << " limit=" << g.limit << " width=" << g.width << " length=" << g.length; |
|||
out << " wheel="; |
|||
for(auto&& w : g.wheel) out << w; |
|||
out << " sticks="; |
|||
for(auto&& s : g.sticks) out << s; |
|||
return out << ")"; |
|||
} |
|||
|
|||
struct CarGenome { |
|||
std::vector<StickGenome> sticks; |
|||
}; |
|||
|
|||
std::ostream & operator<<(std::ostream& out, CarGenome const & g){ |
|||
out << "(C sticks="; |
|||
for(auto&& s : g.sticks) out << s; |
|||
return out << ")"; |
|||
} |
|||
|
|||
struct GenomeCreator { |
|||
std::mt19937 generator{37}; |
|||
std::uniform_real_distribution<float> distribution_float{0.0, 1.0}; |
|||
std::uniform_int_distribution<int> distribution_int{0, 4}; |
|||
std::uniform_int_distribution<int> distribution_bool{0, 1}; |
|||
std::function<float()> r = std::bind(distribution_float, generator); |
|||
std::function<int()> s = std::bind(distribution_int, generator); |
|||
std::function<int()> w = std::bind(distribution_bool, generator); |
|||
float min = 0.05f; |
|||
|
|||
WheelGenome wheel(){ |
|||
WheelGenome g; |
|||
g.speed = r() * 20 + 10; |
|||
g.radius = r() + min; |
|||
return g; |
|||
} |
|||
|
|||
StickGenome stick(){ |
|||
StickGenome g; |
|||
g.angle = r() * 2 * M_PI; |
|||
g.limit = r() * 0.05f * M_PI; |
|||
g.width = r() * 0.2f + min; |
|||
g.length = r() * 5 + 1; |
|||
if(w()){ |
|||
g.wheel.push_back(wheel()); |
|||
} else { |
|||
auto sticks = s() - 1; |
|||
while(sticks-- > 0){ |
|||
g.sticks.push_back(stick()); |
|||
} |
|||
} |
|||
return g; |
|||
} |
|||
|
|||
CarGenome car(){ |
|||
CarGenome g; |
|||
auto sticks = s() + 1; |
|||
while(sticks-- > 0){ |
|||
g.sticks.push_back(stick()); |
|||
} |
|||
return g; |
|||
} |
|||
}; |
|||
|
|||
static GenomeCreator creator; |
|||
|
|||
struct CarBuilder { |
|||
b2World & world; |
|||
|
|||
b2CircleShape wheelShape; |
|||
b2FixtureDef wheelFixture; |
|||
b2BodyDef wheelBody; |
|||
|
|||
b2PolygonShape stickShape; |
|||
b2FixtureDef stickFixture; |
|||
b2BodyDef stickBody; |
|||
|
|||
b2PolygonShape boxShape; |
|||
b2FixtureDef boxFixture; |
|||
b2BodyDef boxBody; |
|||
|
|||
b2RevoluteJointDef motor; |
|||
b2RevoluteJointDef stickJoint; |
|||
|
|||
std::vector<b2Body*> created_parts; |
|||
|
|||
CarBuilder(b2World & world_) |
|||
: world(world_) |
|||
{ |
|||
// constants
|
|||
wheelFixture.shape = &wheelShape; |
|||
wheelFixture.density = 1.0f; |
|||
wheelFixture.friction = 1.0f; |
|||
wheelFixture.restitution = 0.1f; |
|||
wheelFixture.filter.groupIndex = -1; |
|||
|
|||
wheelBody.type = b2_dynamicBody; |
|||
|
|||
stickFixture.shape = &stickShape; |
|||
stickFixture.density = 2.0f; |
|||
stickFixture.friction = 0.7f; |
|||
stickFixture.filter.groupIndex = -1; |
|||
|
|||
stickBody.type = b2_dynamicBody; |
|||
|
|||
boxShape.SetAsBox(0.05, 0.05); |
|||
|
|||
boxFixture.shape = &boxShape; |
|||
boxFixture.density = 2000.0f; |
|||
boxFixture.friction = 0.3f; |
|||
boxFixture.filter.groupIndex = -1; |
|||
|
|||
boxBody.type = b2_dynamicBody; |
|||
|
|||
motor.maxMotorTorque = 100; |
|||
motor.enableMotor = true; |
|||
|
|||
//stickJoint.enableLimit = true;
|
|||
stickJoint.enableMotor = true; |
|||
stickJoint.maxMotorTorque = 1000; |
|||
stickJoint.motorSpeed = get_rand(-1, 2); |
|||
} |
|||
|
|||
b2Body * createWheel(WheelGenome const & g){ |
|||
wheelShape.m_radius = g.radius; |
|||
|
|||
auto body = world.CreateBody(&wheelBody); |
|||
body->CreateFixture(&wheelFixture); |
|||
created_parts.push_back(body); |
|||
return body; |
|||
} |
|||
|
|||
b2Body * createStick(StickGenome const & g){ |
|||
stickShape.SetAsBox(0.5 * g.length, 0.5 * g.width); |
|||
|
|||
auto body = world.CreateBody(&stickBody); |
|||
body->CreateFixture(&stickFixture); |
|||
created_parts.push_back(body); |
|||
|
|||
for(auto&& wg : g.wheel){ |
|||
auto wheel = createWheel(wg); |
|||
wheel->SetTransform({g.length, 0.0}, 0); |
|||
|
|||
motor.localAnchorA = {0.5f * g.length, 0}; |
|||
motor.bodyA = body; |
|||
motor.bodyB = wheel; |
|||
motor.motorSpeed = -wg.speed; // CCW
|
|||
|
|||
world.CreateJoint(&motor); |
|||
} |
|||
for(auto&& sg : g.sticks){ |
|||
auto stick = createStick(sg); |
|||
float startAngle = sg.angle; |
|||
stick->SetTransform({g.length, 0.0}, startAngle); |
|||
|
|||
stickJoint.localAnchorA = {0.5f * g.length, 0}; |
|||
stickJoint.localAnchorB = {-0.5f * sg.length, 0}; |
|||
stickJoint.bodyA = body; |
|||
stickJoint.bodyB = stick; |
|||
stickJoint.lowerAngle = startAngle - sg.limit; |
|||
stickJoint.upperAngle = startAngle + sg.limit; |
|||
stickJoint.referenceAngle = startAngle; |
|||
|
|||
world.CreateJoint(&stickJoint); |
|||
} |
|||
|
|||
return body; |
|||
} |
|||
|
|||
b2Body * createCar(CarGenome const & g){ |
|||
created_parts.clear(); |
|||
auto body = world.CreateBody(&boxBody); |
|||
body->CreateFixture(&boxFixture); |
|||
created_parts.push_back(body); |
|||
|
|||
for(auto&& sg : g.sticks){ |
|||
auto stick = createStick(sg); |
|||
float startAngle = sg.angle; |
|||
stick->SetTransform({sg.length, 0.0}, startAngle); |
|||
|
|||
stickJoint.localAnchorA = {0, 0}; |
|||
stickJoint.localAnchorB = {-0.5f * sg.length, 0}; |
|||
stickJoint.bodyA = body; |
|||
stickJoint.bodyB = stick; |
|||
stickJoint.lowerAngle = startAngle - sg.limit; |
|||
stickJoint.upperAngle = startAngle + sg.limit; |
|||
stickJoint.referenceAngle = startAngle; |
|||
|
|||
world.CreateJoint(&stickJoint); |
|||
} |
|||
|
|||
return body; |
|||
} |
|||
}; |
|||
|
|||
Car::Car(b2World & world_) |
|||
: world(world_) |
|||
{ |
|||
auto genome = creator.car(); |
|||
CarBuilder builder(world); |
|||
|
|||
body = builder.createCar(genome); |
|||
parts.swap(builder.created_parts); |
|||
} |
|||
|
|||
Car::Car(Car&& c) |
|||
: world(c.world) |
|||
, body(c.body) |
|||
, parts(std::move(c.parts)) |
|||
{} |
|||
|
|||
Car::~Car(){ |
|||
for(auto&& p : parts){ |
|||
world.DestroyBody(p); |
|||
} |
|||
} |
|||
|
|||
b2Vec2 Car::getPosition() const { |
|||
return body->GetPosition(); |
|||
} |
@ -0,0 +1,26 @@ |
|||
//
|
|||
// Car.h
|
|||
// OSXGLEssentials
|
|||
//
|
|||
// Created by Joshua Moerman on 10/03/14.
|
|||
//
|
|||
//
|
|||
|
|||
#pragma once |
|||
|
|||
#include <Box2D/Box2D.h> |
|||
#include <vector> |
|||
|
|||
struct Car { |
|||
Car(b2World & world); |
|||
Car(Car&& c); |
|||
Car(Car const & c) = delete; |
|||
~Car(); |
|||
|
|||
b2Vec2 getPosition() const; |
|||
|
|||
private: |
|||
b2World & world; |
|||
b2Body * body = nullptr; |
|||
std::vector<b2Body*> parts; |
|||
}; |
@ -0,0 +1,156 @@ |
|||
//
|
|||
// Drawer.cpp
|
|||
// OSXGLEssentials
|
|||
//
|
|||
// Created by Joshua Moerman on 10/03/14.
|
|||
//
|
|||
//
|
|||
|
|||
#include "Drawer.h" |
|||
|
|||
#include <moggle/math/projection.hpp> |
|||
#include <moggle/math/transformation.hpp> |
|||
|
|||
using namespace moggle; |
|||
|
|||
// We need to pass relative addresses to opengl
|
|||
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) |
|||
|
|||
// We may assume this at some point
|
|||
static_assert(sizeof(Vertex) == 6*4, "wrong size"); |
|||
|
|||
// Circles
|
|||
static constexpr size_t circleVertices = 13; |
|||
static const Vertex::Position (&getCircle())[circleVertices]{ |
|||
static Vertex::Position vertices[circleVertices]; |
|||
static bool shouldInit = true; |
|||
if(shouldInit){ |
|||
for(int i = 0; i < circleVertices;++i){ |
|||
auto phi = 2 * i / double(circleVertices-1) * M_PI; |
|||
vertices[i] = {cos(phi), -sin(phi)}; |
|||
} |
|||
shouldInit = false; |
|||
} |
|||
return vertices; |
|||
} |
|||
|
|||
static const float viewSize = 20.0; |
|||
|
|||
#if TARGET_OS_IPHONE |
|||
static const char * file = "/plain-iOS"; |
|||
#else |
|||
static const char * file = "/plain"; |
|||
#endif |
|||
|
|||
// Implementation
|
|||
Drawer::Drawer(std::string const & bundle){ |
|||
gl::enable(GL_BLEND); |
|||
gl::blend_function(GL_SRC_ALPHA, GL_ONE); |
|||
|
|||
gl::clear_color(0.2f, 0.05f, 0.05f, 1.0f); |
|||
|
|||
projection = projection_matrices::orthographic(-viewSize, viewSize, -viewSize, viewSize, -1, 1); |
|||
|
|||
auto vertex = shader::from_file(shader_type::vertex, bundle + file + ".vsh"); |
|||
auto fragment = shader::from_file(shader_type::fragment, bundle + file + ".fsh"); |
|||
|
|||
program.attach(vertex); |
|||
program.attach(fragment); |
|||
|
|||
program.bind_attribute(0, "position"); |
|||
program.bind_attribute(1, "color"); |
|||
|
|||
program.link(); |
|||
|
|||
gl::generate_vertex_arrays(1, &vao); |
|||
gl::bind_vertex_array(vao); |
|||
|
|||
gl::generate_buffers(1, &buf); |
|||
gl::bind_buffer(GL_ARRAY_BUFFER, buf); |
|||
} |
|||
|
|||
void Drawer::draw(){ |
|||
// bug when going to fullscreen
|
|||
// possibly related http://lists.apple.com/archives/mac-opengl/2012/Jul/msg00041.html
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
|||
if(glGetError() != GL_NO_ERROR) return; |
|||
|
|||
matrix4<float> mvp = projection * transformation_matrices::translate(-camera); |
|||
|
|||
program.use(); |
|||
program.uniform<matrix4<float>>("mvp").set(mvp); |
|||
|
|||
if(!segments.empty()){ |
|||
if(verbose) printf("drawing %lu objects and %lu segments\n", sizes.size(), segments.size()); |
|||
|
|||
gl::bind_vertex_array(vao); |
|||
gl::bind_buffer(GL_ARRAY_BUFFER, buf); |
|||
gl::buffer_data(GL_ARRAY_BUFFER, sizeof(Vertex) * segments.size(), &segments[0], GL_STATIC_DRAW); |
|||
|
|||
gl::enable_vertex_attribute_array(0); |
|||
gl::enable_vertex_attribute_array(1); |
|||
gl::vertex_attribute_pointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0)); |
|||
gl::vertex_attribute_pointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(3*4)); |
|||
|
|||
GLuint start = 0; |
|||
for(auto&& s : sizes){ |
|||
gl::draw_arrays(GL_LINE_LOOP, start, s); |
|||
start += s; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void Drawer::clear(){ |
|||
sizes.clear(); |
|||
segments.clear(); |
|||
} |
|||
|
|||
void Drawer::resize(float width, float height){ |
|||
auto aspect = width / height; |
|||
auto hheight = viewSize; |
|||
projection = projection_matrices::orthographic(-hheight * aspect, hheight * aspect, -hheight, hheight, -5, 5); |
|||
} |
|||
|
|||
void Drawer::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color){ |
|||
if(verbose) printf("polygon (not solid)\n %d vertices\n %f %f %f\n", vertexCount, color.r, color.g, color.b); |
|||
for(int i = 0; i < vertexCount; ++i){ |
|||
segments.push_back(Vertex{convert(vertices[i]), convert(color)}); |
|||
} |
|||
sizes.emplace_back(vertexCount); |
|||
} |
|||
|
|||
void Drawer::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color){ |
|||
if(verbose) printf("polygon (solid, deferred)\n"); |
|||
DrawPolygon(vertices, vertexCount, color); |
|||
} |
|||
|
|||
void Drawer::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color){ |
|||
if(verbose) printf("circle (not solid)\n at %f %f (%f)\n %f %f %f\n", center.x, center.y, radius, color.r, color.g, color.b); |
|||
for(auto&& p : getCircle()){ |
|||
segments.push_back(Vertex{convert(center) + radius * p, convert(color)}); |
|||
} |
|||
sizes.emplace_back(circleVertices); |
|||
} |
|||
|
|||
void Drawer::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color){ |
|||
if(verbose) printf("circle (solid, deferred)\n"); |
|||
segments.push_back(Vertex{convert(center) - radius * convert(axis), convert(color)}); |
|||
segments.push_back(Vertex{convert(center) + radius * convert(axis), convert(color)}); |
|||
sizes.push_back(2); |
|||
DrawCircle(center, radius, color); |
|||
} |
|||
|
|||
void Drawer::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color){ |
|||
if(verbose) printf("segment\n %f %f -> %f %f\n %f %f %f\n", p1.x, p1.y, p2.x, p2.y, color.r, color.g, color.b); |
|||
segments.push_back(Vertex{convert(p1), convert(color)}); |
|||
segments.push_back(Vertex{convert(p2), convert(color)}); |
|||
sizes.emplace_back(2); |
|||
} |
|||
|
|||
void Drawer::DrawTransform(const b2Transform& xf){ |
|||
if(verbose) printf("transform\n"); |
|||
} |
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,66 @@ |
|||
//
|
|||
// Drawer.h
|
|||
// OSXGLEssentials
|
|||
//
|
|||
// Created by Joshua Moerman on 10/03/14.
|
|||
//
|
|||
//
|
|||
|
|||
#pragma once |
|||
|
|||
#include <Box2D/Box2D.h> |
|||
|
|||
#include <moggle/core/gl.hpp> |
|||
#include <moggle/math/matrix.hpp> |
|||
#include <moggle/core/shader.hpp> |
|||
|
|||
#include <vector> |
|||
|
|||
struct Vertex { |
|||
using Position = moggle::vector3<float>; |
|||
using Color = moggle::vector3<float>; |
|||
|
|||
Position position; |
|||
Color color; |
|||
}; |
|||
|
|||
inline moggle::vector3<float> convert(b2Vec2 const & p){ return {p.x, p.y, 0.0f}; } |
|||
inline moggle::vector3<float> convert(b2Color const & p){ return {p.r, p.g, p.b}; } |
|||
|
|||
struct Drawer : b2Draw { |
|||
// camera position
|
|||
Vertex::Position camera = {0, 0}; |
|||
|
|||
// print debugging info
|
|||
bool verbose = false; |
|||
|
|||
// bundle needed to load shaders
|
|||
Drawer(std::string const & bundle); |
|||
|
|||
// draw buffer
|
|||
void draw(); |
|||
|
|||
// clear buffer
|
|||
void clear(); |
|||
|
|||
// resize any stuff
|
|||
void resize(float width, float height); |
|||
|
|||
// Box 2D drawing interface
|
|||
// Implementation will fill its buffers
|
|||
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override; |
|||
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override; |
|||
virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) override; |
|||
virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) override; |
|||
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override; |
|||
virtual void DrawTransform(const b2Transform& xf) override; |
|||
|
|||
private: |
|||
moggle::shader_program program; |
|||
moggle::matrix4<float> projection; |
|||
std::vector<Vertex> segments; |
|||
std::vector<GLuint> sizes; |
|||
GLuint vao, buf; |
|||
}; |
|||
|
|||
|
@ -1,22 +0,0 @@ |
|||
#version 100 |
|||
|
|||
varying highp vec2 pos; |
|||
varying highp vec2 start; |
|||
|
|||
void main(){ |
|||
|
|||
highp vec2 z = start; |
|||
|
|||
int i = 0; |
|||
for (i = 0; i < 7; i++) { |
|||
highp vec2 zsq = z*z; |
|||
if(zsq.x + zsq.y > 16.0) break; |
|||
|
|||
highp float t = zsq.x - zsq.y + pos.x; |
|||
z.y = 2.0*z.x*z.y + pos.y; |
|||
z.x = t; |
|||
} |
|||
|
|||
gl_FragColor = vec4(float(i) / 7.0); |
|||
gl_FragColor.bg = 0.5 * sin(z) + 0.5; |
|||
} |
@ -1,18 +0,0 @@ |
|||
#version 100 |
|||
|
|||
uniform float rotation; |
|||
|
|||
attribute vec4 position; |
|||
attribute vec4 color; |
|||
|
|||
varying vec2 pos; |
|||
varying vec2 start; |
|||
|
|||
void main(){ |
|||
pos = position.xy; |
|||
pos.x -= 0.5; |
|||
|
|||
start = sqrt(1.0 + 0.01 * rotation) * 0.3 * sin(vec2(0.1, 0.1337) * rotation); |
|||
|
|||
gl_Position = position; |
|||
} |
@ -1,26 +0,0 @@ |
|||
#version 330 |
|||
|
|||
uniform float rotation; |
|||
|
|||
in vec2 pos; |
|||
in vec2 start; |
|||
|
|||
out vec4 fragColor; |
|||
|
|||
void main(){ |
|||
|
|||
vec2 z = start; |
|||
|
|||
int i = 0; |
|||
for (i = 0; i < 30; i++) { |
|||
vec2 zsq = z*z; |
|||
if(zsq.x + zsq.y > 16.0) break; |
|||
|
|||
float t = zsq.x - zsq.y + pos.x; |
|||
z.y = 2.0*z.x*z.y + pos.y; |
|||
z.x = t; |
|||
} |
|||
|
|||
fragColor = vec4(float(i) / 30.0); |
|||
fragColor.bg = 0.5 * sin(z) + 0.5; |
|||
} |
@ -1,18 +0,0 @@ |
|||
#version 330 |
|||
|
|||
uniform float rotation; |
|||
|
|||
in vec4 position; |
|||
in vec4 color; |
|||
|
|||
out vec2 pos; |
|||
out vec2 start; |
|||
|
|||
void main(){ |
|||
pos = position.xy; |
|||
pos.x -= 0.5; |
|||
|
|||
start = sqrt(1.0 + 0.01 * rotation) * 0.3 * sin(vec2(0.1, 0.1337) * rotation); |
|||
|
|||
gl_Position = position; |
|||
} |
@ -0,0 +1,114 @@ |
|||
//
|
|||
// Path.cpp
|
|||
// OSXGLEssentials
|
|||
//
|
|||
// Created by Joshua Moerman on 10/03/14.
|
|||
//
|
|||
//
|
|||
|
|||
#include "Path.h" |
|||
|
|||
#include <cmath> |
|||
#include <random> |
|||
|
|||
// A default thingy which makes implementing it easier. A subclass only have to
|
|||
// provide new points, which will be connected (So this is not suitable for
|
|||
// e.g. jumps or circles)
|
|||
struct DefaultBuilder : PathBuilder { |
|||
// number of vertices in one chunk
|
|||
static constexpr auto chainLength = 8; |
|||
|
|||
DefaultBuilder(b2World & world_, b2Vec2 startingPoint) |
|||
: world(world_) |
|||
, previous(startingPoint) |
|||
, current(startingPoint) |
|||
{ |
|||
fixture.friction = 2.0; |
|||
} |
|||
|
|||
void buildUpTo(float x) override { |
|||
b2BodyDef groundBodyDef; |
|||
groundBodyDef.position = {0.0f, -10.0f}; |
|||
|
|||
while(current.x < x){ |
|||
auto oldPreviousPoint = previous; |
|||
|
|||
b2Vec2 chainPositions[chainLength]; |
|||
chainPositions[0] = current; |
|||
for(int i = 1; i < chainLength; ++i){ |
|||
chainPositions[i] = next; |
|||
previous = current; |
|||
current = next; |
|||
// we always generate one more, for the b2 ghost vertices
|
|||
generate_next(); |
|||
} |
|||
|
|||
b2ChainShape chain; |
|||
chain.CreateChain(chainPositions, chainLength); |
|||
chain.SetPrevVertex(oldPreviousPoint); |
|||
chain.SetNextVertex(next); |
|||
|
|||
fixture.shape = &chain; |
|||
auto groundBody = world.CreateBody(&groundBodyDef); |
|||
groundBody->CreateFixture(&fixture); |
|||
} |
|||
} |
|||
|
|||
virtual void generate_next() = 0; |
|||
|
|||
protected: |
|||
std::mt19937 generator{0}; |
|||
std::uniform_real_distribution<float> distribution{-1.0, 1.0}; |
|||
|
|||
b2World & world; |
|||
|
|||
b2Vec2 previous; |
|||
b2Vec2 current; |
|||
b2Vec2 next; |
|||
|
|||
b2FixtureDef fixture; |
|||
}; |
|||
|
|||
// Creates random terrain, roughness comes with time
|
|||
struct RandomBuilder : DefaultBuilder { |
|||
RandomBuilder(b2World & world_, b2Vec2 startingPoint) |
|||
: DefaultBuilder(world_, startingPoint) |
|||
{ |
|||
generate_next(); |
|||
} |
|||
|
|||
virtual void generate_next() override { |
|||
auto t = current.x; |
|||
|
|||
float m = std::sqrt(0.001f*t + 1) - 1; |
|||
if(t <= 0) m = 0; |
|||
float slope = m * distribution(generator); |
|||
|
|||
auto rot = b2Rot(slope); |
|||
next = b2Mul(rot, {10, 0}) + current; |
|||
} |
|||
}; |
|||
|
|||
// A flat road
|
|||
struct FlatBuilder : DefaultBuilder { |
|||
FlatBuilder(b2World & world_, b2Vec2 startingPoint) |
|||
: DefaultBuilder(world_, startingPoint) |
|||
{ |
|||
generate_next(); |
|||
} |
|||
|
|||
virtual void generate_next() override { |
|||
b2Vec2 newPiece = {10, 0}; |
|||
next = newPiece + current; |
|||
} |
|||
}; |
|||
|
|||
Path::Path(b2World & world_) |
|||
: world(world_) |
|||
, impl(new RandomBuilder(world, {-20, 0})) |
|||
{} |
|||
|
|||
void Path::buildUpTo(float x){ |
|||
impl->buildUpTo(x); |
|||
} |
|||
|
@ -0,0 +1,27 @@ |
|||
//
|
|||
// Path.h
|
|||
// OSXGLEssentials
|
|||
//
|
|||
// Created by Joshua Moerman on 10/03/14.
|
|||
//
|
|||
//
|
|||
|
|||
#pragma once |
|||
|
|||
#include <Box2D/Box2D.h> |
|||
#include <memory> |
|||
|
|||
struct PathBuilder { |
|||
virtual ~PathBuilder() = default; |
|||
virtual void buildUpTo(float x) = 0; |
|||
}; |
|||
|
|||
// Has a path builder object
|
|||
struct Path { |
|||
Path(b2World & world); |
|||
void buildUpTo(float x); |
|||
|
|||
private: |
|||
b2World & world; |
|||
std::unique_ptr<PathBuilder> impl; |
|||
}; |
@ -0,0 +1,8 @@ |
|||
#version 100 |
|||
|
|||
varying lowp vec4 interpolated_color; |
|||
varying lowp vec4 interpolated_position; |
|||
|
|||
void main(){ |
|||
gl_FragColor = interpolated_color; |
|||
} |
@ -0,0 +1,16 @@ |
|||
#version 100 |
|||
|
|||
uniform mat4 mvp; |
|||
|
|||
attribute vec4 position; |
|||
attribute vec4 color; |
|||
|
|||
varying vec4 interpolated_color; |
|||
varying vec4 interpolated_position; |
|||
|
|||
void main(){ |
|||
interpolated_color = color; |
|||
interpolated_position = position; |
|||
|
|||
gl_Position = mvp * position; |
|||
} |
@ -0,0 +1,10 @@ |
|||
#version 330 |
|||
|
|||
in vec4 interpolated_color; |
|||
in vec4 interpolated_position; |
|||
|
|||
out vec4 fragColor; |
|||
|
|||
void main(){ |
|||
fragColor = interpolated_color; |
|||
} |
@ -0,0 +1,16 @@ |
|||
#version 330 |
|||
|
|||
uniform mat4 mvp; |
|||
|
|||
in vec4 position; |
|||
in vec4 color; |
|||
|
|||
out vec4 interpolated_color; |
|||
out vec4 interpolated_position; |
|||
|
|||
void main(){ |
|||
interpolated_color = color; |
|||
interpolated_position = position; |
|||
|
|||
gl_Position = mvp * position; |
|||
} |
Reference in new issue