| @@ -1,5 +1,5 @@ | |||||
| // | // | ||||
| // Lol Engine - Noise tutorial | |||||
| // Lol Engine - Graphing tutorial | |||||
| // | // | ||||
| // Copyright: (c) 2012 Sam Hocevar <sam@hocevar.net> | // Copyright: (c) 2012 Sam Hocevar <sam@hocevar.net> | ||||
| // This program is free software; you can redistribute it and/or | // This program is free software; you can redistribute it and/or | ||||
| @@ -18,6 +18,8 @@ | |||||
| using namespace std; | using namespace std; | ||||
| using namespace lol; | using namespace lol; | ||||
| static int const TEXTURE_WIDTH = 128; | |||||
| extern char const *lolfx_04_texture; | extern char const *lolfx_04_texture; | ||||
| class TextureDemo : public WorldEntity | class TextureDemo : public WorldEntity | ||||
| @@ -34,7 +36,7 @@ public: | |||||
| m_vertices << vec2( 1.0, -1.0); | m_vertices << vec2( 1.0, -1.0); | ||||
| m_vertices << vec2( 1.0, 1.0); | m_vertices << vec2( 1.0, 1.0); | ||||
| m_heightmap = new uint8_t[4 * 512 * 1]; | |||||
| m_heightmap = new uint8_t[4 * TEXTURE_WIDTH * 1]; | |||||
| } | } | ||||
| virtual ~TextureDemo() | virtual ~TextureDemo() | ||||
| @@ -46,45 +48,18 @@ public: | |||||
| { | { | ||||
| WorldEntity::TickGame(seconds); | WorldEntity::TickGame(seconds); | ||||
| /* Generate a new heightmap every 400 frames */ | |||||
| if (m_frames % 400 == 0) | |||||
| { | |||||
| for (int i = 0, height = 64; i < 512; i++) | |||||
| { | |||||
| m_heightmap[4 * i] = height; | |||||
| m_heightmap[4 * i + 1] = 255; /* unused */ | |||||
| m_heightmap[4 * i + 2] = 255; /* unused */ | |||||
| m_heightmap[4 * i + 3] = 255; /* unused */ | |||||
| height += rand() % 17 - 8; | |||||
| height += rand() % 17 - 8; | |||||
| height = std::max(15, std::min(height, 240)); | |||||
| } | |||||
| } | |||||
| /* Generate a new heightmap at the beginning */ | |||||
| if (m_frames == 0) | |||||
| memset(m_heightmap, 255, 4 * TEXTURE_WIDTH); | |||||
| /* Slightly disturb the terrain */ | |||||
| for (int i = 1; i < 511; i++) | |||||
| { | |||||
| int delta = (rand() & 1) ? 1 : -1; | |||||
| if (rand() & 3) | |||||
| continue; | |||||
| uint8_t ¢er = m_heightmap[4 * i]; | |||||
| uint8_t &side1 = m_heightmap[4 * (i - delta)]; | |||||
| uint8_t &side2 = m_heightmap[4 * (i + delta)]; | |||||
| if (center > side1) | |||||
| { | |||||
| center--; | |||||
| side1++; | |||||
| } | |||||
| else if (center > side2) | |||||
| { | |||||
| center--; | |||||
| side2++; | |||||
| } | |||||
| } | |||||
| /* Scroll left */ | |||||
| for (int i = 0; i < TEXTURE_WIDTH - 1; i++) | |||||
| m_heightmap[4 * i] = m_heightmap[4 * i + 4]; | |||||
| int height = m_heightmap[4 * (TEXTURE_WIDTH - 1)]; | |||||
| height = height / 2 + 255 / 4 + rand() % 97 - 48; | |||||
| height = std::max(15, std::min(height, 240)); | |||||
| m_heightmap[4 * (TEXTURE_WIDTH - 1)] = height; | |||||
| /* Update frame counter */ | /* Update frame counter */ | ||||
| ++m_frames; | ++m_frames; | ||||
| @@ -97,7 +72,7 @@ public: | |||||
| /* Initialise GPU data */ | /* Initialise GPU data */ | ||||
| if (!m_ready) | if (!m_ready) | ||||
| { | { | ||||
| m_texture = new Texture(ivec2(512, 1), PixelFormat::A8R8G8B8); | |||||
| m_texture = new Texture(ivec2(TEXTURE_WIDTH, 1), PixelFormat::A8R8G8B8); | |||||
| m_shader = Shader::Create(lolfx_04_texture); | m_shader = Shader::Create(lolfx_04_texture); | ||||
| m_coord = m_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0); | m_coord = m_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0); | ||||
| @@ -25,40 +25,56 @@ float rand(in vec2 p, in float v) | |||||
| return fract(v * sin(dot(p, vec2(1298.9837, 7823.33145)))); | return fract(v * sin(dot(p, vec2(1298.9837, 7823.33145)))); | ||||
| } | } | ||||
| float point2segment(vec2 p1, vec2 p2, vec2 a) | |||||
| { | |||||
| float l2 = dot(p2 - p1, p2 - p1); | |||||
| if (l2 == 0.0) | |||||
| return distance(a, p1); | |||||
| float t = dot(a - p1, p2 - p1) / l2; | |||||
| if (t < 0.0) | |||||
| return distance(a, p1); | |||||
| else if (t > 1.0) | |||||
| return distance(a, p2); | |||||
| vec2 proj = p1 + t * (p2 - p1); | |||||
| return distance(a, proj); | |||||
| } | |||||
| void main(void) | void main(void) | ||||
| { | { | ||||
| float width = 800.0; | |||||
| float height = 600.0; | |||||
| float line_width = 2.0; | |||||
| vec2 t = pass_Position.xy; | vec2 t = pass_Position.xy; | ||||
| vec4 c0 = texture2D(u_Texture, t); | |||||
| float f = rand(pass_Position.xy, 12345.67); | |||||
| if (t.y > c0.x) | |||||
| { | |||||
| /* Sky */ | |||||
| float val = min(t.y * 2.0, 1.0); | |||||
| if (f > 0.999) | |||||
| gl_FragColor = vec4(1.0); | |||||
| else | |||||
| gl_FragColor = vec4(0.4, t.y, val, 1.0); | |||||
| } | |||||
| else if (t.y > c0.x - 0.03) | |||||
| { | |||||
| /* Grass */ | |||||
| if (f > 0.99) | |||||
| gl_FragColor = vec4(0.4, 0.7, 0.3, 1.0); | |||||
| else if (f > 0.9) | |||||
| gl_FragColor = vec4(0.3, 0.6, 0.2, 1.0); | |||||
| else | |||||
| gl_FragColor = vec4(0.2, 0.5, 0.1, 1.0); | |||||
| } | |||||
| else | |||||
| { | |||||
| /* Earth */ | |||||
| if (f > 0.99) | |||||
| gl_FragColor = vec4(0.7, 0.4, 0.3, 1.0); | |||||
| else if (f > 0.9) | |||||
| gl_FragColor = vec4(0.6, 0.3, 0.2, 1.0); | |||||
| else | |||||
| gl_FragColor = vec4(0.5, 0.2, 0.1, 1.0); | |||||
| } | |||||
| vec2 tc1 = floor(t * 128.0) / 128.0; | |||||
| vec2 tc2 = tc1 + vec2(1.0, 1.0) / 128.0; | |||||
| vec2 tc0 = tc1 - vec2(1.0, 1.0) / 128.0; | |||||
| vec2 tc3 = tc2 + vec2(1.0, 1.0) / 128.0; | |||||
| float c0 = texture2D(u_Texture, tc0).x; | |||||
| float c1 = texture2D(u_Texture, tc1).x; | |||||
| float c2 = texture2D(u_Texture, tc2).x; | |||||
| float c3 = texture2D(u_Texture, tc3).x; | |||||
| /* Artificially compress in Y */ | |||||
| c0 *= 0.3; | |||||
| c1 *= 0.3; | |||||
| c2 *= 0.3; | |||||
| c3 *= 0.3; | |||||
| vec2 p0 = vec2(tc0.x * width, c0 * height); | |||||
| vec2 p1 = vec2(tc1.x * width, c1 * height); | |||||
| vec2 p2 = vec2(tc2.x * width, c2 * height); | |||||
| vec2 p3 = vec2(tc3.x * width, c3 * height); | |||||
| vec2 a = vec2(t.x * width, t.y * height); | |||||
| float d0 = point2segment(p0, p1, a); | |||||
| float d1 = point2segment(p1, p2, a); | |||||
| float d2 = point2segment(p2, p3, a); | |||||
| float d = clamp(line_width - min(min(d0, d1), d2), 0.0, 1.0); | |||||
| gl_FragColor = vec4(t.y, d, d * 0.3, 1.0); | |||||
| } | } | ||||