Browse Source

testing some raycasting algorithms

master
cinnaboot 8 years ago
parent
commit
4743d7d58a
  1. 1
      TODO.md
  2. 67
      src/camera.cpp
  3. 8
      src/camera.h
  4. 7
      src/gooey.cpp
  5. 67
      src/hexgame.cpp
  6. 63
      src/hexgrid.cpp
  7. 13
      src/hexgrid.h
  8. 7
      src/util.h

1
TODO.md

@ -35,6 +35,7 @@
- use a storage pool for assimp meshes allowing reuse across entities
- also cache textures from loaded meshes for re-use
- replace remaining calls to malloc/free with safe(r) function in util.h
- remove v2i/v3f... etc from util.h and either use glm everywhere, or write a smaller linear math.h
## LATER TODO:
- add initial opengl constant for INT_MAX, and checks in render_group functions

67
src/camera.cpp

@ -12,6 +12,12 @@
#define NEAR_CLIP_PLANE 20.f
// forward declarations
inline glm::vec3 convertv3f(v3f v);
// interface
void
cameraInitPerspective(camera& cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up)
{
@ -65,6 +71,59 @@ cameraUnproject(camera& cam, int x, int y, int vp_width, int vp_height)
return v;
}
v3f
cameraCreateRay(camera& cam, v2i vp_coords, v2i vp_dims)
{
#if 0
float x = 2.f * vp_coords.x / vp_dims.x - 1.f;
float y = 2.f * vp_coords.y / vp_dims.y - 1.f;
glm::vec4 ray_start_ndc = glm::vec4(x, y, -1.f, 1.f);
glm::vec4 ray_end_ndc = glm::vec4(x, y, 0, 1.f);
glm::mat4 M = glm::inverse(cam.projection * cam.view);
glm::vec4 ray_start_world = M * ray_start_ndc;
glm::vec4 ray_end_world = M * ray_end_ndc;
ray_start_world /= ray_start_world.w;
ray_end_world /= ray_end_world.w;
glm::vec3 ray_origin = glm::vec3(ray_start_world);
glm::vec3 ray_dir = glm::normalize(glm::vec3(ray_end_world - ray_start_world));
return v3f(ray_dir.x, ray_dir.y, ray_dir.z);
#else
// http://antongerdelan.net/opengl/raycasting.html
float x = 2.f * vp_coords.x / vp_dims.x - 1.f;
float y = 2.f * vp_coords.y / vp_dims.y - 1.f;
glm::vec4 ray_clip = glm::vec4(x, y, -1.f, 1.f);
glm::vec4 ray_eye = glm::inverse(cam.projection) * ray_clip;
ray_eye = glm::vec4(ray_eye.x, ray_eye.y, -1.f, 0); // NOTE: reset as ray
glm::vec4 ray_world = glm::normalize(glm::inverse(cam.view) * ray_eye);
return v3f(ray_world.x, ray_world.y, ray_world.z);
#endif
}
bool
cameraIntersectPlane(camera& cam, v3f ray, v3f plane_origin, v3f plane_normal, v3f& intersection)
{
glm::vec3 c_o = cam.position;
glm::vec3 r = convertv3f(ray);
//glm::vec3 r = cam.forward;
glm::vec3 p_o = convertv3f(plane_origin);
glm::vec3 p_n = convertv3f(plane_normal);
float divisor = glm::dot(r, p_n);
if (divisor <= 0.000001f && divisor >= -0.000001f) // NOTE: ray and plane are co-planar
return false;
#if 1
float distance = glm::dot((p_o - c_o), p_n) / divisor;
glm::vec3 xsect = c_o + (r * distance);
#else
float distance = glm::dot(n, (p_o - c_o)) / glm::dot(n, r);
glm::vec3 xsect = c_o + r * distance;
#endif
intersection = v3f(xsect.x, xsect.y, xsect.z);
return true;
}
void
cameraMove(camera& cam, bool up, bool left, bool down, bool right, bool forward, bool backward)
{
@ -143,3 +202,11 @@ cameraRoll(camera& cam, bool CW, bool CCW)
cam.view *= m;
cam.MVP = cam.projection * cam.view * cam.model;
}
// internal
inline glm::vec3
convertv3f(v3f v)
{
return glm::vec3(v.x, v.y, v.z);
}

8
src/camera.h

@ -31,7 +31,15 @@ enum projection_type
v2f cameraUnproject(camera& cam, int x, int y, int vp_width, int vp_height);
v3f cameraCreateRay(camera& cam, v2i vp_coords, v2i vp_dims);
bool cameraIntersectPlane(camera& cam, v3f ray, v3f plane_origin, v3f plane_normal, v3f& intersection);
void cameraInitPerspective(camera& cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up);
void cameraMove(camera& cam, bool up, bool left, bool down, bool right, bool forward, bool backward);
void cameraRotate(camera& cam, int32 xrel, int32 yrel);
void cameraRoll(camera& cam, bool CW, bool CCW);

7
src/gooey.cpp

@ -147,6 +147,10 @@ renderHexgridWindow(hexgrid& grid, ImGuiWindowFlags window_flags)
grid.draw_mode = LINE;
if (ImGui::RadioButton("Cone Fill", (grid.draw_mode == CONE_FILL)))
grid.draw_mode = CONE_FILL;
if (ImGui::RadioButton("Add Hexes", (grid.draw_mode == ADD_HEXES)))
grid.draw_mode = ADD_HEXES;
if (ImGui::RadioButton("Remove Hexes", (grid.draw_mode == REMOVE_HEXES)))
grid.draw_mode = REMOVE_HEXES;
ImGui::Separator();
ImGui::Text("is_selecting");
@ -166,9 +170,6 @@ renderHexgridWindow(hexgrid& grid, ImGuiWindowFlags window_flags)
}
ImGui::Separator();
ImGui::Button("Add Hex");
ImGui::SameLine(); ImGui::Button("Remove Hex");
ImGui::TextWrapped("TODO: need to add more state to hexgame.cpp for adding/removing hexes, and modifying entities");
ImGui::End();
}

67
src/hexgame.cpp

@ -90,6 +90,10 @@ init()
// TODO: I think this is necessary because we're using calloc to initialize gamestate
// which contains the hashtable.
g_game_state->grid.hex_map = std::unordered_map<Hex, hex_info, hex_hashfunc>();
// NOTE: testing hex_add
g_game_state->grid.draw_mode = ADD_HEXES;
// TODO: maybe add this as an option to scene json?
g_game_state->grid.normal = v3f(0.f, 0.f, 1.f);
// init global render state
g_render_state = UTIL_ALLOC(1, render_state);
@ -170,37 +174,41 @@ startDrawHelper(int32 x, int32 y)
void
handleMouseDown(SDL_MouseButtonEvent &e)
{
game_state* gs = g_game_state;
render_state* rs = g_render_state;
v2i coords = mapMouseToViewport(e.x, e.y);
v2i dims = rs->viewport_dims;
switch (g_game_state->grid.draw_mode)
{
switch (gs->grid.draw_mode) {
case FILL:
startDrawHelper(coords.x, coords.y);
break;
case LINE:
startDrawHelper(coords.x, coords.y);
break;
case CONE_FILL:
startDrawHelper(coords.x, coords.y);
break;
case PATHFINDING:
break;
case ADD_HEXES: {
v3f ray = cameraCreateRay(rs->cam, coords, dims);
v3f xsect;
if (cameraIntersectPlane(rs->cam, ray, gs->grid.position, gs->grid.normal, xsect))
hgAddHex(gs->grid, xsect);
break;
}
case NONE:
// fall through
default:
{
v2i dims = g_render_state->viewport_dims;
v2f v = cameraUnproject(g_render_state->cam, coords.x, coords.y, dims.x, dims.y);
hex_info *hex = hgGetSingleHex(g_game_state->grid, v.x, v.y);
v2f v = cameraUnproject(rs->cam, coords.x, coords.y, dims.x, dims.y);
hex_info *hex = hgGetSingleHex(gs->grid, v.x, v.y);
if (hex) {
hex->selected = !hex->selected;
g_game_state->grid.start_hex = g_game_state->grid.current_hex = hex;
gs->grid.start_hex = gs->grid.current_hex = hex;
}
}break;
break;
}
}
@ -211,25 +219,19 @@ handleMouseMove(SDL_MouseMotionEvent &e)
v2i dims = g_render_state->viewport_dims;
v2f v = cameraUnproject(g_render_state->cam, coords.x, coords.y, dims.x, dims.y);
switch (g_game_state->grid.draw_mode)
{
switch (g_game_state->grid.draw_mode) {
case FILL:
hgUpdateHexFill(g_game_state->grid, v.x, v.y);
break;
case LINE:
hgUpdateHexLineDraw(g_game_state->grid, v.x, v.y);
break;
case CONE_FILL:
hgUpdateHexConeFill(g_game_state->grid, v.x, v.y, CONE_ANGLE, g_polygon_select_vertices);
break;
case PATHFINDING:
break;
case NONE:
// fall through
default:
break;
}
@ -241,22 +243,19 @@ processSDLEvents()
SDL_Event e;
bool run = true;
while (SDL_PollEvent(&e))
{
while (SDL_PollEvent(&e)) {
// let gooey have event
// TODO: need to check for both io.WantCaptureKeyboard and io.WantCaptureMouse
// to fix bug with 'ESC' not passing through while in imgui
bool gooey_wants = gooProcessEvent(e);
game_state* gs = g_game_state;
switch (e.type)
{
switch (e.type) {
case SDL_QUIT:
run = false;
break;
case SDL_KEYDOWN:
switch (e.key.keysym.sym)
{
switch (e.key.keysym.sym) {
case SDLK_ESCAPE: run = false; break;
case SDLK_e: gs->is_moveforward = true; break;
case SDLK_s: gs->is_moveleft = true; break;
@ -269,8 +268,7 @@ processSDLEvents()
}
break;
case SDL_KEYUP:
switch (e.key.keysym.sym)
{
switch (e.key.keysym.sym) {
case SDLK_e: gs->is_moveforward = false; break;
case SDLK_s: gs->is_moveleft = false; break;
case SDLK_d: gs->is_movebackward = false; break;
@ -282,22 +280,17 @@ processSDLEvents()
}
break;
case SDL_MOUSEBUTTONDOWN:
if (!gooey_wants)
{
if (e.button.button == SDL_BUTTON_LEFT)
{
if (!gooey_wants) {
if (e.button.button == SDL_BUTTON_LEFT) {
gs->grid.is_selecting = true;
handleMouseDown(e.button);
}
else if (e.button.button == SDL_BUTTON_RIGHT)
{
} else if (e.button.button == SDL_BUTTON_RIGHT) {
gs->is_camera_rotate = true;
}
}
break;
case SDL_MOUSEBUTTONUP:
if (!gooey_wants)
{
if (!gooey_wants) {
if (e.button.button == SDL_BUTTON_LEFT)
gs->grid.is_selecting = false;
else if (e.button.button == SDL_BUTTON_RIGHT)

63
src/hexgrid.cpp

@ -5,7 +5,9 @@
// forward declarations
bool createHexagonGrid(hexgrid& hg);
hex_info createHexInfo(hexgrid& hg, int q, int r);
void createHexagonGrid(hexgrid& hg);
// interface
@ -13,8 +15,7 @@ bool
hgCreateHexes(hexgrid& hg)
{
if (hg.gridT == HEXAGON) {
if (!createHexagonGrid(hg))
return false;
createHexagonGrid(hg);
} else {
LOG(ERROR) << "Unhandled grid type\n";
return false;
@ -23,6 +24,32 @@ hgCreateHexes(hexgrid& hg)
return true;
}
// TODO: testing add/remove hex interface
bool
hgAddHex(hexgrid& hg, v3f hex_coords)
{
hex_info* hxi = hgGetSingleHex(hg, hex_coords.x, hex_coords.y);
if (hxi) {
hxi->selected = true;
} else {
Hex h = hex_round(pixel_to_hex(hg.hexlib_layout, Point(hex_coords.x, hex_coords.y)));
hex_info new_hex = createHexInfo(hg, h.q, h.r);
// TODO: need to reseize the GL buffers for filled hexes & hex lines here
//hg.hex_map.insert({h, new_hex});
}
return false;
}
bool
hgRemoveHex(hexgrid& hg, v3i hex_coords)
{
return false;
}
// -------------------
hex_info*
hgGetSingleHex(hexgrid& hg, real32 x, real32 y)
{
@ -157,7 +184,23 @@ hgUpdateUVBuffer(hexgrid& hg, float* uv_buffer, uint buf_len)
// internal
bool
hex_info
createHexInfo(hexgrid& hg, int q, int r)
{
hex_info hxi;
hxi.hexID = (int32) hg.hex_map.size();
hxi.selected = false;
hxi.hex.q = q; hxi.hex.r = r; hxi.hex.s = -q-r;
Point p = hex_to_pixel(hg.hexlib_layout, hxi.hex);
hxi.XPos = p.x;
hxi.YPos = p.y;
hxi.vertices = polygon_corners(hg.hexlib_layout, hxi.hex);
hxi.vertices.shrink_to_fit();
return hxi;
}
void
createHexagonGrid(hexgrid& hg)
{
int hr = hg.hex_radius;
@ -168,15 +211,7 @@ createHexagonGrid(hexgrid& hg)
int r2 = std::min(hr, -q + hr);
for (int r = r1; r <= r2; r++) {
hex_info hxi;
hxi.hexID = (int32) hg.hex_map.size();
hxi.selected = false;
hxi.hex.q = q; hxi.hex.r = r; hxi.hex.s = -q-r;
Point p = hex_to_pixel(hg.hexlib_layout, hxi.hex);
hxi.XPos = p.x;
hxi.YPos = p.y;
hxi.vertices = polygon_corners(hg.hexlib_layout, hxi.hex);
hxi.vertices.shrink_to_fit();
hex_info hxi = createHexInfo(hg, q, r);
// NOTE: testing sparse grid
if ((q > -2 && q < 2) && (r > -2 && r < 2)) {
@ -187,6 +222,4 @@ createHexagonGrid(hexgrid& hg)
/////////////
}
}
return true;
}

13
src/hexgrid.h

@ -16,7 +16,9 @@ enum HexDrawMode
FILL,
LINE,
CONE_FILL,
PATHFINDING
PATHFINDING,
ADD_HEXES,
REMOVE_HEXES
};
// TODO: implement more hexgrid types
@ -55,6 +57,7 @@ struct hexgrid
Layout hexlib_layout;
Orientation hexlib_orientation;
v3f position;
v3f normal;
uint hex_size;
uint hex_radius;
@ -72,6 +75,14 @@ struct hexgrid
bool hgCreateHexes(hexgrid& hg);
// TODO: testing add/remove hex interface
bool hgAddHex(hexgrid& hg, v3f hex_coords);
bool hgRemoveHex(hexgrid& hg, v3i hex_coords);
// -------------------
hex_info* hgGetSingleHex(hexgrid& hg, real32 x, real32 y);
void hgResetHexes(hexgrid& hg);

7
src/util.h

@ -41,6 +41,13 @@ struct v3f
real64 z;
};
struct v3i
{
int32 x;
int32 y;
int32 z;
};
struct v4i
{
int32 x0;

Loading…
Cancel
Save