Skip to content

Instantly share code, notes, and snippets.

@MORTAL2000
Last active November 22, 2015 12:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MORTAL2000/d6dc0f39cdcf3192d9bf to your computer and use it in GitHub Desktop.
Save MORTAL2000/d6dc0f39cdcf3192d9bf to your computer and use it in GitHub Desktop.
#include <SFML/Graphics.hpp>
#include <array>
#include <cmath>
struct P
{
struct Screen
{
float x, y, w, scale;
}screen;
sf::Vector3f world, camera;
};
struct Color
{
virtual ~Color() {}
};
struct Light : public Color
{
sf::Color road = sf::Color(100, 100, 100), grass = sf::Color(0, 100, 0), rumble = sf::Color(100, 0, 0), lane = sf::Color::White;
}light;
struct Dark : public Color
{
sf::Color road = sf::Color(100, 100, 100), grass = sf::Color(0, 150, 0), rumble = sf::Color::White;
}dark;
struct Segment
{
P p1, p2;
int index;
Color* color;
};
class Polygon : public sf::Drawable, public sf::Transformable
{
public:
Polygon(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, sf::Color color)
{
m_vertices.setPrimitiveType(sf::Quads);
m_vertices.resize(4);
m_vertices[0].position = sf::Vector2f(x1, y1);
m_vertices[1].position = sf::Vector2f(x2, y2);
m_vertices[2].position = sf::Vector2f(x3, y3);
m_vertices[3].position = sf::Vector2f(x4, y4);
m_vertices[0].color = m_vertices[1].color = m_vertices[2].color = m_vertices[3].color = color;
}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
target.draw(m_vertices, states);
}
sf::VertexArray m_vertices;
};
void project(P& p, float cameraX, float cameraY, float cameraZ, float cameraDepth, float width, float height, float roadWidth)
{
p.camera.x = p.world.x - cameraX;
p.camera.y = p.world.y - cameraY;
p.camera.z = p.world.z - cameraZ;
p.screen.scale = cameraDepth / p.camera.z;
p.screen.x = std::round((width / 2) + (p.screen.scale * p.camera.x * width / 2));
p.screen.y = std::round((height / 2) - (p.screen.scale * p.camera.y * height / 2));
p.screen.w = std::round((p.screen.scale * roadWidth * width / 2));
}
float rumbleWidth(float projectedRoadWidth, int lanes)
{
return projectedRoadWidth / std::max(6, 2 * lanes);
}
float laneMarkerWidth(float projectedRoadWidth, int lanes)
{
return projectedRoadWidth / std::max(32, 8 * lanes);
}
void renderSegment(sf::RenderTarget& target, float width, int lanes, float x1, float y1, float w1, float x2, float y2, float w2, Color* c)
{
sf::RectangleShape rect(sf::Vector2f(width, y1 - y2));
rect.setPosition(0, y2);
float r1 = rumbleWidth(w1, lanes),
r2 = rumbleWidth(w2, lanes),
l1 = laneMarkerWidth(w1, lanes),
l2 = laneMarkerWidth(w2, lanes),
lanew1, lanew2, lanex1, lanex2, lane;
Light* p = dynamic_cast<Light*>(c);
if (p)
{
rect.setFillColor(p->grass);
Polygon polygon(x1 - w1 - r1, y1, x1 - w1, y1, x2 - w2, y2, x2 - w2 - r2, y2, p->rumble);
Polygon polygon1( x1 + w1 + r1, y1, x1 + w1, y1, x2 + w2, y2, x2 + w2 + r2, y2, p->rumble);
Polygon polygon2( x1 - w1, y1, x1 + w1, y1, x2 + w2, y2, x2 - w2, y2, p->road);
target.draw(rect);
target.draw(polygon);
target.draw(polygon1);
target.draw(polygon2);
}
else
{
Dark* d = dynamic_cast<Dark*>(c);
if (d)
{
rect.setFillColor(d->grass);
Polygon polygon(x1 - w1 - r1, y1, x1 - w1, y1, x2 - w2, y2, x2 - w2 - r2, y2, d->rumble);
Polygon polygon1(x1 + w1 + r1, y1, x1 + w1, y1, x2 + w2, y2, x2 + w2 + r2, y2, d->rumble);
Polygon polygon2(x1 - w1, y1, x1 + w1, y1, x2 + w2, y2, x2 - w2, y2, d->road);
target.draw(rect);
target.draw(polygon);
target.draw(polygon1);
target.draw(polygon2);
}
}
lanew1 = w1 * 2 / lanes;
lanew2 = w2 * 2 / lanes;
lanex1 = x1 - w1 + lanew1;
lanex2 = x2 - w2 + lanew2;
for (lane = 1; lane < lanes; lanex1 += lanew1, lanex2 += lanew2, lane++)
{
Light* p = dynamic_cast<Light*>(c);
if (p)
{
Polygon polygon(lanex1 - l1 / 2, y1, lanex1 + l1 / 2, y1, lanex2 + l2 / 2, y2, lanex2 - l2 / 2, y2, p->lane);
target.draw(polygon);
}
}
}
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "test");
float roadWidth = 2000;
float segmentLength = 200;
float width = 800;
float height = 600;
int drawDistance = 300;
float playerX = 0;
float playerZ = 0;
float cameraHeight = 1000;
int fieldOfView = 100;
float cameraDepth = 1 / std::tan((fieldOfView / 2) * 3.141592653589793238462643383f / 180);
float position = 0;
int rumbleLength = 3;
int lanes = 3;
std::array<Segment, 500> segments;
for (auto i = 0u; i < segments.size(); ++i)
{
Segment s;
s.index = i;
s.p1.world.z = i * segmentLength;
s.p2.world.z = (i + 1) * segmentLength;
if (static_cast<std::size_t>(std::floor(i / rumbleLength)) % 2)
s.color = &light;
else
s.color = &dark;
segments[i] = s;
}
const Segment& baseSegment = segments[static_cast<std::size_t>(std::floor(position / segmentLength)) % segments.size()];
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
for (int n = 0; n < drawDistance; n++)
{
Segment& s= segments[(baseSegment.index + n) % segments.size()];
float camX = playerX * roadWidth;
float camY = cameraHeight;
float camZ = position;
project(s.p1, camX, camY, camZ, cameraDepth, width, height, roadWidth);
project(s.p2, camX, camY, camZ, cameraDepth, width, height, roadWidth);
renderSegment(window, width, lanes, s.p1.screen.x, s.p1.screen.y, s.p1.screen.w, s.p2.screen.x, s.p2.screen.y, s.p2.screen.w, s.color);
}
window.display();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment