diff --git a/.gitignore b/.gitignore index 09978a6e..5dc772ad 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ tools/make-font tutorial/01_triangle tutorial/02_cube tutorial/03_noise +tutorial/04_texture tutorial/05_easymesh tutorial/08_fbo tutorial/11_fractal diff --git a/src/gpu/shader.h b/src/gpu/shader.h index 43a08e8b..8b98dd9c 100644 --- a/src/gpu/shader.h +++ b/src/gpu/shader.h @@ -50,6 +50,7 @@ struct ShaderTexture { friend class Shader; friend class FrameBuffer; + friend class Texture; public: inline ShaderTexture() : m_flags(0) {} diff --git a/src/gpu/texture.cpp b/src/gpu/texture.cpp index 1290c738..7088e28d 100644 --- a/src/gpu/texture.cpp +++ b/src/gpu/texture.cpp @@ -45,11 +45,11 @@ class TextureData PixelFormat m_format; #if defined USE_D3D9 - IDirect3DTexture9 *m_tex; + IDirect3DTexture9 *m_texture; #elif defined _XBOX - D3DTexture *m_tex; + D3DTexture *m_texture; #else - GLuint m_texid; + GLuint m_texture; GLint m_internal_format; GLenum m_gl_format, m_gl_type; #endif @@ -101,7 +101,7 @@ Texture::Texture(ivec2 size, PixelFormat format) g_d3ddevice->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1, d3d_usage, d3d_format, - D3DPOOL_DEFAULT, &m_data->m_tex, NULL); + D3DPOOL_DEFAULT, &m_data->m_texture, NULL); #else static struct { @@ -143,8 +143,8 @@ Texture::Texture(ivec2 size, PixelFormat format) m_data->m_gl_format = GET_CLAMPED(gl_formats, format).format; m_data->m_gl_type = GET_CLAMPED(gl_formats, format).type; - glGenTextures(1, &m_data->m_texid); - glBindTexture(GL_TEXTURE_2D, m_data->m_texid); + glGenTextures(1, &m_data->m_texture); + glBindTexture(GL_TEXTURE_2D, m_data->m_texture); # if defined __CELLOS_LV2__ /* We need this hint because by default the storage type is @@ -157,15 +157,26 @@ Texture::Texture(ivec2 size, PixelFormat format) #endif } +ShaderTexture Texture::GetTexture() const +{ + ShaderTexture ret; +#if defined USE_D3D9 || defined _XBOX + ret.m_flags = (uint64_t)(uintptr_t)m_data->m_texture; +#else + ret.m_flags = m_data->m_texture; +#endif + return ret; +} + void Texture::Bind() { #if defined _XBOX || defined USE_D3D9 - g_d3ddevice->SetTexture(0, m_data->m_tex); + g_d3ddevice->SetTexture(0, m_data->m_texture); #else # if !defined HAVE_GLES_2X glEnable(GL_TEXTURE_2D); # endif - glBindTexture(GL_TEXTURE_2D, m_data->m_texid); + glBindTexture(GL_TEXTURE_2D, m_data->m_texture); #endif } @@ -174,14 +185,14 @@ void Texture::SetData(void *data) #if defined _XBOX || defined USE_D3D9 D3DLOCKED_RECT rect; # if defined USE_D3D9 - m_data->m_tex->LockRect(0, &rect, NULL, D3DLOCK_DISCARD); + m_data->m_texture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD); # else - m_data->m_tex->LockRect(0, &rect, NULL, 0); + m_data->m_texture->LockRect(0, &rect, NULL, 0); # endif memcpy(rect.pBits, data, rect.Pitch * m_data->m_size.y); - m_data->m_tex->UnlockRect(0); + m_data->m_texture->UnlockRect(0); #else glTexImage2D(GL_TEXTURE_2D, 0, m_data->m_internal_format, @@ -194,7 +205,7 @@ void Texture::SetSubData(ivec2 origin, ivec2 size, void *data) { #if defined _XBOX || defined USE_D3D9 D3DLOCKED_RECT rect; - m_data->m_tex->LockRect(0, &rect, NULL, 0); + m_data->m_texture->LockRect(0, &rect, NULL, 0); for (int j = 0; j < size.y; j++) { @@ -204,7 +215,7 @@ void Texture::SetSubData(ivec2 origin, ivec2 size, void *data) memcpy(dst, src, size.x * 4); } - m_data->m_tex->UnlockRect(0); + m_data->m_texture->UnlockRect(0); #else glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x, origin.y, size.x, size.y, @@ -215,9 +226,9 @@ void Texture::SetSubData(ivec2 origin, ivec2 size, void *data) Texture::~Texture() { #if defined USE_D3D9 || defined _XBOX - m_data->m_tex->Release(); + m_data->m_texture->Release(); #else - glDeleteTextures(1, &m_data->m_texid); + glDeleteTextures(1, &m_data->m_texture); #endif delete m_data; diff --git a/src/gpu/texture.h b/src/gpu/texture.h index 214edea9..7ebdd9e7 100644 --- a/src/gpu/texture.h +++ b/src/gpu/texture.h @@ -46,6 +46,8 @@ public: void SetData(void *data); void SetSubData(ivec2 origin, ivec2 size, void *data); + ShaderTexture GetTexture() const; + private: class TextureData *m_data; }; diff --git a/tutorial/04_texture.cpp b/tutorial/04_texture.cpp new file mode 100644 index 00000000..10a5d713 --- /dev/null +++ b/tutorial/04_texture.cpp @@ -0,0 +1,156 @@ +// +// Lol Engine - Noise tutorial +// +// Copyright: (c) 2012 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/projects/COPYING.WTFPL for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "loldebug.h" + +using namespace std; +using namespace lol; + +extern char const *lolfx_04_texture; + +class TextureDemo : public WorldEntity +{ +public: + TextureDemo() : + m_frames(0), + m_ready(false) + { + 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_vertices << vec2( 1.0, -1.0); + m_vertices << vec2( 1.0, 1.0); + + m_heightmap = new uint8_t[4 * 512 * 1]; + } + + virtual ~TextureDemo() + { + delete m_heightmap; + } + + virtual void TickGame(float 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)); + } + } + + /* 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++; + } + } + + /* Update frame counter */ + ++m_frames; + } + + virtual void TickDraw(float seconds) + { + WorldEntity::TickDraw(seconds); + + /* Initialise GPU data */ + if (!m_ready) + { + m_texture = new Texture(ivec2(512, 1), PixelFormat::A8R8G8B8); + + m_shader = Shader::Create(lolfx_04_texture); + m_coord = m_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0); + + m_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position)); + + m_vbo = new VertexBuffer(m_vertices.Bytes()); + void *vertices = m_vbo->Lock(0, 0); + memcpy(vertices, &m_vertices[0], m_vertices.Bytes()); + m_vbo->Unlock(); + + m_ready = true; + + /* FIXME: this object never cleans up */ + } + + /* Send new heightmap to GPU */ + m_texture->SetData(m_heightmap); + + m_shader->Bind(); + m_shader->SetUniform(m_texture_uni, m_texture->GetTexture(), 0); + m_vdecl->SetStream(m_vbo, m_coord); + m_vdecl->Bind(); + m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6); + m_vdecl->Unbind(); + } + +private: + Array m_vertices; + Texture *m_texture; + Shader *m_shader; + ShaderAttrib m_coord; + ShaderUniform m_texture_uni; + VertexDeclaration *m_vdecl; + VertexBuffer *m_vbo; + uint8_t *m_heightmap; + int m_frames; + bool m_ready; +}; + +int main(int argc, char **argv) +{ + Application app("Tutorial 4: Texture", ivec2(640, 480), 60.0f); + +#if defined _MSC_VER && !defined _XBOX + _chdir("../.."); +#elif defined _WIN32 && !defined _XBOX + _chdir("../.."); +#endif + + new TextureDemo(); + + app.Run(); + return EXIT_SUCCESS; +} + diff --git a/tutorial/04_texture.lolfx b/tutorial/04_texture.lolfx new file mode 100644 index 00000000..25930ac5 --- /dev/null +++ b/tutorial/04_texture.lolfx @@ -0,0 +1,64 @@ +[vert.glsl] + +#version 120 + +attribute vec2 in_Position; + +varying vec4 pass_Position; + +void main(void) +{ + pass_Position = vec4(0.5 * in_Position + 0.5, 0.0, 1.0); + gl_Position = vec4(in_Position, 0.0, 1.0); +} + +[frag.glsl] + +#version 120 + +uniform sampler2D u_Texture; + +varying vec4 pass_Position; + +float rand(in vec2 p, in float v) +{ + return fract(v * sin(dot(p, vec2(1298.9837, 7823.33145)))); +} + +void main(void) +{ + 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.02) + { + /* 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); + } +} + diff --git a/tutorial/04_texture.vcxproj b/tutorial/04_texture.vcxproj new file mode 100644 index 00000000..231d76fb --- /dev/null +++ b/tutorial/04_texture.vcxproj @@ -0,0 +1,68 @@ + + + + + Debug + PS3 + + + Debug + Win32 + + + Debug + x64 + + + Debug + Xbox 360 + + + Release + PS3 + + + Release + Win32 + + + Release + x64 + + + Release + Xbox 360 + + + + + + + + + + + {9e62f2fe-3408-4eae-8238-fd84238ceeda} + + + + {834852db-edb6-4fd0-bcf9-45cd01126962} + Application + Win32Proj + + + + + + + + + + + + + + + + + diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am index 2e1629d8..1c3d3a71 100644 --- a/tutorial/Makefile.am +++ b/tutorial/Makefile.am @@ -3,7 +3,8 @@ include $(top_srcdir)/build/autotools/common.am AM_CPPFLAGS = -I$(top_srcdir)/src -noinst_PROGRAMS = 01_triangle 02_cube 03_noise 05_easymesh 08_fbo 11_fractal +noinst_PROGRAMS = 01_triangle 02_cube 03_noise 04_texture 05_easymesh \ + 08_fbo 11_fractal 01_triangle_SOURCES = 01_triangle.cpp 01_triangle.lolfx 01_triangle_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ @@ -20,6 +21,11 @@ noinst_PROGRAMS = 01_triangle 02_cube 03_noise 05_easymesh 08_fbo 11_fractal 03_noise_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@ 03_noise_DEPENDENCIES = $(top_builddir)/src/liblol.a +04_texture_SOURCES = 04_texture.cpp 04_texture.lolfx +04_texture_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ +04_texture_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@ +04_texture_DEPENDENCIES = $(top_builddir)/src/liblol.a + 05_easymesh_SOURCES = 05_easymesh.cpp 05_easymesh_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ 05_easymesh_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@