Initial WiP implementation of 2D grid raytracing. Not working.
This commit is contained in:
parent
f91ff6625f
commit
e2d307da52
7 changed files with 271 additions and 7 deletions
|
@ -7,7 +7,7 @@ include(TargetArch)
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
set(common_gcc_flags "-Wall -Wextra -pedantic -Wconversion")
|
set(common_gcc_flags "-Wall -Wextra -pedantic -Wconversion -ffast-math")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags} -O0")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags} -O0")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${common_gcc_flags}")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${common_gcc_flags}")
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags} -O0")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags} -O0")
|
||||||
|
@ -72,6 +72,7 @@ add_executable(${PROJECT_NAME}
|
||||||
src/worlditems.cpp
|
src/worlditems.cpp
|
||||||
src/moveable.cpp
|
src/moveable.cpp
|
||||||
src/fsgn.cpp
|
src/fsgn.cpp
|
||||||
|
src/grid_raytrace.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} SYSTEM
|
target_include_directories(${PROJECT_NAME} SYSTEM
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit fc7b66642959e7de19aade010b6ebc1e59ba4b7a
|
Subproject commit aaa8e75dc125e4116bed76ed14cbfc028bf6e9c7
|
|
@ -21,13 +21,12 @@
|
||||||
#include "inputbag.hpp"
|
#include "inputbag.hpp"
|
||||||
#include "gameactions.hpp"
|
#include "gameactions.hpp"
|
||||||
#include "worldgrid.hpp"
|
#include "worldgrid.hpp"
|
||||||
|
#include "grid_raytrace.hpp"
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace curry {
|
namespace curry {
|
||||||
namespace {
|
|
||||||
} //unnamed namespace
|
|
||||||
|
|
||||||
Character::Character (cloonel::InputBag* parInputBag, const WorldSizeNotifiable::DeferredRegister& parDeferredRegister) :
|
Character::Character (cloonel::InputBag* parInputBag, const WorldSizeNotifiable::DeferredRegister& parDeferredRegister) :
|
||||||
WorldSizeNotifiable(parDeferredRegister),
|
WorldSizeNotifiable(parDeferredRegister),
|
||||||
m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f)),
|
m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f)),
|
||||||
|
@ -102,9 +101,30 @@ namespace curry {
|
||||||
const auto old_pos = this->position();
|
const auto old_pos = this->position();
|
||||||
const auto new_pos = old_pos + offset;
|
const auto new_pos = old_pos + offset;
|
||||||
|
|
||||||
//if (m_world
|
|
||||||
|
|
||||||
this->set_position(new_pos);
|
this->set_position(new_pos);
|
||||||
|
if (position() == old_pos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vec2us last_valid_pos(0xFFFF);
|
||||||
|
|
||||||
|
auto is_walkable = [](const WorldTileProperty& wtp) {
|
||||||
|
return wtp.property->walkable;
|
||||||
|
};
|
||||||
|
|
||||||
|
for_each_voxel_under_segment(old_pos, this->position(), m_texture.width_height(), *m_world, is_walkable);
|
||||||
|
//for (auto tile_vec : crossed_tiles(old_pos, this->position(), m_world->tile_size())) {
|
||||||
|
// const TileIndex* const tile = m_world->tile(tile_vec);
|
||||||
|
// for (uint16_t z = 0; z < m_world->layer_count(); ++z) {
|
||||||
|
// const auto& tile_prop = m_world->tile_property(tile + z);
|
||||||
|
// if (not tile_prop.walkable) {
|
||||||
|
// assert(last_valid_pos != vec2us(0xFFFF));
|
||||||
|
// this->set_position(vector_cast<vec2f>(last_valid_pos));
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// last_valid_pos = tile_vec;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Character::set_speed (float parSpeed) {
|
void Character::set_speed (float parSpeed) {
|
||||||
|
|
124
src/grid_raytrace.cpp
Normal file
124
src/grid_raytrace.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||||
|
|
||||||
|
This file is part of MyCurry.
|
||||||
|
|
||||||
|
MyCurry is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
MyCurry is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "grid_raytrace.hpp"
|
||||||
|
#include "worldgrid.hpp"
|
||||||
|
#include "vectorwrapper/vectorops.hpp"
|
||||||
|
#include "fsgn.hpp"
|
||||||
|
#include "tileproperty.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <ciso646>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cfloat>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace curry {
|
||||||
|
namespace {
|
||||||
|
float inv_length (const vec2f& parVec) {
|
||||||
|
return 1.0f / std::sqrt(parVec.x() * parVec.x() + parVec.y() * parVec.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2f abs (const vec2f& parVec) {
|
||||||
|
return vec2f(std::abs(parVec.x()), std::abs(parVec.y()));
|
||||||
|
}
|
||||||
|
|
||||||
|
float segment_intersection (const vec2f& parA, const vec2f& parDirA, const vec2f& parB, const vec2f& parDirB) {
|
||||||
|
const auto& p = parA;
|
||||||
|
const auto& r = parDirA;
|
||||||
|
const auto& q = parB;
|
||||||
|
const auto& s = parDirB;
|
||||||
|
|
||||||
|
const auto r_cross_s = cross(r, s);
|
||||||
|
if (std::abs(r_cross_s) <= FLT_EPSILON) {
|
||||||
|
if (std::abs(cross(q - p, r)) <= FLT_EPSILON) {
|
||||||
|
assert(std::abs(dot(r, r)) > FLT_EPSILON);
|
||||||
|
auto t0 = dot(q - p, r) / dot(r, r);
|
||||||
|
auto t1 = dot(q - p + s, r) / dot(r, r);
|
||||||
|
if (dot(s, r) < 0.0f)
|
||||||
|
std::swap(t0, t1);
|
||||||
|
assert(t0 <= t1);
|
||||||
|
if (0.0f <= t0)
|
||||||
|
return t0;
|
||||||
|
else if (t1 <= 1.0f)
|
||||||
|
return t1;
|
||||||
|
else
|
||||||
|
return INFINITY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return INFINITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(not (std::abs(r_cross_s) <= FLT_EPSILON));
|
||||||
|
const auto inv_r_cross_s = 1.0f / r_cross_s;
|
||||||
|
const auto t = cross(q - p, s) * inv_r_cross_s;
|
||||||
|
const auto u = cross(q - p, r) * inv_r_cross_s;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
//if (0.0f <= t and t <= 1.0f and 0.0f <= u and u <= 1.0f)
|
||||||
|
//return t;
|
||||||
|
//else
|
||||||
|
//return INFINITY;
|
||||||
|
}
|
||||||
|
} //unnamed namespace
|
||||||
|
|
||||||
|
//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<bool(const WorldTileProperty&)> parFunc) {
|
||||||
|
const vec2f tile_size = vector_cast<vec2f>(parWorld.tile_size());
|
||||||
|
//in this simplified case everything should be part of the world grid
|
||||||
|
assert(parFrom >= vec2f(0.0f));
|
||||||
|
assert(parTo >= vec2f(0.0f));
|
||||||
|
assert(parFrom / tile_size <= vector_cast<vec2f>(parWorld.world_size()));
|
||||||
|
assert(parTo / tile_size <= vector_cast<vec2f>(parWorld.world_size()));
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
const auto next_tile_boundary = (step + abs(step)) / 2.0f;
|
||||||
|
const auto intersection = vec2f(
|
||||||
|
segment_intersection(
|
||||||
|
u,
|
||||||
|
v,
|
||||||
|
vec2f(static_cast<float>(start.x() + next_tile_boundary.x()), 0.0f),
|
||||||
|
vec2f(0.0f, static_cast<float>(parWorld.world_size().y()) * tile_size.y())
|
||||||
|
),
|
||||||
|
segment_intersection(
|
||||||
|
u,
|
||||||
|
v,
|
||||||
|
vec2f(0.0f, static_cast<float>(start.y()) + next_tile_boundary.y()),
|
||||||
|
vec2f(static_cast<float>(parWorld.world_size().x()) * tile_size.x(), 0.0f)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
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() /
|
||||||
|
);
|
||||||
|
|
||||||
|
//if (not std::isinf(intersection_vert)) {
|
||||||
|
//todo: continuare da qui
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
} //namespace curry
|
39
src/grid_raytrace.hpp
Normal file
39
src/grid_raytrace.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||||
|
|
||||||
|
This file is part of MyCurry.
|
||||||
|
|
||||||
|
MyCurry is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
MyCurry is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "vector.hpp"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace curry {
|
||||||
|
class WorldGrid;
|
||||||
|
class TileProperty;
|
||||||
|
|
||||||
|
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<bool(const WorldTileProperty&)> parFunc );
|
||||||
|
} //namespace curry
|
|
@ -5,6 +5,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
main.cpp
|
main.cpp
|
||||||
|
${MYCURRY_SOURCE_DIR}/grid_raytrace.cpp
|
||||||
|
grid_raytrace.cpp
|
||||||
|
${MYCURRY_SOURCE_DIR}/worldgrid.cpp
|
||||||
|
${MYCURRY_SOURCE_DIR}/fsgn.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME}
|
target_compile_definitions(${PROJECT_NAME}
|
||||||
|
|
76
test/unit/grid_raytrace.cpp
Normal file
76
test/unit/grid_raytrace.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||||
|
|
||||||
|
This file is part of MyCurry.
|
||||||
|
|
||||||
|
MyCurry is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
MyCurry is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch.hpp"
|
||||||
|
#include "grid_raytrace.hpp"
|
||||||
|
#include "worldgrid.hpp"
|
||||||
|
#include "tileindextype.hpp"
|
||||||
|
#include "tileproperty.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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<std::vector<curry::TileIndex>>( {{
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||||
|
}}));
|
||||||
|
world.set_tile_properties(std::vector<curry::TileProperty>({ curry::TileProperty() }));
|
||||||
|
|
||||||
|
REQUIRE(world.world_size() == vec2us(10));
|
||||||
|
REQUIRE(world.layer_count() == 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<WorldTileProperty> diagonal;
|
||||||
|
for_each_voxel_under_segment (
|
||||||
|
vec2f(0.0f, 0.0f), //from
|
||||||
|
vec2f(640.0f, 640.0f), //to
|
||||||
|
vec2us(1, 1), //objsize
|
||||||
|
world, //world
|
||||||
|
[diagonal](const WorldTileProperty& wtp) mutable {diagonal.push_back(wtp); return true;}
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto* tile_prop = &world.tile_property(world.tile(vec2us(0)));
|
||||||
|
std::vector<WorldTileProperty> 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}
|
||||||
|
};
|
||||||
|
CHECK(expected == diagonal);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue