Last active
November 22, 2015 12:42
-
-
Save MORTAL2000/d6dc0f39cdcf3192d9bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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