Index: /trunk/tests/render_test/box.frag
===================================================================
--- /trunk/tests/render_test/box.frag	(revision 46)
+++ /trunk/tests/render_test/box.frag	(revision 46)
@@ -0,0 +1,22 @@
+#version 120
+varying vec3 f_coord;
+varying vec3 f_normal;
+varying vec3 f_material;
+varying float f_diffuse_value;
+uniform sampler2D tex;
+uniform vec3 light;
+ 
+void main(void) {
+	float w = f_material.x;
+	bool secondary = f_normal.y < 0.1;
+	float remmod  = floor( w / 16 + 0.5 );
+	float modulus = w - remmod * 16;
+	float dist = distance( light, f_coord );
+	float dmod = clamp(5.0 - dist, 0.0, 1.0) * f_diffuse_value;
+
+	if (secondary)
+		gl_FragColor = texture2D(tex, vec2((fract(f_coord.z - f_coord.x) + modulus ), ( fract(-f_coord.y) + remmod) )  / 16.0);
+	else
+		gl_FragColor = texture2D(tex, vec2((fract(f_coord.z) + modulus ), ( fract(f_coord.x) + remmod) )  / 16.0);
+	gl_FragColor = vec4( gl_FragColor.xyz * (f_diffuse_value + 0.4), 1.0 );
+}
Index: /trunk/tests/render_test/box.vert
===================================================================
--- /trunk/tests/render_test/box.vert	(revision 46)
+++ /trunk/tests/render_test/box.vert	(revision 46)
@@ -0,0 +1,21 @@
+#version 120
+attribute vec3 coords;
+attribute vec3 material;
+varying vec3 f_coord;
+varying vec3 f_normal;
+varying vec3 f_material;
+varying float f_diffuse_value;
+uniform mat4 matrix_mvp;
+uniform vec3 light;
+
+void main(void) {
+	f_normal = vec3(0,0,0);
+	f_normal[int(abs(material.y)-1)] = sign( material.y );
+	vec3 vnormal  = normalize(f_normal);
+	vec3 vlight   = normalize(light - coords);
+	float diffuse = max(dot(vlight, vnormal), 0.0);
+	f_diffuse_value = diffuse;
+	f_coord = coords;
+	f_material = material;
+	gl_Position = matrix_mvp * vec4(coords, 1.0);
+}
Index: /trunk/tests/render_test/char.frag
===================================================================
--- /trunk/tests/render_test/char.frag	(revision 46)
+++ /trunk/tests/render_test/char.frag	(revision 46)
@@ -0,0 +1,14 @@
+#version 120
+varying vec3 f_coord;
+varying vec3 f_material;
+uniform sampler2D tex;
+ 
+void main(void) {
+	float w = f_material.x;
+	float remmod  = floor( w / 16 + 0.5 );
+	float modulus = w - remmod * 16;
+
+	gl_FragColor = texture2D(tex, vec2((fract(f_coord.x) + modulus ), ( fract(f_coord.z) + remmod) )  / 16.0);
+
+//	gl_FragColor = texture2D(tex, vec2((fract(f_coord.z - f_coord.x) + modulus ), ( fract(-f_coord.y) + remmod) )  / 16.0);
+}
Index: /trunk/tests/render_test/char.vert
===================================================================
--- /trunk/tests/render_test/char.vert	(revision 46)
+++ /trunk/tests/render_test/char.vert	(revision 46)
@@ -0,0 +1,13 @@
+#version 120
+attribute vec3 coords;
+attribute vec3 material;
+varying vec3 f_coord;
+varying vec3 f_material;
+uniform mat4 matrix_mvp;
+uniform vec3 pos;
+
+void main(void) {
+	f_coord = coords;
+	f_material = material;
+	gl_Position = matrix_mvp * vec4(coords + pos, 1.0);
+}
Index: /trunk/tests/render_test/premake4.lua
===================================================================
--- /trunk/tests/render_test/premake4.lua	(revision 46)
+++ /trunk/tests/render_test/premake4.lua	(revision 46)
@@ -0,0 +1,24 @@
+solution "nv_render_test"
+	configurations { "debug", "release" }
+
+  	language "C++"
+	flags { "ExtraWarnings", "NoPCH" }
+
+	configuration "debug"
+		defines { "DEBUG" }
+		flags { "Symbols", "StaticRuntime" }
+		objdir (_ACTION.."/debug")
+
+	configuration "release"
+		defines { "NDEBUG" }
+		flags { "Optimize", "StaticRuntime" }
+		objdir (_ACTION.."/release")
+
+	dofile("render_test.lua")
+	dofile("../../nv.lua")
+
+if _ACTION == "clean" then
+	for action in premake.action.each() do
+		os.rmdir(action.trigger)
+	end
+end
Index: /trunk/tests/render_test/render_test.lua
===================================================================
--- /trunk/tests/render_test/render_test.lua	(revision 46)
+++ /trunk/tests/render_test/render_test.lua	(revision 46)
@@ -0,0 +1,9 @@
+-- RL project definition
+project "rl"
+	kind "ConsoleApp"
+	files { "rl.cc" }
+	includedirs { "../../" }
+	targetname "rl"
+	defines { "_SCL_SECURE_NO_WARNINGS" }
+	links { "nv" }
+ 
Index: /trunk/tests/render_test/rl.cc
===================================================================
--- /trunk/tests/render_test/rl.cc	(revision 46)
+++ /trunk/tests/render_test/rl.cc	(revision 46)
@@ -0,0 +1,322 @@
+#include <nv/lib/sdl12.hh>
+#include <nv/lib/sdl_image.hh>
+#include <nv/interface/vertex_buffer.hh>
+#include <nv/gl/gl_device.hh>
+#include <nv/gl/image.hh>
+#include <nv/interface/context.hh>
+#include <nv/interface/window.hh>
+#include <nv/interface/program.hh>
+#include <nv/interface/texture2d.hh>
+#include <nv/logging.hh>
+#include <nv/logger.hh>
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <nv/string.hh>
+#include <nv/types.hh>
+
+typedef glm::detail::tvec3<char> byte3;
+
+const nv::uint16 size_x  = 16;
+const nv::uint16 size_y  = 16;
+const nv::uint16 size_xy = size_x * size_y;
+
+nv::uint8 height[size_xy] = 
+{
+	4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  6,  6,  6,  6,  6,  6,  6,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  6,  6,  6,  6,  6,  6,  6,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  6,  6,  6,  6,  6,  6,  6,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  5,  5,  5,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  5,  5,  5,  4,  2,  2,  2,  2,  2,  2,  4,  4,  4,
+	4,  4,  4,  5,  5,  5,  4,  2,  2,  2,  2,  2,  2,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  2,  2,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  2,  2,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  2,  2,  2,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  4,  4,  4,  4,  4,  4,
+	4,  4,  4,  4,  4,  4,  4,  2,  2,  2,  4,  4,  4,  4,  4,  4,
+};
+
+nv::uint8 map[size_xy] = 
+{
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+	3,  2,  2,  2,  2,  2,  2,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  2,  2,  2,  2,  2,  2,
+	2,  2,  2,  2,  2,  2,  2,  6,  6,  6,  2,  2,  2,  2,  2,  2,
+};
+
+struct world;
+struct being;
+
+class application
+{
+public:
+	application();
+	bool initialize();
+	bool init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, int count, void* vertex, void* material );
+	bool run();
+	~application();
+protected:
+	nv::device* m_device;
+	nv::window* m_window;
+	nv::texture2d* m_texture;
+	nv::clear_state m_clear_state;
+	nv::render_state m_render_state;
+
+	nv::program* m_char_program;
+	nv::program* m_box_program;
+	nv::vertex_array* m_char_va;
+	nv::vertex_array* m_box_va;
+	unsigned int m_count;
+};
+
+application* g_application;
+
+application::application()
+{
+	m_device = new nv::gl_device();
+	m_window = m_device->create_window( 800, 600 );
+	
+	nv::load_sdl_image_library();
+	SDL_Surface* texture = IMG_Load( "spritesheet.png" );
+	nv::image sprites( glm::ivec2( texture->w, texture->h ), 4, (nv::uint8*)texture->pixels );
+	nv::texture2d_sampler sampler( nv::texture2d_sampler::NEAREST, nv::texture2d_sampler::REPEAT );
+	m_texture = m_device->create_texture2d( sprites.get_size(), nv::texture2d::RGBA, nv::texture2d::UBYTE, sampler, (void*)sprites.get_data() );
+
+	m_clear_state.buffers = nv::clear_state::COLOR_AND_DEPTH_BUFFER;
+	m_render_state.depth_test.enabled = true;
+	m_render_state.blending.enabled   = true;
+	m_render_state.blending.src_rgb_factor   = nv::blending::SRC_ALPHA;
+	m_render_state.blending.dst_rgb_factor   = nv::blending::ONE_MINUS_SRC_ALPHA;
+	m_render_state.blending.src_alpha_factor = nv::blending::SRC_ALPHA;
+	m_render_state.blending.dst_alpha_factor = nv::blending::ONE_MINUS_SRC_ALPHA;
+}
+
+bool application::initialize()
+{
+	{ // CHARACTER
+		byte3 vertex[6];
+		byte3 material[6];
+		int m = 16;	int x = 0; int y = 0; int h = 0;
+		vertex[0] = byte3( x,   h, y );   material[0] = byte3( m, 1, 0 );
+		vertex[1] = byte3( x,   h, y+1 ); material[1] = byte3( m, 1, 0 );
+		vertex[2] = byte3( x+1, h, y+1 ); material[2] = byte3( m, 1, 0 );
+		vertex[3] = byte3( x+1, h, y+1 ); material[3] = byte3( m, 1, 0 );
+		vertex[4] = byte3( x+1, h, y );   material[4] = byte3( m, 1, 0 );
+		vertex[5] = byte3( x,   h, y );   material[5] = byte3( m, 1, 0 );
+
+		if (!init_program( "char", m_char_program, m_char_va, 6, vertex, material ) ) return false;
+	}
+
+	{ // WORLD
+		byte3 vertex[size_x * size_y * 256];
+		byte3 material[size_x * size_y * 256];
+		m_count = 0;
+		int mcount = 0;
+		for (int i = 0; i < size_x * size_y; ++i )
+		{
+			int x = i % size_x;
+			int y = i / size_x;
+
+			vertex[m_count++] = byte3( x,   height[i], y   ); material[mcount++] = byte3( map[i], 2, 0 );
+			vertex[m_count++] = byte3( x,   height[i], y+1 ); material[mcount++] = byte3( map[i], 2, 0 );
+			vertex[m_count++] = byte3( x+1, height[i], y+1 ); material[mcount++] = byte3( map[i], 2, 0 );
+
+			vertex[m_count++] = byte3( x+1, height[i], y+1 ); material[mcount++] = byte3( map[i], 2, 0 );
+			vertex[m_count++] = byte3( x+1, height[i], y );   material[mcount++] = byte3( map[i], 2, 0 );
+			vertex[m_count++] = byte3( x,   height[i], y );   material[mcount++] = byte3( map[i], 2, 0 );
+
+			if (i > 0 && height[i-1] != height[i])
+			{
+				short dir   = height[i-1] > height[i] ? -1 : 1;
+				nv::uint8 m = 1;
+				for ( int h = height[i-1]; h != height[i]; h = h + dir )
+				{
+					vertex[m_count++] = byte3( x, h,     y );   material[mcount++] = byte3( m, -dir, 0 );
+					vertex[m_count++] = byte3( x, h,     y+1 ); material[mcount++] = byte3( m, -dir, 0 );
+					vertex[m_count++] = byte3( x, h+dir, y+1 ); material[mcount++] = byte3( m, -dir, 0 );
+
+					vertex[m_count++] = byte3( x, h+dir, y+1 ); material[mcount++] = byte3( m, -dir, 0 );
+					vertex[m_count++] = byte3( x, h+dir, y );   material[mcount++] = byte3( m, -dir, 0 );
+					vertex[m_count++] = byte3( x, h,     y );   material[mcount++] = byte3( m, -dir, 0 );
+				}
+			}
+
+			if (i >= size_x && height[i-size_x] != height[i])
+			{
+				short dir   = height[i-size_x] > height[i] ? -1 : 1;
+				nv::uint8 m = 1;
+				for ( int h = height[i-size_x]; h != height[i]; h = h + dir )
+				{
+					vertex[m_count++] = byte3( x,   h,     y ); material[mcount++] = byte3( m, -3*dir, 0 );
+					vertex[m_count++] = byte3( x,   h+dir, y ); material[mcount++] = byte3( m, -3*dir, 0 );
+					vertex[m_count++] = byte3( x+1, h+dir, y ); material[mcount++] = byte3( m, -3*dir, 0 );
+
+					vertex[m_count++] = byte3( x+1, h+dir, y ); material[mcount++] = byte3( m, -3*dir, 0 );
+					vertex[m_count++] = byte3( x+1, h,     y ); material[mcount++] = byte3( m, -3*dir, 0 );
+					vertex[m_count++] = byte3( x,   h,     y ); material[mcount++] = byte3( m, -3*dir, 0 );
+				}
+			}
+
+		}
+
+		if (!init_program( "box",  m_box_program, m_box_va, m_count, vertex, material ) ) return false;
+	}
+
+	return true;
+}
+
+bool application::init_program( const std::string& name, nv::program*& p, nv::vertex_array*& va, int count, void* vertex, void* material )
+{
+	p  = m_device->create_program( nv::slurp( name+".vert" ), nv::slurp( name+".frag" ) );
+	va = m_device->create_vertex_array();
+
+	nv::attribute* a;
+	a = p->get_attribute( "coords" ); if (a == nullptr) return false;
+	nv::vertex_buffer* vbcoords   = m_device->create_vertex_buffer( nv::STATIC_DRAW, count*sizeof(byte3), vertex );
+	va->add_vertex_buffer( a->get_location(), vbcoords, nv::BYTE, 3 );
+
+	a = p->get_attribute( "material" ); if (a == nullptr) return false;
+	nv::vertex_buffer* vbmaterial = m_device->create_vertex_buffer( nv::STATIC_DRAW, count*sizeof(byte3), material );
+	va->add_vertex_buffer( a->get_location(), vbmaterial, nv::BYTE, 3 );
+
+	return true;
+}
+
+bool application::run()
+{
+	int keypress = 0;
+
+	glm::vec3 move( 0, 0, 0 );
+
+	while(!keypress) 
+	{
+		m_window->get_context()->clear( m_clear_state );
+
+		//		float d = -4.0f;
+		float angle = (float)(SDL_GetTicks() / 1000.0 * 45);  // 45° per second
+		glm::vec3 axis_y(0.0, 1.0, 0.0);
+		glm::mat4 anim  = glm::rotate(glm::mat4(1.0f), angle, axis_y);
+
+		//			glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0, 0.0, d));
+		//			glm::mat4 view  = glm::lookAt(glm::vec3(0.0, 2.0, 0.0), glm::vec3(0.0, 0.0, d), glm::vec3(0.0, 1.0, 0.0));
+
+		glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(-8.5, 0.0, -8.0));
+		glm::mat4 view  = glm::lookAt(glm::vec3(0.0, 20.0, 5.0) + move, glm::vec3(0.0, 4.0, 0.0) + move, glm::vec3(0.0, 1.0, 0.0));
+		glm::mat4 projection = glm::perspective(25.0f, 1.0f*800.0f/600.0f, 0.1f, 100.0f);
+		//projection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 0.1f, 100.0f);
+		glm::mat4 mv         = view * model;
+		glm::mat3 N          = glm::transpose(glm::inverse(glm::mat3(mv)));
+
+		m_texture->bind( 0 );
+		m_box_program->set_uniform( "matrix_mvp", projection * mv );
+		m_box_program->set_uniform( "light", glm::vec3(8.5, 4.5, 6.5) + move );
+		m_box_program->set_uniform( "tex", 0 );
+		m_window->get_context()->draw( nv::TRIANGLES, m_render_state, m_box_program, m_box_va, m_count );
+
+		m_char_program->set_uniform( "matrix_mvp", projection * mv );
+		m_char_program->set_uniform( "pos", move + glm::vec3( 8, 4.1, 6 ) );
+		m_char_program->set_uniform( "tex", 0 );
+		m_window->get_context()->draw( nv::TRIANGLES, m_render_state, m_char_program, m_char_va, 6 );
+
+		SDL_GL_SwapBuffers();
+		SDL_Event event;
+		while(SDL_PollEvent(&event)) 
+		{      
+			switch (event.type) 
+			{
+			case SDL_QUIT:
+				keypress = 1;
+				break;
+			case SDL_KEYDOWN:
+				switch (event.key.keysym.sym) 
+				{
+				case SDLK_ESCAPE: keypress = 1; break;
+				case SDLK_LEFT: move.x = move.x - 1.0f; break;
+				case SDLK_RIGHT: move.x = move.x + 1.0f; break;
+				case SDLK_UP: move.z = move.z - 1.0f; break;
+				case SDLK_DOWN: move.z = move.z + 1.0f; break;
+				}
+				break;
+			}
+		}
+	}
+	return true;
+}
+
+application::~application()
+{
+	delete m_char_program;
+	delete m_box_program;
+	delete m_char_va;
+	delete m_box_va;
+	delete m_texture;
+	delete m_window;
+	delete m_device;
+}
+
+/*
+class test_resource : public nv::resource
+{
+public:
+	typedef std::shared_ptr< test_resource > ptr;
+public:
+	test_resource() {}
+	virtual bool load() { return true; };
+	virtual bool unload() { return true; };
+};
+*/
+//	nv::resource_manager::pointer()->register_resource_type<test_resource>("test");
+
+
+
+int main(int, char* [])
+{
+	nv::logger log(nv::LOG_TRACE);
+	log.add_sink( new nv::log_file_sink("log.txt"), nv::LOG_TRACE );
+	log.add_sink( new nv::log_console_sink(), nv::LOG_TRACE );
+	
+	NV_LOG( nv::LOG_NOTICE, "Logging started" );
+
+// 	nv::load_freetype_library();
+// 
+// 	size_t depth = 3;
+// 	nv::texture_atlas tex( glm::ivec2( 512, 512 ), depth );
+// 	for ( nv::uint16 i = 10; i < 32; i += 2 )
+// 	{
+// 		nv::texture_font font( &tex, "aero.ttf", i );
+// 		font.load_glyphs( "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" );
+// 	}
+
+	g_application = new application();
+
+//	SDL_Surface* s = SDL_CreateRGBSurfaceFrom( (void*)tex.get_data(), 512, 512, depth * 8, 512 * depth,0,0,0,0);
+//	SDL_SaveBMP_RW( s, SDL_RWFromFile("test.bmp", "wb"), 1);
+
+	if ( g_application->initialize() )
+	{
+		g_application->run();
+	}
+	delete g_application;
+
+	NV_LOG( nv::LOG_NOTICE, "Logging stopped" );
+
+	return 0;
+}
+
