diff --git a/src/binding/src/script_core.cpp b/src/binding/src/script_core.cpp index d1a2c63..e301337 100644 --- a/src/binding/src/script_core.cpp +++ b/src/binding/src/script_core.cpp @@ -231,6 +231,8 @@ void register_core_function(sol::state& lua,sol::table& ns) auto image_type = ns.new_usertype("image" ,sol::call_constructor,sol::constructors() ,"create",&image::create + ,"release",&image::release + ,"is_valid",sol::readonly_property(&image::is_valid) ,"size",sol::readonly_property(&image::size) ,"generate_noise",&image::generate_noise ,"change_count",sol::property(&image::change_count,&image::set_change_count) diff --git a/src/binding/src/script_system.cpp b/src/binding/src/script_system.cpp index 0a26a62..19a43af 100644 --- a/src/binding/src/script_system.cpp +++ b/src/binding/src/script_system.cpp @@ -9,6 +9,8 @@ #include "pw/core/debug.hpp" +#include + namespace pw { void register_system_function(sol::state&, sol::table &ns) @@ -45,8 +47,8 @@ void register_system_function(sol::state&, sol::table &ns) ,"new",sol::no_constructor ,"get",&path::get ,"separator",sol::readonly_property(&path::separator) - ,"resource_paths",sol::readonly_property(&path::resource_paths) ,"executable_path",sol::readonly_property(&path::executable_path) + ,"resource_paths",sol::readonly_property([](const path& p){return sol::as_table(p.resource_paths());}) ); } diff --git a/src/core/include/pw/core/image.hpp b/src/core/include/pw/core/image.hpp index 29664d2..875bbe3 100644 --- a/src/core/include/pw/core/image.hpp +++ b/src/core/include/pw/core/image.hpp @@ -68,6 +68,8 @@ public: ::pw::size size() const; void generate_noise(); + bool is_valid() const; + protected: ::pw::size _size; diff --git a/src/core/include/pw/core/quaternion.hpp b/src/core/include/pw/core/quaternion.hpp index b645bf2..8ba1d34 100644 --- a/src/core/include/pw/core/quaternion.hpp +++ b/src/core/include/pw/core/quaternion.hpp @@ -110,11 +110,11 @@ struct quaternion_ : vector4_ { using std::sqrt; auto wtemp = sqrt(T(1) + m(0,0) + m(1,1) + m(2,2)) / T(2); auto w4 = T(4.0) * wtemp; - return quaternion_( + return quaternion_({ (m(2,1) - m(1,2)) / w4, (m(0,2) - m(2,0)) / w4, (m(1,0) - m(0,1)) / w4, - wtemp); + wtemp}); } static auto normalized_lerp(const quaternion_ &a,const quaternion_ &b,const T &t) { diff --git a/src/core/src/image.cpp b/src/core/src/image.cpp index b0706aa..c35536d 100644 --- a/src/core/src/image.cpp +++ b/src/core/src/image.cpp @@ -49,10 +49,16 @@ void image::generate_noise() void image::release(bool release_memory) { _data.clear(); + _size = pw::size(); if (release_memory) _data.shrink_to_fit(); } +bool image::is_valid() const +{ + return !_data.empty() && (0 != _size.area()); +} + uint32_t image::bytes_per_pixel(image::pixel_layout t) { switch (t) { diff --git a/src/runtime/CMakeLists.txt b/src/runtime/CMakeLists.txt index 44026b9..4aea251 100644 --- a/src/runtime/CMakeLists.txt +++ b/src/runtime/CMakeLists.txt @@ -4,6 +4,7 @@ set(scripts_demo ${CMAKE_SOURCE_DIR}/src/scripts/demos/simple_001.lua ${CMAKE_SOURCE_DIR}/src/scripts/demos/simple_002.lua ${CMAKE_SOURCE_DIR}/src/scripts/demos/simple_003.lua + ${CMAKE_SOURCE_DIR}/src/scripts/demos/simple_004.lua ) set(scripts_test diff --git a/src/runtime/pixwerx.cpp b/src/runtime/pixwerx.cpp index 32f8521..1a4fd1d 100644 --- a/src/runtime/pixwerx.cpp +++ b/src/runtime/pixwerx.cpp @@ -50,17 +50,22 @@ int main(int argc,const char** argv) { return -1; } - std::ifstream input; // run a file if (args["file"]) { + std::ifstream input; + input.open(args["file"].as(),std::ifstream::in); if (!input.is_open()) { + std::cerr << "cannot open '" << args["file"].as() << "'" << std::endl; + + return -1; } + // read as string std::ostringstream sout; std::copy(std::istreambuf_iterator(input), std::istreambuf_iterator(), diff --git a/src/scene/include/pw/scene/entity.hpp b/src/scene/include/pw/scene/entity.hpp index 3e5d8b1..49764b3 100644 --- a/src/scene/include/pw/scene/entity.hpp +++ b/src/scene/include/pw/scene/entity.hpp @@ -99,7 +99,9 @@ public: bool valid() const { return _registry && _registry->valid(_entity); } - + /** + * @brief conversion operator + */ operator bool() const { return _registry && _entity != entt::null; } diff --git a/src/scripts/demos/simple_003.lua b/src/scripts/demos/simple_003.lua index 873d3ed..6efe57c 100644 --- a/src/scripts/demos/simple_003.lua +++ b/src/scripts/demos/simple_003.lua @@ -229,7 +229,6 @@ while w:update() do -- just to quickly modify speed local move_step = 0.05 - -- camera if pw.input.get().input_string == 'w' then cam_pos.z = cam_pos.z - move_step @@ -245,8 +244,6 @@ while w:update() do cam_pos.y = cam_pos.y - move_step end - - -- just some debugging print(cam_pos.x,cam_pos.y,cam_pos.z) diff --git a/src/scripts/demos/simple_004.lua b/src/scripts/demos/simple_004.lua new file mode 100644 index 0000000..6ae3955 --- /dev/null +++ b/src/scripts/demos/simple_004.lua @@ -0,0 +1,266 @@ +-- +-- pixwerx - bare rendering engine binding usage +-- + +-- we need everything +pw.script:load_all() + +print("executable path:",pw.path.get().executable_path) +print("resource paths:",pw.path.get().resource_paths) + +for k,v in pairs(pw.path.get().resource_paths) do + print(k,v) +end + + +local img = pw.image() +if not img:create(pw.size(512,512),pw.pixel_layout.rgb8) then + print("image couldnt be created") +else + + -- generate some noise + img:generate_noise() + + -- for debugging + pw.image_io.get():write("test.png",img,0) + +end + +-- create a window (remember windows are invisible by default) +local w = pw.window.new() + +-- set title +w.title = "pixwerx - bare rendering" + +-- set size +w.size = pw.size(640,480) + +-- move window +w.position = pw.point(100,100) + +-- create a new geometry +local g = pw.geometry() + +g.primitive_topology = pw.primitive_topology_type.triangle_list -- meh + +-- create texture coordinates +g.texture_coordinates = { { + { 0.0, 0.0 }, + { 1.0, 1.0 }, + { 1.0, 0.0 }, + { 0.0, 1.0 } +} } + +z = -5.0 +s = 1 + +-- indices +g.indices = { + 0, 1, 2, -- triangle #1 + 2, 3, 0 -- triangle #2 + } + +print(g.indices,#g.indices) + + +-- geometry can only build with indexed facesets +g.vertices = { + { -s,-s, z }, + { s,-s, z }, + { s, s, z }, + { -s, s, z } +} + +-- 0 --- 3 +-- | \ | +-- 1 --- 2 + +g:compute_normals() + + +local mm = pw.matrix4x4.identity +local mv = pw.matrix4x4() +local mp = pw.matrix4x4() + +local s = pw.shader() + +s:set_source(pw.shader_type.vertex,[[ +#version 400 + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec3 normals; +layout (location = 2) in vec2 texture_coords; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + + +out vec2 tex_c; + +void main() { + tex_c = texture_coords; + gl_Position = projection * view * model * vec4(vertices, 1.0); +} +]]) + +s:set_source(pw.shader_type.fragment,[[ +#version 400 + +uniform vec4 color = vec4(1.0, 0.0, 0.0, 1.0); +uniform sampler2D tex_color; + +in vec2 tex_c; + +out vec4 frag_color; + +void main() { + frag_color = texture(tex_color,tex_c) * color; +} +]]) + +-- check if the shader can be compiled and linked +if not s:build() then + print("Error!") +end + +-- the renderer for a geometry +local renderer = pw.renderer() + +-- camera position +local cam_pos = pw.vector3(0,0,0) + +-- model position +local model_pos = pw.vector3(0,0,0) + + +-- create new context (should move into a scene later) +local ctx = pw.context() + +-- create a texture +local tx = pw.texture() + +-- create texture from an image +tx:create(img) + +-- unload it - would only make sense for static textures +-- img:release() + +-- set function to +w.on_resize = function(self) + -- use client_size to resize the viewport + ctx:set_viewport(pw.rectangle(pw.point(0,0),self.client_size:cast_to_float())) +end + + +-- setup a lua callback function as callback +w.on_update = function(self) + + -- we set the clear color + ctx.clearcolor = pw.color(pw.mathf.ping_pong(pw.time.now,1.0),0,1,1) + ctx:clear() + + -- set view matrix with look_at - view matrix is moving the world - hence inverse! + mv = pw.matrixtransform.look_at(cam_pos,cam_pos + pw.vector3.forward,pw.vector3.up).inverse + + -- compute aspect ratio from canvas size + aspect_ratio = self.client_size.width / self.client_size.height + + -- create a view frustum for a perspective projection + mp = pw.matrixtransform.perspective_projection(math.rad(45),aspect_ratio,0.2,100) + + -- + -- this code is raw rendering mode + -- + + -- just some toying around + local color_red = pw.mathf.ping_pong(pw.time.now,1.0) + local color_green = pw.mathf.ping_pong(pw.time.now + 1,1.0) + local color_blue = 1.0 - pw.mathf.ping_pong(pw.time.now,1.0) + -- color is currently still a vector4 + local cl = pw.vector4( color_red, color_green, color_blue, 1.0 ) + + + img:generate_noise() + tx:update(img) + + -- bind the shader + s:use() + + -- update the uniforms, currently the slow path + s:set_uniform_mat4("model",mm) + s:set_uniform_mat4("view",mv) + s:set_uniform_mat4("projection",mp) + s:set_uniform_vec4("color",cl) + + -- specific to our shader + s:set_uniform_int("tex_color",0) + + -- bind the texture + tx:bind() + + -- update renderer from geometry + renderer:update(g) + + -- draw + renderer:draw() + + local e = ctx:get_error() + if e ~= 0 then + print("OpenGL error",e) + end + +end + +-- before entering the update loop make the window visible +w.visible = true + +-- some fluffyness +local speed = 0 + +-- main update loop +while w:update() do + + -- only check if get a new input + if pw.input.get().has_input then + + + -- somehow works + if pw.input.get().input_string == 'f' then + w.fullscreen = not w.fullscreen + end + + -- keycode for quit + if pw.input.get().input_string == 'q' then + break + end + + -- just to quickly modify speed + local move_step = 0.05 + + -- camera + if pw.input.get().input_string == 'w' then + cam_pos.z = cam_pos.z - move_step + elseif pw.input.get().input_string == 's' then + cam_pos.z = cam_pos.z + move_step + elseif pw.input.get().input_string == 'a' then + cam_pos.x = cam_pos.x - move_step + elseif pw.input.get().input_string == 'd' then + cam_pos.x = cam_pos.x + move_step + elseif pw.input.get().input_string == 'z' then + cam_pos.y = cam_pos.y + move_step + elseif pw.input.get().input_string == 'x' then + cam_pos.y = cam_pos.y - move_step + end + + -- just some debugging + print(cam_pos.x,cam_pos.y,cam_pos.z) + + end + + -- just to check + if pw.input:get().mouse_button == 1 then + print(pw.input:get().mouse_position.x,pw.input:get().mouse_position.y,w.client_size.width,w.client_size.height) + end + +end diff --git a/src/system/CMakeLists.txt b/src/system/CMakeLists.txt index 8e10e8f..ccd7bc9 100644 --- a/src/system/CMakeLists.txt +++ b/src/system/CMakeLists.txt @@ -4,6 +4,7 @@ set(hdrs include/pw/system/input.hpp include/pw/system/path.hpp include/pw/system/window.hpp + src/path_internal.in.hpp ) set(srcs @@ -13,6 +14,15 @@ set(srcs src/window.cpp ) + + + +configure_file(src/path_internal.in.hpp + ${CMAKE_BINARY_DIR}/include/pw/system/path_internal.hpp + @ONLY + ) + + add_library(pwsystem STATIC ${hdrs} @@ -23,6 +33,8 @@ target_include_directories( pwsystem PUBLIC include + PRIVATE + ${CMAKE_BINARY_DIR}/include/ ) target_link_libraries(pwsystem pwcore pwvisual glfw glad) diff --git a/src/system/src/path.cpp b/src/system/src/path.cpp index 205cb79..e2fe49d 100644 --- a/src/system/src/path.cpp +++ b/src/system/src/path.cpp @@ -1,5 +1,7 @@ #include "pw/system/path.hpp" +#include "pw/system/path_internal.hpp" + #if defined(_WIN32) || defined(_WIN64) || defined(_WIN32_WCE) #define WIN32_LEAN_AND_MEAN #include @@ -28,7 +30,14 @@ struct path::impl { path &host; - impl(path &host_) : host(host_) {} + std::vector internal_paths; + + impl(path &host_) : host(host_) + { + // TODO: this should only be done in debug/develop mode!!! + internal_paths.push_back(std::string(internal::pixwerx_binary_dir)); + internal_paths.push_back(std::string(internal::pixwerx_source_dir)); + } }; @@ -77,8 +86,13 @@ std::string path::executable_path() const DWORD ret = GetModuleFileName( NULL, &lpFname[0], MAXPATHLEN ); result.assign(&lpFname[0]); #elif defined(__USE_POSIX) - readlink("/proc/self/exe", buf.data(), buf.size()); + auto read_bytes = readlink("/proc/self/exe", buf.data(), buf.size()); // data is not null-terminated + + // make buffer null - terminated + if (read_bytes < buf.size()) buf[read_bytes] = '\0'; + #endif + result.assign(buf.data()); return result; @@ -98,6 +112,9 @@ std::string path::find_file(const std::string&) const path::path() { _impl = std::make_unique(*this); + + // preset by implementation which should add package resource paths + _resource_paths.assign(_impl->internal_paths.begin(),_impl->internal_paths.end()); } std::string path::get_filename(const std::string& filepath, diff --git a/src/system/src/path_internal.in.hpp b/src/system/src/path_internal.in.hpp new file mode 100644 index 0000000..2d185a6 --- /dev/null +++ b/src/system/src/path_internal.in.hpp @@ -0,0 +1,16 @@ +#ifndef PW_SYSTEM_PATH_INTERNAL_HPP +#define PW_SYSTEM_PATH_INTERNAL_HPP 1 + +#include + +namespace pw { +namespace internal { + +constexpr std::string_view pixwerx_source_dir { "@CMAKE_SOURCE_DIR@" }; +constexpr std::string_view pixwerx_binary_dir { "@CMAKE_BINARY_DIR@" }; + +} +} + + +#endif diff --git a/src/visual/CMakeLists.txt b/src/visual/CMakeLists.txt index 12eb6e2..36e6c8f 100644 --- a/src/visual/CMakeLists.txt +++ b/src/visual/CMakeLists.txt @@ -12,7 +12,7 @@ set(srcs src/context.cpp src/framebuffer.cpp src/shader.cpp - src/pass.cpp +# src/pass.cpp # src/pipeline.cpp # src/target.cpp src/texture.cpp diff --git a/src/visual/include/pw/visual/context.hpp b/src/visual/include/pw/visual/context.hpp index 2c175ae..5da31d4 100644 --- a/src/visual/include/pw/visual/context.hpp +++ b/src/visual/include/pw/visual/context.hpp @@ -60,18 +60,6 @@ protected: std::unique_ptr _impl; }; - -//class context { -//public: - -// virtual bool make_current() = 0; -// virtual void resize() = 0; -// virtual ::pw::size size() = 0; -// virtual void flush() = 0; - -// virtual ~context() = default; -//}; - } #endif diff --git a/src/visual/src/renderer.cpp b/src/visual/src/renderer.cpp index 3f66fac..0e9bbb1 100644 --- a/src/visual/src/renderer.cpp +++ b/src/visual/src/renderer.cpp @@ -149,24 +149,11 @@ struct renderer::impl { void draw() { - - // following code has no business being here ;) -#if 0 - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - glClearColor(0.0,1.0,0,1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#endif - - - glBindVertexArray(_vao); glDrawElements(GL_TRIANGLES, _mesh_elements, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); -#if 1 +#if 0 auto error = glGetError(); if (error != GL_NO_ERROR) { @@ -180,7 +167,7 @@ struct renderer::impl { }; // -// +// Outer wrapper // renderer::renderer() @@ -229,22 +216,4 @@ void renderer::set_change_count(uint64_t n) _impl->_change_count = n; } - - -//class viewport { - - - -// void set(point p,size s); - - - -//protected: - -// struct _impl; -// std::unique_ptr<_impl>; - -//}; - - } diff --git a/src/visual/src/texture.cpp b/src/visual/src/texture.cpp index 48e366e..a9e5972 100644 --- a/src/visual/src/texture.cpp +++ b/src/visual/src/texture.cpp @@ -11,8 +11,8 @@ struct texture::impl { texture &_host; - uint32_t _texture_id {0}; - uint32_t _texture_sampler {0}; + uint32_t _texture_id { 0 }; + uint32_t _texture_sampler { 0 }; uint64_t _change_count { std::numeric_limits::max()}; impl() = delete; @@ -93,6 +93,7 @@ struct texture::impl { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // create texture glTexImage2D(GL_TEXTURE_2D,0,format, i.size().width,i.size().height, 0, @@ -101,7 +102,9 @@ struct texture::impl { nullptr ); + // generate MipMaps glGenerateMipmap(GL_TEXTURE_2D); + glGenerateTextureMipmap(_texture_id); // debug::e() << __PRETTY_FUNCTION__ << " " << __LINE__ << " GL error: " << glGetError();