From ff91bbbc71b6241c13eeb2290b75ceba6f89cad9 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Fri, 10 Feb 2017 19:24:44 +0000 Subject: [PATCH] Fix code so raytrace test now passes. --- src/gamelib/character.cpp | 4 +- src/gamelib/grid_raytrace.cpp | 75 +++++++++++++++++++++++------------ src/gamelib/grid_raytrace.hpp | 12 +----- test/unit/grid_raytrace.cpp | 29 +++++++------- 4 files changed, 66 insertions(+), 54 deletions(-) diff --git a/src/gamelib/character.cpp b/src/gamelib/character.cpp index 7af063c..c72b8fc 100644 --- a/src/gamelib/character.cpp +++ b/src/gamelib/character.cpp @@ -107,8 +107,8 @@ namespace curry { vec2us last_valid_pos(0xFFFF); - auto is_walkable = [](const WorldTileProperty& wtp) { - return wtp.property->walkable; + auto is_walkable = [](vec2us idx) { + return true; //wtp.property->walkable; }; for_each_voxel_under_segment(old_pos, this->position(), m_texture.width_height(), *m_world, is_walkable); diff --git a/src/gamelib/grid_raytrace.cpp b/src/gamelib/grid_raytrace.cpp index 3309bf7..cb2615f 100644 --- a/src/gamelib/grid_raytrace.cpp +++ b/src/gamelib/grid_raytrace.cpp @@ -79,13 +79,21 @@ namespace curry { //else //return INFINITY; } + + vec2f frac (vec2f parVal) { + return parVal - vec2f(std::floor(parVal.x()), std::floor(parVal.y())); + } + + template int sgn (T val) { + return (T(0) < val) - (val < T(0)); + } #if !defined(BUILD_TESTING) } //unnamed namespace #endif //see: //http://stackoverflow.com/questions/24679963/precise-subpixel-line-drawing-algorithm-rasterization-algorithm - void for_each_voxel_under_segment (const vec2f& parFrom, const vec2f& parTo, vec2us parObjSize, const WorldGrid& parWorld, std::function parFunc) { + void for_each_voxel_under_segment (const vec2f& parFrom, const vec2f& parTo, vec2us parObjSize, const WorldGrid& parWorld, std::function parFunc) { const vec2f tile_size = vector_cast(parWorld.tile_size()); //in this simplified case everything should be part of the world grid assert(parFrom >= vec2f(0.0f)); @@ -93,36 +101,51 @@ namespace curry { assert(parFrom / tile_size <= vector_cast(parWorld.world_size())); assert(parTo / tile_size <= vector_cast(parWorld.world_size())); - float t = 0.0f; + //float t = 0.0f; const vec2f& u = parFrom; const vec2f v = parTo - parFrom; - vec2us start = pixel_to_world_tile(parWorld, u); - vec2f step(fsgn(v.x()), fsgn(v.y())); + //vec2f step(fsgn(v.x()), fsgn(v.y())); - const auto next_tile_boundary = (step + abs(step)) / 2.0f; - const auto intersection = vec2f( - segment_intersection( - u, - v, - vec2f(static_cast(start.x() + next_tile_boundary.x()), 0.0f), - vec2f(0.0f, static_cast(parWorld.world_size().y()) * tile_size.y()) - ), - segment_intersection( - u, - v, - vec2f(0.0f, static_cast(start.y()) + next_tile_boundary.y()), - vec2f(static_cast(parWorld.world_size().x()) * tile_size.x(), 0.0f) - ) - ); + const auto delta = tile_size / v; + auto max = delta * (vec2f(1.0f) - frac(u / tile_size)); - const auto delta = vec2f( - std::isinf(intersection.x()) ? 0.0f : tile_size.x() / dot(vec2f(1.0f, 0.0f), v * inv_length(v)), - 0.0f //std::isinf(intersection.y()) ? 0.0f : tile_size.y() / - ); + //vec2us start = pixel_to_world_tile(parWorld, u); + //const auto next_tile_boundary = (step + abs(step)) / 2.0f; + //const auto max = vec2f( + // segment_intersection( + // u, + // v, + // vec2f(static_cast(start.x() + next_tile_boundary.x()), 0.0f), + // vec2f(0.0f, static_cast(parWorld.world_size().y()) * tile_size.y()) + // ), + // segment_intersection( + // u, + // v, + // vec2f(0.0f, static_cast(start.y()) + next_tile_boundary.y()), + // vec2f(static_cast(parWorld.world_size().x()) * tile_size.x(), 0.0f) + // ) + //); - //if (not std::isinf(intersection_vert)) { -//todo: continuare da qui - //} + //const auto delta = vec2f( + // std::isinf(max.x()) ? 0.0f : tile_size.x() / dot(vec2f(1.0f, 0.0f), v * inv_length(v)), + // 0.0f //std::isinf(max.y()) ? 0.0f : tile_size.y() / + //); + + //see: + //http://stackoverflow.com/questions/12367071/how-do-i-initialize-the-t-variables-in-a-fast-voxel-traversal-algorithm-for-ray#12370474 + vec2i step(sgn(v.x()), sgn(v.y())); + vec2us curr_tile = pixel_to_world_tile(parWorld, u); + const vec2us last_tile = pixel_to_world_tile(parWorld, parTo); + while (parFunc(curr_tile) and last_tile != curr_tile) { + if (max.x() < max.y()) { + max.x() += delta.x(); + curr_tile.x() = static_cast(curr_tile.x() + step.x()); + } + else { + max.y() += delta.y(); + curr_tile.y() = static_cast(curr_tile.y() + step.y()); + } + } } } //namespace curry diff --git a/src/gamelib/grid_raytrace.hpp b/src/gamelib/grid_raytrace.hpp index 80b7123..017e5a7 100644 --- a/src/gamelib/grid_raytrace.hpp +++ b/src/gamelib/grid_raytrace.hpp @@ -25,20 +25,10 @@ namespace curry { class WorldGrid; - class TileProperty; #if defined(BUILD_TESTING) float segment_intersection (const vec2f& parA, const vec2f& parDirA, const vec2f& parB, const vec2f& parDirB); #endif - struct WorldTileProperty { - vec2us index; - const TileProperty* property; - - bool operator== (const WorldTileProperty& parOther) const { - return parOther.index == index && parOther.property == property; - } - }; - - void for_each_voxel_under_segment ( const vec2f& parFrom, const vec2f& parTo, vec2us parObjSize, const WorldGrid& parWorld, std::function parFunc ); + void for_each_voxel_under_segment ( const vec2f& parFrom, const vec2f& parTo, vec2us parObjSize, const WorldGrid& parWorld, std::function parFunc ); } //namespace curry diff --git a/test/unit/grid_raytrace.cpp b/test/unit/grid_raytrace.cpp index 5fbd6a9..ac6032d 100644 --- a/test/unit/grid_raytrace.cpp +++ b/test/unit/grid_raytrace.cpp @@ -28,7 +28,6 @@ TEST_CASE ("Check that 2D raytracing works", "[raytracing][geometry]") { using curry::for_each_voxel_under_segment; using curry::vec2us; using curry::vec2f; - using curry::WorldTileProperty; curry::WorldGrid world(vec2us(64)); world.set_layers(vec2us(10, 10), std::vector>( {{ @@ -49,27 +48,27 @@ TEST_CASE ("Check that 2D raytracing works", "[raytracing][geometry]") { REQUIRE(world.layer_count() == 1); { - std::vector diagonal; + std::vector diagonal; for_each_voxel_under_segment ( vec2f(0.0f, 0.0f), //from - vec2f(640.0f, 640.0f), //to + vec2f(639.0f, 639.0f), //to vec2us(1, 1), //objsize world, //world - [diagonal](const WorldTileProperty& wtp) mutable {diagonal.push_back(wtp); return true;} + [&diagonal](vec2us wtp) mutable {diagonal.push_back(wtp); return true;} ); const auto* tile_prop = &world.tile_property(world.tile(vec2us(0))); - std::vector expected { - WorldTileProperty{vec2us(0, 0), tile_prop}, - WorldTileProperty{vec2us(1, 1), tile_prop}, - WorldTileProperty{vec2us(2, 2), tile_prop}, - WorldTileProperty{vec2us(3, 3), tile_prop}, - WorldTileProperty{vec2us(4, 4), tile_prop}, - WorldTileProperty{vec2us(5, 5), tile_prop}, - WorldTileProperty{vec2us(6, 6), tile_prop}, - WorldTileProperty{vec2us(7, 7), tile_prop}, - WorldTileProperty{vec2us(8, 8), tile_prop}, - WorldTileProperty{vec2us(9, 9), tile_prop} + std::vector expected { + vec2us(0, 0), vec2us(0, 1), + vec2us(1, 1), vec2us(1, 2), + vec2us(2, 2), vec2us(2, 3), + vec2us(3, 3), vec2us(3, 4), + vec2us(4, 4), vec2us(4, 5), + vec2us(5, 5), vec2us(5, 6), + vec2us(6, 6), vec2us(6, 7), + vec2us(7, 7), vec2us(7, 8), + vec2us(8, 8), vec2us(8, 9), + vec2us(9, 9) }; CHECK(expected == diagonal); }