Fancy skybox :D

This commit is contained in:
Themaister 2013-07-21 20:02:50 +02:00
parent 944673d9b8
commit 518e326582
21 changed files with 280 additions and 182 deletions

View File

@ -43,13 +43,13 @@ else
CFLAGS += -O3
endif
CXXFLAGS += -std=gnu++11 -Wall -pedantic $(fpic) -DHAVE_ZIP_DEFLATE
CXXFLAGS += -std=gnu++11 -Wall -pedantic $(fpic) -DHAVE_ZIP_DEFLATE $(shell pkg-config assimp --cflags)
CFLAGS += -std=gnu99 -Wall -pedantic $(fpic) -DHAVE_ZIP_DEFLATE
SOURCES := $(wildcard *.cpp) $(wildcard */*.cpp)
CSOURCES := $(wildcard *.c) $(wildcard */*.c)
OBJECTS := $(SOURCES:.cpp=.o) $(CSOURCES:.c=.o)
LIBS += $(GL_LIB)
LIBS += $(GL_LIB) $(shell pkg-config assimp --libs)
all: $(TARGET)

View File

@ -3,83 +3,61 @@
#include <gl/shader.hpp>
#include <gl/vertex_array.hpp>
#include <gl/texture.hpp>
#include <gl/mesh.hpp>
#include <memory>
#include <cstdint>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
using namespace glm;
using namespace GL;
class HeightGrid
class Scene
{
public:
void init(unsigned size)
void init(const std::string& path)
{
init_vertices(size);
init_indices(size);
vector<VertexArray::Array> arrays = {
{ Shader::VertexLocation, 2, GL_SHORT, GL_FALSE, 0, 0 },
};
array.setup(arrays, &vertex, &elems);
auto meshes = load_scene(path);
for (auto& mesh : meshes)
{
auto drawable = Util::make_unique<Drawable>();
drawable->vertex.init(GL_ARRAY_BUFFER, mesh.vbo, Buffer::None);
drawable->elems.init(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo, Buffer::None);
drawable->array.setup(mesh.arrays, &drawable->vertex,
&drawable->elems);
drawable->indices = mesh.ibo.size();
drawables.push_back(move(drawable));
}
mat4 model = translate(mat4(1.0), vec3(0, -5, -10));
uniform_offset.init(GL_UNIFORM_BUFFER, sizeof(model),
Buffer::None, value_ptr(model), Shader::VertexSlot1);
}
void render()
{
array.bind();
glDrawElements(GL_TRIANGLE_STRIP, elements, GL_UNSIGNED_SHORT, nullptr);
array.unbind();
uniform_offset.bind();
for (auto& drawable : drawables)
{
drawable->array.bind();
glDrawElements(GL_TRIANGLES, drawable->indices,
GL_UNSIGNED_INT, nullptr);
drawable->array.unbind();
}
uniform_offset.unbind();
}
private:
VertexArray array;
Buffer vertex;
Buffer elems;
unsigned elements = 0;
void init_vertices(unsigned size)
struct Drawable
{
vector<GLshort> vertices;
vertices.reserve(2 * size * size);
for (unsigned y = 0; y < size; y++)
{
for (unsigned x = 0; x < size; x++)
{
vertices.push_back(x);
vertices.push_back(int(size) - 1 - y);
}
}
vertex.init(GL_ARRAY_BUFFER, 2 * size * size * sizeof(GLshort), Buffer::None, vertices.data());
}
void init_indices(unsigned size)
{
elements = (size - 1) * (2 * size + 1);
vector<GLushort> indices;
indices.reserve(elements);
int pos = 0;
for (unsigned y = 0; y < size - 1; y++)
{
int dir_odd = -int(size) + ((y & 1) ? -1 : 1);
int dir_even = size;
for (unsigned x = 0; x < 2 * size - 1; x++)
{
indices.push_back(pos);
pos += (x & 1) ? dir_odd : dir_even;
}
indices.push_back(pos);
indices.push_back(pos);
}
elems.init(GL_ELEMENT_ARRAY_BUFFER, elements * sizeof(GLushort), Buffer::None, indices.data());
}
VertexArray array;
Buffer vertex;
Buffer elems;
size_t indices;
};
Buffer uniform_offset;
vector<unique_ptr<Drawable>> drawables;
};
class HeightmapApp : public LibretroGLApplication
@ -139,12 +117,24 @@ class HeightmapApp : public LibretroGLApplication
global.camera_pos = vec4(player_pos.x, player_pos.y, player_pos.z, 0.0);
global_fragment.camera_pos = global.camera_pos;
global_fragment.light_pos = vec4(100.0, 100.0, 100.0, 1.0);
global_fragment.light_color = vec4(1.0);
global_fragment.light_ambient = vec4(0.25);
GlobalTransforms *buf;
if (global_buffer.map(buf))
{
*buf = global;
global_buffer.unmap();
}
GlobalFragmentData *frag_buf;
if (global_fragment_buffer.map(frag_buf))
{
*frag_buf = global_fragment;
global_fragment_buffer.unmap();
}
}
void viewport_changed(const Resolution& res) override
@ -169,7 +159,7 @@ class HeightmapApp : public LibretroGLApplication
vec3 right_walk_dir = vec3(rotate_y_right * vec4(0, 0, -1, 1));
vec3 mod_speed = buttons.r ? vec3(120.0f) : vec3(60.0f);
vec3 mod_speed = buttons.r ? vec3(240.0f) : vec3(120.0f);
vec3 velocity = player_look_dir * vec3(analog.y * -0.25f) +
right_walk_dir * vec3(analog.x * 0.25f);
@ -177,30 +167,6 @@ class HeightmapApp : public LibretroGLApplication
update_global_data();
}
void bind_all()
{
global_buffer.bind();
global_frag_buffer.bind();
shader.use();
tex.bind(0);
sampler.bind(0);
skybox.tex.bind(1);
skybox.sampler.bind(1);
}
void unbind_all()
{
global_buffer.unbind();
global_frag_buffer.unbind();
shader.unbind();
tex.unbind(0);
sampler.unbind(0);
skybox.tex.unbind(1);
skybox.sampler.unbind(1);
}
void run(float delta, const InputState& input, GLuint) override
{
auto analog = input.analog;
@ -214,12 +180,6 @@ class HeightmapApp : public LibretroGLApplication
analog.ry = 0.0f;
update_input(delta, analog, input.pressed);
if (input.triggered.a)
{
foo_define ^= 1;
shader.set_global_define("FOO", foo_define);
}
glViewport(0, 0, width, height);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@ -228,13 +188,26 @@ class HeightmapApp : public LibretroGLApplication
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
bind_all();
grid.render();
global_buffer.bind();
global_fragment_buffer.bind();
skybox.tex.bind(0);
skybox.sampler.bind(0);
shader.use();
scene.render();
shader.unbind();
skybox.shader.use();
skybox.arrays.bind();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
skybox.arrays.unbind();
unbind_all();
skybox.shader.unbind();
global_buffer.unbind();
global_fragment_buffer.unbind();
skybox.tex.unbind(0);
skybox.sampler.unbind(0);
}
void get_context_version(unsigned& major, unsigned& minor) const override
@ -245,10 +218,9 @@ class HeightmapApp : public LibretroGLApplication
void load() override
{
global_buffer.init(GL_UNIFORM_BUFFER, sizeof(global), Buffer::WriteOnly);
vec4 global_color(0.8f, 0.6f, 0.2f, 1.0f);
global_frag_buffer.init(GL_UNIFORM_BUFFER, sizeof(global_color), Buffer::None, value_ptr(global_color), 1);
global_buffer.init(GL_UNIFORM_BUFFER, sizeof(global), Buffer::WriteOnly, nullptr, Shader::GlobalVertexData);
global_fragment_buffer.init(GL_UNIFORM_BUFFER,
sizeof(global_fragment), Buffer::WriteOnly, nullptr, Shader::GlobalFragmentData);
player_pos = vec3(0.0f);
player_look_dir = vec3(0, 0, -1);
@ -256,19 +228,14 @@ class HeightmapApp : public LibretroGLApplication
player_view_deg_y = 0.0f;
shader.init(path("test.vs"), path("test.fs"));
Shader::reserve_global_define("FOO", 1);
grid.init(128);
tex.load_texture_2d({Texture::Texture2D, { path("app/test.png") }, true });
sampler.init(Sampler::TrilinearClamp);
scene.init(path("test.obj"));
skybox.tex.load_texture_2d({Texture::TextureCube, {
path("app/skybox_autum_forest_right.png"),
path("app/skybox_pine_forest_left.png"),
path("app/skybox_autum_forest_top.png"),
path("app/skybox_autum_forest_bottom.png"),
path("app/skybox_pine_forest_front.png"),
path("app/skybox_autum_forest_back.png"),
path("app/xpos.png"),
path("app/xneg.png"),
path("app/ypos.png"),
path("app/yneg.png"),
path("app/zpos.png"),
path("app/zneg.png"),
}, true});
skybox.sampler.init(Sampler::TrilinearClamp);
skybox.shader.init(path("skybox.vs"), path("skybox.fs"));
@ -299,16 +266,21 @@ class HeightmapApp : public LibretroGLApplication
vec4 camera_pos;
};
struct GlobalFragmentData
{
vec4 camera_pos;
vec4 light_pos;
vec4 light_color;
vec4 light_ambient;
};
GlobalTransforms global;
GlobalFragmentData global_fragment;
Buffer global_buffer;
Buffer global_frag_buffer;
Buffer global_fragment_buffer;
Shader shader;
unsigned foo_define = 0;
HeightGrid grid;
Texture tex;
Sampler sampler;
Scene scene;
struct
{
@ -322,6 +294,6 @@ class HeightmapApp : public LibretroGLApplication
unique_ptr<LibretroGLApplication> libretro_gl_application_create()
{
return unique_ptr<LibretroGLApplication>(new HeightmapApp);
return Util::make_unique<HeightmapApp>();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

BIN
app/xneg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

BIN
app/xpos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

BIN
app/yneg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/ypos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
app/zneg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

BIN
app/zpos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

View File

@ -4,6 +4,7 @@
#include "global.hpp"
#include <stdexcept>
#include <cstring>
#include <type_traits>
namespace GL
{
@ -18,6 +19,13 @@ namespace GL
};
void init(GLenum target, GLsizei size, GLuint flags, const void *initial_data = nullptr, GLuint index = 0);
template<typename T>
typename std::enable_if<sizeof(typename T::value_type) != 0, void>::type init(GLenum target, const T& t, GLuint flags, GLuint index = 0)
{
init(target, t.size() * sizeof(typename T::value_type), flags, t.data(), index);
}
void reset() override;
void destroyed() override;

View File

@ -48,12 +48,17 @@ namespace GL
void ContextManager::register_listener(ContextListener *listener)
{
ListenerState state{};
state.listener = listener;
state.id = context_id++;
#ifdef GL_DEBUG
cerr << "Registering listener: " <<
static_cast<void*>(listener) << endl;
#endif
auto state = make_shared<ListenerState>();
state->listener = listener;
state->id = context_id++;
if (alive)
state.reset_chain();
listeners.push_back(std::move(state));
state->reset_chain();
listeners.push_back(move(state));
}
void ContextManager::register_dependency(ContextListener *master, ContextListener *slave)
@ -61,15 +66,28 @@ namespace GL
if (!master || !slave)
return;
auto& itr_master = find_or_throw(listeners, *master);
auto& itr_slave = find_or_throw(listeners, *slave);
itr_master.dependencies.push_back(&itr_slave);
itr_slave.dependers.push_back(&itr_master);
#ifdef GL_DEBUG
cerr << "Registering dependency: " <<
static_cast<void*>(master) << " < " << static_cast<void*>(slave) << endl;
#endif
auto pred_master = [master](const shared_ptr<ListenerState>& state) {
return state->listener == master;
};
auto pred_slave = [slave](const shared_ptr<ListenerState>& state) {
return state->listener == slave;
};
auto& itr_master = find_if_or_throw(listeners, pred_master);
auto& itr_slave = find_if_or_throw(listeners, pred_slave);
itr_master->dependencies.push_back(itr_slave);
itr_slave->dependers.push_back(itr_master);
if (alive)
{
itr_master.reset_chain();
itr_slave.reset_chain();
itr_master->reset_chain();
itr_slave->reset_chain();
}
}
@ -78,24 +96,59 @@ namespace GL
if (!master_ptr || !slave_ptr)
return;
auto& itr_master = find_or_throw(listeners, *master_ptr);
auto& itr_slave = find_or_throw(listeners, *slave_ptr);
erase_all(itr_master.dependencies, &itr_slave);
erase_all(itr_slave.dependers, &itr_master);
#ifdef GL_DEBUG
cerr << "Unregistering dependency: " <<
static_cast<void*>(master_ptr) << " < " << static_cast<void*>(slave_ptr) << endl;
#endif
auto pred_master = [master_ptr](const shared_ptr<ListenerState>& state) {
return state->listener == master_ptr;
};
auto pred_slave = [slave_ptr](const shared_ptr<ListenerState>& state) {
return state->listener == slave_ptr;
};
auto& itr_master = find_if_or_throw(listeners, pred_master);
auto& itr_slave = find_if_or_throw(listeners, pred_slave);
auto pred_master_erase = [&itr_master](const weak_ptr<ListenerState>& state) {
return state.lock() == itr_master;
};
auto pred_slave_erase = [&itr_slave](const weak_ptr<ListenerState>& state) {
return state.lock() == itr_slave;
};
erase_if_all(itr_master->dependencies, pred_slave_erase);
erase_if_all(itr_slave->dependers, pred_master_erase);
}
void ContextManager::unregister_listener(const ContextListener *listener)
{
auto& itr = find_or_throw(listeners, *listener);
for (auto& parent_listener : itr.dependers)
erase_all(parent_listener->dependencies, &itr);
for (auto& child_listener : itr.dependencies)
erase_all(child_listener->dependers, &itr);
#ifdef GL_DEBUG
cerr << "Unregistering listener: " <<
static_cast<const void*>(listener) << endl;
#endif
if (itr.signaled)
auto pred = [listener](const weak_ptr<ListenerState>& state) {
return shared_ptr<ListenerState>(state)->listener == listener;
};
auto& itr = find_if_or_throw(listeners, pred);
auto itr_pred = [&itr](const weak_ptr<ListenerState>& state) {
return state.lock() == itr;
};
for (auto& parent_listener : itr->dependers)
erase_if_all(parent_listener.lock()->dependencies, itr_pred);
for (auto& child_listener : itr->dependencies)
erase_if_all(child_listener.lock()->dependers, itr_pred);
if (itr->signaled)
{
itr.signaled = false;
itr.listener->destroyed();
itr->signaled = false;
itr->listener->destroyed();
}
erase_all(listeners, itr);
@ -105,13 +158,13 @@ namespace GL
{
alive = true;
for (auto& state : listeners)
state.reset_chain();
state->reset_chain();
}
void ContextManager::notify_destroyed()
{
for (auto& state : listeners)
state.destroy_chain();
state->destroy_chain();
alive = false;
}
@ -121,7 +174,12 @@ namespace GL
{
signaled = true;
for (auto state : dependencies)
state->reset_chain();
state.lock()->reset_chain();
#ifdef GL_DEBUG
cerr << "Resetting: " <<
static_cast<void*>(listener) << endl;
#endif
listener->reset();
}
}
@ -132,7 +190,12 @@ namespace GL
{
signaled = false;
for (auto state : dependers)
state->destroy_chain();
state.lock()->destroy_chain();
#ifdef GL_DEBUG
cerr << "Destroying: " <<
static_cast<void*>(listener) << endl;
#endif
listener->destroyed();
}
}

View File

@ -10,6 +10,10 @@
#include "util.hpp"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
namespace GL
{
class LibretroGLApplication
@ -101,10 +105,10 @@ namespace GL
struct ListenerState
{
ContextListener *listener;
ContextListener *listener = nullptr;
bool signaled = false;
std::vector<ListenerState*> dependencies;
std::vector<ListenerState*> dependers;
std::vector<std::weak_ptr<ListenerState>> dependencies;
std::vector<std::weak_ptr<ListenerState>> dependers;
uint64_t id = 0;
void reset_chain();
@ -116,7 +120,7 @@ namespace GL
bool operator!=(const ContextListener& other) const { return listener != &other; }
};
std::vector<ListenerState> listeners;
std::vector<std::shared_ptr<ListenerState>> listeners;
bool alive = false;
uint64_t context_id = 0;

View File

@ -1,10 +1,26 @@
uniform GlobalFragmentData
{
vec4 camera_pos;
vec4 light_pos;
vec4 light_color;
vec4 light_ambient;
};
uniform samplerCube uSampler1;
uniform samplerCube uSampler0;
in vec3 vDirection;
out vec4 FragColor;
float saturate(float a)
{
return clamp(a, 0.0, 1.0);
}
void main()
{
FragColor = texture(uSampler1, normalize(vDirection));
vec3 dir = normalize(vDirection);
vec4 col = texture(uSampler0, dir);
vec3 to_light = light_pos.xyz - camera_pos.xyz;
col += pow(saturate(dot(dir, normalize(to_light))), 200.0 * length(to_light));
FragColor = col;
}

54
test.fs
View File

@ -1,40 +1,46 @@
uniform GlobalVertexData
uniform GlobalFragmentData
{
mat4 vp;
mat4 view;
mat4 view_nt;
mat4 proj;
mat4 inv_vp;
mat4 inv_view;
mat4 inv_view_nt;
mat4 inv_proj;
vec4 camera_pos;
vec4 light_pos;
vec4 light_color;
vec4 light_ambient;
};
in vec2 vTex;
in vec3 vWorldPos;
in vec3 vNormal;
uniform sampler2D uSampler0;
uniform samplerCube uSampler1;
uniform samplerCube uSampler0;
out vec4 FragColor;
float saturate(float a)
{
return clamp(a, 0.0, 1.0);
}
void main()
{
vec3 to_plane = normalize(vWorldPos - camera_pos.xyz);
vec3 normal = vec3(0.02 * sin(vWorldPos.x * 0.15), 0.01 * cos(vWorldPos.y * 0.29), 1.0);
normal = normalize(normal);
vec3 reflect_dir = reflect(to_plane, normal);
vec4 col_reflect = texture(uSampler1, reflect_dir);
vec3 vEye = normalize(camera_pos.xyz - vWorldPos);
vec3 vLight = normalize(light_pos.xyz - vWorldPos);
vec3 normal = normalize(vNormal);
float fres = 1.0;
vec3 refract_dir = refract(to_plane, normal, 1.4);
vec4 col_refract = vec4(0.0);
if (refract_dir != vec3(0.0))
float ndotl = saturate(dot(vLight, normal));
float spec = 0.0;
if (ndotl > 0.0)
{
col_refract = texture(uSampler1, refract_dir);
fres = pow(1.0 - dot(refract_dir, -normal), 5.0);
vec3 half_vec = normalize(vEye + vLight);
spec = pow(saturate(dot(half_vec, normal)), 50.0);
}
FragColor = mix(col_refract, col_reflect, fres);
vec3 refract_normal = refract(-vEye, normal, 1.4);
vec3 reflect_normal = reflect(-vEye, normal);
float incidence = 0.0;
incidence = dot(refract_normal, -normal);
vec4 refracted = texture(uSampler0, refract_normal);
vec4 reflected = texture(uSampler0, reflect_normal);
vec4 col = light_ambient + light_color * spec;
FragColor = mix(reflected, refracted, incidence) + col * vec4(1.1, 0.8, 0.7, 1.0);
}

14
test.vs
View File

@ -11,18 +11,22 @@ uniform GlobalVertexData
vec4 camera_pos;
};
in vec2 aVertex;
in vec2 aTexCoord;
uniform VertexSlot1
{
mat4 model;
};
in vec3 aVertex;
in vec3 aNormal;
out vec2 vTex;
out vec3 vWorldPos;
out vec3 vNormal;
void main()
{
vec4 world = vec4(aVertex.x - 64.0, aVertex.y - 64.0, -10.0, 1.0);
vec4 world = model * vec4(aVertex, 1.0);
gl_Position = vp * world;
vTex = vec2(1.0, -1.0) * aVertex / 128.0;
vWorldPos = world.xyz;
vNormal = mat3(model) * aNormal;
}

View File

@ -12,6 +12,16 @@
#include <algorithm>
#include <cstdarg>
#include <cstring>
#include <memory>
namespace Util
{
template<typename T, typename... P>
inline std::unique_ptr<T> make_unique(P&&... p)
{
return std::unique_ptr<T>(new T(std::forward<P>(p)...));
}
}
namespace Template
{
@ -24,10 +34,25 @@ namespace Template
return *itr;
}
template<typename T, typename P>
inline auto find_if_or_throw(T& t, const P& pred) -> decltype(*std::begin(t))
{
auto itr = std::find_if(std::begin(t), std::end(t), pred);
if (itr == std::end(t))
throw std::runtime_error("Couldn't find element in iterator.");
return *itr;
}
template<typename T, typename P>
inline void erase_if_all(T& t, const P& p)
{
t.erase(std::remove_if(std::begin(t), std::end(t), p), std::end(t));
}
template<typename T, typename U>
inline void erase_all(T& t, const U& u)
{
t.erase(std::remove_if(std::begin(t), std::end(t), [&u](const U& other) { return other == u; }), std::end(t));
erase_if_all(t, [&u](const U& other) { return other == u; });
}
}