Browse Source

Added CSG v0.001a : not optimized, too much operation makes it slow. triangle count is not optimized.

Useage : "...[.... csg*]" equals "current mesh -CSG- the mesh in the braces".
Keywords :  CsgUnion<csgu>, CsgSubstract<csgs>, CsgAnd<csga>, CsgXor<csgx>
TODO : cleanup useless code.
TODO : Some bugs are still present, some face that disappear should not.
TODO : Correct epsilon useage (see geometry files).
TODO : Coplanar face are not handled -at all-.
TODO : Vertex count goes through the roof in case of a Xor.
legacy
Benjamin ‘Touky’ Huet touky 12 years ago
parent
commit
4393a43752
17 changed files with 1694 additions and 625 deletions
  1. +1
    -0
      src/Makefile.am
  2. +1
    -0
      src/core.h
  3. +553
    -0
      src/easymesh/csgbsp.cpp
  4. +78
    -0
      src/easymesh/csgbsp.h
  5. +3
    -3
      src/easymesh/easymesh-compiler.cpp
  6. +3
    -3
      src/easymesh/easymesh-compiler.h
  7. +27
    -22
      src/easymesh/easymesh-parser.y
  8. +8
    -3
      src/easymesh/easymesh-scanner.l
  9. +406
    -9
      src/easymesh/easymesh.cpp
  10. +23
    -5
      src/easymesh/easymesh.h
  11. +1
    -1
      src/easymesh/shiny.lolfx
  12. +340
    -405
      src/generated/easymesh-parser.cpp
  13. +67
    -36
      src/generated/easymesh-parser.h
  14. +140
    -118
      src/generated/easymesh-scanner.cpp
  15. +2
    -0
      src/lolcore.vcxproj
  16. +6
    -0
      src/lolcore.vcxproj.filters
  17. +35
    -20
      tutorial/05_easymesh.cpp

+ 1
- 0
src/Makefile.am View File

@@ -30,6 +30,7 @@ liblol_a_SOURCES = \
eglapp.cpp eglapp.h \
\
easymesh/easymesh.cpp easymesh/easymesh.h \
easymesh/csgbsp.cpp easymesh/csgbsp.h \
easymesh/shiny.lolfx \
easymesh/easymesh-compiler.cpp easymesh/easymesh-compiler.h \
generated/easymesh-parser.cpp generated/easymesh-parser.h \


+ 1
- 0
src/core.h View File

@@ -132,6 +132,7 @@ static inline int isnan(float f)
#include "mesh/mesh.h"
#include "image/image.h"
#include "application/application.h"
#include "easymesh/csgbsp.h"
#include "easymesh/easymesh.h"

// Managers


+ 553
- 0
src/easymesh/csgbsp.cpp View File

@@ -0,0 +1,553 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2010-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

//
// The EasyMesh class
// ------------------
//

#if defined HAVE_CONFIG_H
# include "config.h"
#endif

#if defined _XBOX
# define _USE_MATH_DEFINES /* for M_PI */
# include <xtl.h>
# undef near /* Fuck Microsoft */
# undef far /* Fuck Microsoft again */
#elif defined _WIN32
# define _USE_MATH_DEFINES /* for M_PI */
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef near /* Fuck Microsoft */
# undef far /* Fuck Microsoft again */
#endif

#include "core.h"

namespace lol
{

int CsgBsp::AddLeaf(int leaf_type, vec3 origin, vec3 normal, int above_idx)
{
if (leaf_type > 2 && leaf_type < -1)
return -1;

if ((m_tree.Count() == 0 && above_idx == -1) ||
(above_idx >= 0 &&
above_idx < m_tree.Count() &&
leaf_type > LEAF_CURRENT &&
leaf_type < LEAF_ABOVE &&
m_tree[above_idx].m_leaves[leaf_type] == -1))
{
if (m_tree.Count() != 0)
m_tree[above_idx].m_leaves[leaf_type] = m_tree.Count();
m_tree.Push(CsgBspLeaf(origin, normal, above_idx));
return m_tree.Count() - 1;
}

return -1;
}

int CsgBsp::TestPoint(int leaf_idx, vec3 point)
{
if (leaf_idx >= 0 && leaf_idx < m_tree.Count())
{
vec3 p2o = point - m_tree[leaf_idx].m_origin;

if (length(p2o) < CSG_EPSILON)
return LEAF_CURRENT;

float p2o_dot = dot(normalize(p2o), m_tree[leaf_idx].m_normal);

if (p2o_dot > CSG_EPSILON)
return LEAF_FRONT;
else if (p2o_dot < -CSG_EPSILON)
return LEAF_BACK;
}
return LEAF_CURRENT;
}

void CsgBsp::AddTriangleToTree(int const &tri_idx, vec3 const &tri_v0, vec3 const &tri_v1, vec3 const &tri_v2)
{
//<Leaf_Id, v0, v1, v2>
Array< int, vec3, vec3, vec3 > tri_to_process;
//<FW/BW, Leaf_Id, v0, v1, v2, twin_leaf>
Array< int, int, vec3, vec3, vec3, int > Leaf_to_add;

//Tree is empty, so this leaf is the first
if (m_tree.Count() == 0)
{
AddLeaf(LEAF_CURRENT, tri_v0, cross(normalize(tri_v1 - tri_v0), normalize(tri_v2 - tri_v1)), LEAF_CURRENT);
m_tree.Last().m_tri_list.Push(tri_idx, tri_v0, tri_v1, tri_v2);
return;
}

tri_to_process.Reserve(20);
tri_to_process.Push(0, tri_v0, tri_v1, tri_v2);

while (tri_to_process.Count())
{
int leaf_idx = tri_to_process.Last().m1;
vec3 v[3] = { tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4 };

int res_nb[3] = { 0, 0, 0 };
int res_side[3] = { -1, -1, -1 };

//Check where each point is located
for (int i = 0; i < 3; i++)
{
int result = TestPoint(leaf_idx, v[i]);
if (result != LEAF_CURRENT)
{
res_nb[result]++;
res_side[i] = result;
}
}

//Points are located on each sides, let's do the mumbo-jumbo
if (res_nb[LEAF_BACK] && res_nb[LEAF_FRONT])
{
//there are two intersections, no more.
vec3 isec_v[2] = { vec3(.0f), vec3(.0f) };
int isec_i[2] = { 0, 0 };
int isec_base = 0;
int isec_idx = 0;

for (int i = 0; i < 3; i++)
{
vec3 ray = v[(i + 1) % 3] - v[i];

if (RayIsectPlane(v[i], v[(i + 1) % 3],
m_tree[leaf_idx].m_origin, m_tree[leaf_idx].m_normal,
isec_v[isec_idx]))
isec_i[isec_idx++] = i;
else
isec_base = i;
}

int v_idx0 = (isec_base == 1)?(1):(0);
int v_idx1 = (isec_base == 1)?(0):(1);
int leaf_type = res_side[(isec_base + 2) % 3];

tri_to_process.Pop();
#if 1
if (m_tree[leaf_idx].m_leaves[leaf_type] == LEAF_CURRENT)
Leaf_to_add.Push(leaf_type, leaf_idx, v[((isec_base + 2) % 3)], isec_v[v_idx1], isec_v[v_idx0], -1);
else
tri_to_process.Push(leaf_idx, v[((isec_base + 2) % 3)], isec_v[v_idx1], isec_v[v_idx0]);

if (m_tree[leaf_idx].m_leaves[1 - leaf_type] == LEAF_CURRENT)
{
Leaf_to_add.Push(1 - leaf_type, leaf_idx, v[isec_base], v[((isec_base + 1) % 3)], isec_v[v_idx0], -1);
Leaf_to_add.Push(1 - leaf_type, leaf_idx, v[isec_base], isec_v[v_idx0], isec_v[v_idx1], Leaf_to_add.Count() - 1);
}
else
{
tri_to_process.Push(m_tree[leaf_idx].m_leaves[1 - leaf_type], v[isec_base], v[((isec_base + 1) % 3)], isec_v[v_idx0]);
tri_to_process.Push(m_tree[leaf_idx].m_leaves[1 - leaf_type], v[isec_base], isec_v[v_idx0], isec_v[v_idx1]);
}
#else
vec3 new_v[9] = { v[((isec_base + 2) % 3)], isec_v[v_idx1], isec_v[v_idx0],
v[isec_base], v[((isec_base + 1) % 3)], isec_v[v_idx0],
v[isec_base], isec_v[v_idx0], isec_v[v_idx1] };

//Error check : Skip the triangle where two points are on the same location.
//it fixes the problem of having an intersection with one of the isec-point being on one of the triangle vertices.
//(the problem being a very funny infinite loop)
for(int k = 0; k < 9; k += 3)
{
bool skip_tri = false;
for(int l = 0; l < 3; l++)
{
if (length(new_v[k + l] - new_v[k + (l + 1) % 3]) < CSG_EPSILON)
{
skip_tri = true;
break;
}
}

if (skip_tri)
continue;

tri_to_process.Push(0, new_v[k], new_v[k + 1], new_v[k + 2]);
}
#endif
}
//All points are on one side, transfer to the next leaf
else if (res_nb[LEAF_BACK] || res_nb[LEAF_FRONT])
{
int new_leaf_type = ((res_nb[LEAF_FRONT])?(LEAF_FRONT):(LEAF_BACK));
int new_leaf = m_tree[leaf_idx].m_leaves[new_leaf_type];

//No leaf exist, so add a new one
if (new_leaf == LEAF_CURRENT)
{
tri_to_process.Pop();
Leaf_to_add.Push(new_leaf_type, leaf_idx, v[0], v[1], v[2], -1);
}
else
tri_to_process.Last().m1 = new_leaf;
}
//All points are on the current leaf, add the tri_idx to the list of this leaf.
else
{
tri_to_process.Pop();

bool already_exist = false;
for (int i = 0; !already_exist && i < m_tree[leaf_idx].m_tri_list.Count(); i++)
already_exist = (m_tree[leaf_idx].m_tri_list[i].m1 == tri_idx);
if (!already_exist)
m_tree[leaf_idx].m_tri_list.Push(tri_idx, tri_v0, tri_v1, tri_v2);
}
}

//Add all leaves to the tree.
for (int i = 0; i < Leaf_to_add.Count(); i++)
{
//If we had it to an already existing leaf.
if (Leaf_to_add[i].m2 < m_tree.Count() && m_tree[Leaf_to_add[i].m2].m_leaves[Leaf_to_add[i].m1] == LEAF_CURRENT)
{
AddLeaf(Leaf_to_add[i].m1, tri_v0, cross(normalize(tri_v1 - tri_v0), normalize(tri_v2 - tri_v1)), Leaf_to_add[i].m2);
m_tree.Last().m_tri_list.Push(tri_idx, tri_v0, tri_v1, tri_v2);
}

/*
if (Leaf_to_add[i].m6 == -1)
{
AddLeaf(Leaf_to_add[i].m1, tri_v0, cross(normalize(tri_v1 - tri_v0), normalize(tri_v2 - tri_v1)), Leaf_to_add[i].m2);
m_tree.Last().m_tri_list.Push(tri_idx, tri_v0, tri_v1, tri_v2);
}
else
m_tree[Leaf_to_add[i].m6].m_tri_list.Push(tri_idx, tri_v0, tri_v1, tri_v2);
*/
}
}

//return 0 when no split has been done.
//return 1 when split has been done.
//return -1 when error.
int CsgBsp::TestTriangleToTree(vec3 const &tri_v0, vec3 const &tri_v1, vec3 const &tri_v2,
//In order to easily build the actual vertices list afterward, this list stores each Vertices location and its source vertices & Alpha.
//<Point_Loc, Src_V0, Src_V1, Alpha> as { Point_Loc = Src_V0 + (Src_V1 - Src_V0) * Alpha; }
Array< vec3, int, int, float > &vert_list,
//This is the final triangle list : If Side_Status is LEAF_CURRENT, a new test will be done point by point.
//<{IN|OUT}side_status, v0, v1, v2>
Array< int, int, int, int > &tri_list)
{
//This list stores the current triangles to process.
//<Leaf_Id_List, v0, v1, v2, Should_Point_Test>
Array< Array< int >, int, int, int, int > tri_to_process;

//Tree is empty, ABORT !
if (m_tree.Count() == 0)
return -1;

//Let's push the source vertices in here.
vert_list.Push(tri_v0, -1, -1, .0f);
vert_list.Push(tri_v1, -1, -1, .0f);
vert_list.Push(tri_v2, -1, -1, .0f);

//Let's push the triangle in here.
tri_to_process.Reserve(20);
tri_to_process.Push( Array< int >(), 0, 1, 2, 0);
tri_to_process.Last().m1.Push(0);

while (tri_to_process.Count())
{
while (tri_to_process.Count())
{
int leaf_idx = tri_to_process.Last().m1.Last();
int t[3] = { tri_to_process.Last().m2,
tri_to_process.Last().m3,
tri_to_process.Last().m4 };
vec3 v[3] = { vert_list[t[0]].m1,
vert_list[t[1]].m1,
vert_list[t[2]].m1 };

int res_nb[3] = { 0, 0, 0 };
int res_side[3] = { -1, -1, -1 };
//Check where each point is located
for (int i = 0; i < 3; i++)
{
int result = TestPoint(leaf_idx, v[i]);
if (result != LEAF_CURRENT)
{
res_nb[result]++;
res_side[i] = result;
}
}

//Points are located on each sides, let's do the mumbo-jumbo
if (res_nb[LEAF_BACK] && res_nb[LEAF_FRONT])
{
//there are two intersections, no more.
vec3 isec_v[2] = { vec3(.0f), vec3(.0f) };
int isec_i[2] = { 0, 0 };
int new_v_idx[2] = { 0, 0 };
int isec_base = 0;
int isec_idx = 0;

int i = 0;
for (; i < m_tree[leaf_idx].m_tri_list.Count(); i++)
{
if (TriangleIsectTriangle(v[0], v[1], v[2],
m_tree[leaf_idx].m_tri_list[i].m2, m_tree[leaf_idx].m_tri_list[i].m3, m_tree[leaf_idx].m_tri_list[i].m4,
isec_v[0], isec_v[1]))
break;
}

//There was no triangle intersection, the complex case.
if (i == m_tree[leaf_idx].m_tri_list.Count())
{
tri_to_process.Last().m1.Pop();

//Register the triangle as needing to intersect with Front & back leaves.
if (m_tree[leaf_idx].m_leaves[LEAF_FRONT] != LEAF_CURRENT)
tri_to_process.Last().m1.Push(m_tree[leaf_idx].m_leaves[LEAF_FRONT]);
if (m_tree[leaf_idx].m_leaves[LEAF_BACK] != LEAF_CURRENT)
tri_to_process.Last().m1.Push(m_tree[leaf_idx].m_leaves[LEAF_BACK]);
//Mark the triangle as needing point by point test
tri_to_process.Last().m5 = 1;
}
//there was an intersection, so let's split the triangle.
else
{
//Get intersection on actual triangle sides.
if (RayIsectTriangleSide(v[0], v[1], v[2],
isec_v[0], isec_v[1],
isec_v[0], isec_i[0], isec_v[1], isec_i[1]))
{
{
for(int k = 0; k < 2; k++)
{
if (isec_base == isec_i[k])
isec_base++;

#if 1 //Skip point creation if it's on the same location a one of the triangle.
bool skip_point = false;
int l = 0;
for(; l < 3; l++)
{
if (length(v[l] - isec_v[k]) < CSG_EPSILON)
{
skip_point = true;
new_v_idx[k] = t[l];
break;
}
}

if (skip_point)
continue;
#endif
new_v_idx[k] = vert_list.Count();
vec3 PmV0 = (isec_v[k] - vert_list[t[isec_i[k]]].m1);
vec3 V1mV0 = (vert_list[t[(isec_i[k] + 1) % 3]].m1 - vert_list[t[isec_i[k]]].m1);
float alpha = length(PmV0) / length(V1mV0);
vert_list.Push(isec_v[k],
t[isec_i[k]], t[(isec_i[k] + 1) % 3],
//Alpha = length((Point_Loc - Src_V0) / (Src_V1 - Src_V0));
alpha);
}

int v_idx0 = (isec_base == 1)?(1):(0);
int v_idx1 = (isec_base == 1)?(0):(1);
//Leaf_type is the type for the triangle that is alone on its side.
int leaf_type = res_side[(isec_base + 2) % 3];
int tri_to_remove = tri_to_process.Count() - 1;

#if 0
if (m_tree[leaf_idx].m_leaves[leaf_type] == LEAF_CURRENT && tri_to_process.Last().m1.Last() == 1)
tri_list.Push(leaf_type,
t[(isec_base + 2) % 3], new_v_idx[v_idx1], new_v_idx[v_idx0]);
else
{
tri_to_process.Push(Array< int >(), t[(isec_base + 2) % 3], new_v_idx[v_idx1], new_v_idx[v_idx0], 0);
tri_to_process.Last().m1.Push(0);
}

if (m_tree[leaf_idx].m_leaves[1 - leaf_type] == LEAF_CURRENT && tri_to_process.Last().m1.Last() == 1)
{
tri_list.Push((tri_to_process.Last().m5)?(LEAF_CURRENT):(1 - leaf_type),
t[isec_base], new_v_idx[((isec_base + 1) % 3)], new_v_idx[v_idx0]);
tri_list.Push((tri_to_process.Last().m5)?(LEAF_CURRENT):(1 - leaf_type),
t[isec_base], new_v_idx[v_idx0], new_v_idx[v_idx1]);
}
else
{
tri_to_process.Push(Array< int >(), t[isec_base], t[((isec_base + 1) % 3)], new_v_idx[v_idx0], 0);
tri_to_process.Last().m1.Push(0);
tri_to_process.Push(Array< int >(), t[isec_base], new_v_idx[v_idx0], new_v_idx[v_idx1], 0);
tri_to_process.Last().m1.Push(0);
}
#else
int new_t[9] = { t[(isec_base + 2) % 3], new_v_idx[v_idx1], new_v_idx[v_idx0],
t[isec_base], t[((isec_base + 1) % 3)], new_v_idx[v_idx0],
t[isec_base], new_v_idx[v_idx0], new_v_idx[v_idx1] };
int new_side[3] = { res_side[(isec_base + 2) % 3],
(res_side[isec_base] == LEAF_CURRENT)?(res_side[((isec_base + 1) % 3)]):(res_side[isec_base]),
res_side[isec_base] };

//Error check : Skip the triangle where two points are on the same location.
//it fixes the problem of having an intersection with one of the isec-point being on one of the triangle vertices.
//(the problem being a very funny infinite loop)
for(int k = 0; k < 9; k += 3)
{
#if 1 //Error check
bool skip_tri = false;
for(int l = 0; l < 3; l++)
{
if (length(vert_list[new_t[k + l]].m1 - vert_list[new_t[k + (l + 1) % 3]].m1) < CSG_EPSILON)
{
skip_tri = true;
break;
}
}

if (skip_tri)
continue;
#endif
#if 0 //Send the newly created triangle back to the beginning
tri_to_process.Push(Array< int >(), new_t[k], new_t[k + 1], new_t[k + 2], 0);
tri_to_process.Last().m1.Push(0);
#else //Inherit parent tree
if (m_tree[leaf_idx].m_leaves[new_side[k / 3]] == LEAF_CURRENT && tri_to_process[tri_to_remove].m1.Count() == 1)
tri_list.Push(new_side[k / 3], new_t[k], new_t[k + 1], new_t[k + 2]);
else
{
tri_to_process.Push(Array< int >(), new_t[k], new_t[k + 1], new_t[k + 2], 0);
tri_to_process.Last().m1 = tri_to_process[tri_to_remove].m1;
if (m_tree[leaf_idx].m_leaves[new_side[k / 3]] == LEAF_CURRENT)
tri_to_process.Last().m1.Pop();
else
tri_to_process.Last().m1.Last() = m_tree[leaf_idx].m_leaves[new_side[k / 3]];
}
#endif
}
#endif

tri_to_process.Remove(tri_to_remove);
}
}
}
}
//All points are on one side, transfer to the next leaf
else if (res_nb[LEAF_BACK] || res_nb[LEAF_FRONT])
{
int new_leaf_type = ((res_nb[LEAF_FRONT])?(LEAF_FRONT):(LEAF_BACK));
int new_leaf = m_tree[leaf_idx].m_leaves[new_leaf_type];

//No leaf exist, we're at the end
if (new_leaf == LEAF_CURRENT)
{
//We still need to test other leaves.
if (tri_to_process.Last().m1.Count() > 1)
tri_to_process.Last().m1.Pop();
else
{
tri_list.Push((tri_to_process.Last().m5)?(LEAF_CURRENT):(new_leaf_type),
tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4);
tri_to_process.Pop();
}
}
else
tri_to_process.Last().m1.Last() = new_leaf;
}
//All points are on the current leaf, add the tri_idx to the list of this leaf.
else
{
//TODO : Special case, handle coplanar cut.
tri_list.Push(LEAF_CURRENT, tri_to_process.Last().m2, tri_to_process.Last().m3, tri_to_process.Last().m4);
tri_to_process.Pop();
}
}

//Now that we have all the split points, let's double-check the results
for (int i = 0; i < tri_list.Count(); i++)
{
#define TEST_MAX 4
int t[3] = { tri_list[i].m2,
tri_list[i].m3,
tri_list[i].m4 };
vec3 v[4] = { vert_list[t[0]].m1,
vert_list[t[1]].m1,
vert_list[t[2]].m1,
(vert_list[t[0]].m1 +
vert_list[t[1]].m1 +
vert_list[t[2]].m1) / 3.0f };

int res_total = 0;
int res_nb[3] = { 0, 0, 0 };
int res_Leaf[4] = { 0, 0, 0, 0 };
int res_side[4] = { -1, -1, -1, -1 };
while (res_total < TEST_MAX)
{
for (int k = 0; k < TEST_MAX; k++)
{
if (res_Leaf[k] != LEAF_CURRENT)
{
int result = TestPoint(res_Leaf[k], v[k]);
if (result != LEAF_CURRENT)
{
res_Leaf[k] = m_tree[res_Leaf[k]].m_leaves[result];
res_side[k] = result;
if (res_Leaf[k] == LEAF_CURRENT)
{
res_total++;
res_nb[result]++;
}
}
else
{
res_Leaf[k] = LEAF_CURRENT;
res_side[k] = LEAF_CURRENT;
res_total++;
}
}
}
}
int k = 0;
if (res_nb[LEAF_BACK] && res_nb[LEAF_FRONT])
{
res_total = res_total;
tri_list[i].m1 = LEAF_BACK;
#if 0
tri_to_process.Push( Array< int >(), tri_list[i].m2, tri_list[i].m3, tri_list[i].m4, 0);
tri_to_process.Last().m1.Push(0);
tri_list.Remove(i--);
break;
#endif
}
else
{
for (; k < TEST_MAX; k++)
{
if (res_side[k] != LEAF_CURRENT)
{
tri_list[i].m1 = res_side[k];
break;
}
}
if (k == TEST_MAX)
tri_list[i].m1 = LEAF_FRONT;
}
}
}

if (tri_list.Count() == 1)
return 0;
return 1;
}

} /* namespace lol */


+ 78
- 0
src/easymesh/csgbsp.h View File

@@ -0,0 +1,78 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2010-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

//
// The EasyMesh class
// ------------------
//

#if !defined __CSGBSP_CSGBSP_H__
#define __CSGBSP_CSGBSP_H__

namespace lol
{

#define LEAF_ABOVE 2
#define LEAF_FRONT 1
#define LEAF_BACK 0
#define LEAF_CURRENT -1

//Naïve bsp for the poor people
class CsgBspLeaf
{
friend class CsgBsp;

public:
CsgBspLeaf(vec3 origin, vec3 normal, int above_idx)
{
m_origin = origin;
m_normal = normal;
m_leaves[LEAF_ABOVE] = above_idx;

m_leaves[LEAF_FRONT] = -1;
m_leaves[LEAF_BACK] = -1;
}

private:
vec3 m_origin;
vec3 m_normal;
Array< int, vec3, vec3, vec3 > m_tri_list;
ivec3 m_leaves;
};

//Naïve bsp for the poor people
class CsgBsp
{
public:
void AddTriangleToTree(int const &tri_idx, vec3 const &tri_v0, vec3 const &tri_v1, vec3 const &tri_v2);

//return 0 when no split has been done.
//return 1 when split has been done.
//return -1 when error.
int TestTriangleToTree(vec3 const &tri_v0, vec3 const &tri_v1, vec3 const &tri_v2,
//In order to easily build the actual vertices list afterward, this list stores each Vertices location and its source vertices & Alpha.
//<Point_Loc, Src_V0, Src_V1, Alpha> as { Point_Loc = Src_V0 + (Src_V1 - Src_V0) * Alpha; }
Array< vec3, int, int, float > &vert_list,
//This is the final triangle list : If Side_Status is LEAF_CURRENT, a new test will be done point by point.
//<{IN|OUT}side_status, v0, v1, v2>
Array< int, int, int, int > &tri_list);

private:
int AddLeaf(int leaf_type, vec3 origin, vec3 normal, int above_idx);
int TestPoint(int leaf_idx, vec3 point);

Array<CsgBspLeaf> m_tree;
};

} /* namespace lol */

#endif /* __CSGBSP_CSGBSP_H__ */


+ 3
- 3
src/easymesh/easymesh-compiler.cpp View File

@@ -1,9 +1,9 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See


+ 3
- 3
src/easymesh/easymesh-compiler.h View File

@@ -1,9 +1,9 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See


+ 27
- 22
src/easymesh/easymesh-parser.y View File

@@ -2,9 +2,9 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -48,6 +48,7 @@
%token T_TRANSLATEY T_ROTATEY T_TAPERY T_SCALEY T_MIRRORY
%token T_TRANSLATEZ T_ROTATEZ T_TAPERZ T_SCALEZ T_MIRRORZ
%token T_TRANSLATE T_SCALE T_TOGGLESCALEWINDING
%token T_CSGUNION T_CSGSUBSTRACT T_CSGAND T_CSGXOR
%token T_CHAMFER

%token T_CYLINDER T_BOX T_SMOOTHCHAMFBOX T_FLATCHAMFBOX T_SPHERE T_CAPSULE
@@ -116,25 +117,29 @@ color_command:
;

transform_command:
T_CHAMFER args1 { mc.m_mesh.Chamfer($2.f0); }
| T_TRANSLATEX args1 { mc.m_mesh.Translate(vec3($2.f0, 0, 0)); }
| T_TRANSLATEY args1 { mc.m_mesh.Translate(vec3(0, $2.f0, 0)); }
| T_TRANSLATEZ args1 { mc.m_mesh.Translate(vec3(0, 0, $2.f0)); }
| T_TRANSLATE args3 { mc.m_mesh.Translate(vec3($2.f0, $2.f1, $2.f2)); }
| T_ROTATEX args1 { mc.m_mesh.RotateX($2.f0); }
| T_ROTATEY args1 { mc.m_mesh.RotateY($2.f0); }
| T_ROTATEZ args1 { mc.m_mesh.RotateZ($2.f0); }
| T_TAPERX args3 { mc.m_mesh.TaperX($2.f0, $2.f1, $2.f2); }
| T_TAPERY args3 { mc.m_mesh.TaperY($2.f0, $2.f1, $2.f2); }
| T_TAPERZ args3 { mc.m_mesh.TaperZ($2.f0, $2.f1, $2.f2); }
| T_SCALEX args1 { mc.m_mesh.Scale(vec3($2.f0, 1.0, 1.0)); }
| T_SCALEY args1 { mc.m_mesh.Scale(vec3(1.0, $2.f0, 1.0)); }
| T_SCALEZ args1 { mc.m_mesh.Scale(vec3(1.0, 1.0, $2.f0)); }
| T_SCALE args3 { mc.m_mesh.Scale(vec3($2.f0, $2.f1, $2.f2)); }
| T_MIRRORX { mc.m_mesh.MirrorX(); }
| T_MIRRORY { mc.m_mesh.MirrorY(); }
| T_MIRRORZ { mc.m_mesh.MirrorZ(); }
| T_TOGGLESCALEWINDING { mc.m_mesh.ToggleScaleWinding(); }
T_CHAMFER args1 { mc.m_mesh.Chamfer($2.f0); }
| T_TRANSLATEX args1 { mc.m_mesh.Translate(vec3($2.f0, 0, 0)); }
| T_TRANSLATEY args1 { mc.m_mesh.Translate(vec3(0, $2.f0, 0)); }
| T_TRANSLATEZ args1 { mc.m_mesh.Translate(vec3(0, 0, $2.f0)); }
| T_TRANSLATE args3 { mc.m_mesh.Translate(vec3($2.f0, $2.f1, $2.f2)); }
| T_ROTATEX args1 { mc.m_mesh.RotateX($2.f0); }
| T_ROTATEY args1 { mc.m_mesh.RotateY($2.f0); }
| T_ROTATEZ args1 { mc.m_mesh.RotateZ($2.f0); }
| T_TAPERX args3 { mc.m_mesh.TaperX($2.f0, $2.f1, $2.f2); }
| T_TAPERY args3 { mc.m_mesh.TaperY($2.f0, $2.f1, $2.f2); }
| T_TAPERZ args3 { mc.m_mesh.TaperZ($2.f0, $2.f1, $2.f2); }
| T_SCALEX args1 { mc.m_mesh.Scale(vec3($2.f0, 1.0, 1.0)); }
| T_SCALEY args1 { mc.m_mesh.Scale(vec3(1.0, $2.f0, 1.0)); }
| T_SCALEZ args1 { mc.m_mesh.Scale(vec3(1.0, 1.0, $2.f0)); }
| T_SCALE args3 { mc.m_mesh.Scale(vec3($2.f0, $2.f1, $2.f2)); }
| T_MIRRORX { mc.m_mesh.MirrorX(); }
| T_MIRRORY { mc.m_mesh.MirrorY(); }
| T_MIRRORZ { mc.m_mesh.MirrorZ(); }
| T_TOGGLESCALEWINDING { mc.m_mesh.ToggleScaleWinding(); }
| T_CSGUNION { mc.m_mesh.CsgUnion(); }
| T_CSGSUBSTRACT { mc.m_mesh.CsgSubstract(); }
| T_CSGAND { mc.m_mesh.CsgAnd(); }
| T_CSGXOR { mc.m_mesh.CsgXor(); }
;

primitive_command:


+ 8
- 3
src/easymesh/easymesh-scanner.l View File

@@ -2,9 +2,9 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -71,6 +71,11 @@ mx { return token::T_MIRRORX; }
my { return token::T_MIRRORY; }
mz { return token::T_MIRRORZ; }

csgu { return token::T_CSGUNION; }
csgs { return token::T_CSGSUBSTRACT; }
csga { return token::T_CSGAND; }
csgx { return token::T_CSGXOR; }

ab { return token::T_BOX; }
ac { return token::T_CYLINDER; }
acap { return token::T_CAPSULE; }


+ 406
- 9
src/easymesh/easymesh.cpp View File

@@ -1,9 +1,9 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -75,7 +75,7 @@ void EasyMesh::MeshConvert(Shader* provided_shader)

m_gpu.modelview = m_gpu.shader->GetUniformLocation("in_ModelView");
m_gpu.view = m_gpu.shader->GetUniformLocation("in_View");
m_gpu.invview = m_gpu.shader->GetUniformLocation("in_Inv_View");
m_gpu.invview = m_gpu.shader->GetUniformLocation("in_Inv_View");
m_gpu.proj = m_gpu.shader->GetUniformLocation("in_Proj");
m_gpu.normalmat = m_gpu.shader->GetUniformLocation("in_NormalMat");
m_gpu.damage = m_gpu.shader->GetUniformLocation("in_Damage");
@@ -141,6 +141,403 @@ void EasyMesh::Render(mat4 const &model, float damage)
m_gpu.vdecl->Unbind();
}


//-------------------
// "Collisions" functions
//-------------------
#define VX_ALONE -2
#define VX_MASTER -1

//helpers func to retrieve a vertex.
int FindVertexInDict(int search_idx, Array< int, int > const &vertex_dict)
{
//Resolve current vertex idx in the dictionnary (if exist)
for (int j = 0; j < vertex_dict.Count(); j++)
if (vertex_dict[j].m1 == search_idx)
return j;
return -1;
}

//helpers func to retrieve a triangle.
int FindTriangleInDict(int search_idx, Array< int, Array< vec3, vec3, vec3 > > const &triangle_isec)
{
//Resolve current vertex idx in the dictionnary (if exist)
for (int j = 0; j < triangle_isec.Count(); j++)
if (triangle_isec[j].m1 == search_idx)
return j;
return -1;
}

//Will update the given list with all the vertices on the same spot.
void EasyMesh::UpdateVertexDict(Array< int, int > &vertex_dict)
{
//First, build the vertex Dictionnary
for (int i = 0; i < m_vert.Count(); i++)
{
int CurIdx = FindVertexInDict(i, vertex_dict);
//go through all vertices and do the match-up.
if (CurIdx == -1)
{
for (int j = i + 1; j < m_vert.Count(); j++)
{
if (sqlength(m_vert[i].m1 - m_vert[j].m1) < CSG_EPSILON)
{
if (CurIdx == -1)
{
CurIdx = vertex_dict.Count();
vertex_dict.Push(i, VX_MASTER);
}
vertex_dict.Push(j, CurIdx);
}
}
}
}
}

void EasyMesh::MeshCsg(int csg_operation)
{
//A vertex dictionnary for vertices on the same spot.
Array< int, int > vertex_dict;
//This list keeps track of the triangle that will need deletion at the end.
Array< int > triangle_to_kill;
//Listing for each triangle of the vectors intersecting it. <tri_Id, <Point0, Point1, tri_isec_Normal>>
Array< int, Array< vec3, vec3, vec3 > > triangle_isec;
//keep a track of the intersection point on the triangle. <pos, side_id>
Array< vec3, int > triangle_vertex;
for (int k = 0; k < 10; k++)
triangle_vertex.Push(vec3(.0f), 0);

//bsp infos
CsgBsp mesh_bsp_0;
CsgBsp mesh_bsp_1;

//BSP BUILD : We use the brace logic, csg should be used as : "[ exp .... [exp .... csg]]"
int cursor_start = (m_cursors.Count() < 2)?(0):(m_cursors[(m_cursors.Count() - 2)].m2);
for (int mesh_id = 0; mesh_id < 2; mesh_id++)
{
int start_point = (mesh_id == 0)?(cursor_start):(m_cursors.Last().m2);
int end_point = (mesh_id == 0)?(m_cursors.Last().m2):(m_indices.Count());
CsgBsp &mesh_bsp = (mesh_id == 0)?(mesh_bsp_0):(mesh_bsp_1);
for (int i = start_point; i < end_point; i += 3)
mesh_bsp.AddTriangleToTree(i, m_vert[m_indices[i]].m1, m_vert[m_indices[i + 1]].m1, m_vert[m_indices[i + 2]].m1);
}

//BSP Useage : let's crunch all triangles on the correct BSP
int indices_count = m_indices.Count();
for (int mesh_id = 0; mesh_id < 2; mesh_id++)
{
int start_point = (mesh_id == 0)?(cursor_start):(m_cursors.Last().m2);
int end_point = (mesh_id == 0)?(m_cursors.Last().m2):(indices_count);
CsgBsp &mesh_bsp = (mesh_id == 0)?(mesh_bsp_1):(mesh_bsp_0);
Array< vec3, int, int, float > vert_list;
Array< int, int, int, int > tri_list;
vec3 n0(.0f); vec3 n1(.0f);
vec4 c0(.0f); vec4 c1(.0f);

//Reserve some memory
vert_list.Reserve(3);
tri_list.Reserve(3);

for (int i = start_point; i < end_point; i += 3)
{
int Result = mesh_bsp.TestTriangleToTree(m_vert[m_indices[i]].m1, m_vert[m_indices[i + 1]].m1, m_vert[m_indices[i + 2]].m1, vert_list, tri_list);
int tri_base_idx = m_indices.Count();

//one split has been done, we need to had the new vertices & the new triangles.
if (Result == 1)
{
triangle_to_kill.Push(i);
#if 1
int base_idx = m_vert.Count();
for (int k = 3; k < vert_list.Count(); k++)
{
int P0 = (vert_list[k].m2 < 3)?(m_indices[i + vert_list[k].m2]):(base_idx + vert_list[k].m2 - 3);
int P1 = (vert_list[k].m3 < 3)?(m_indices[i + vert_list[k].m3]):(base_idx + vert_list[k].m3 - 3);

AddVertex(vert_list[k].m1);

//Normal : bad calculations there.
n0 = m_vert[P0].m2;
n1 = m_vert[P1].m2;
SetCurVertNormal(normalize(n0 + (n1 - n0) * vert_list[k].m4));

#if 1
//Color
c0 = m_vert[P0].m3;
c1 = m_vert[P1].m3;
vec4 res = c0 + ((c1 - c0) * vert_list[k].m4);
SetCurVertColor(res);
#else
if (mesh_id == 0)
SetCurVertColor(vec4(1.0f, .0f, .0f, 1.0f));
else
SetCurVertColor(vec4(.0f, 1.0f, 1.0f, 1.0f));
#endif
}
for (int k = 0; k < tri_list.Count(); k++)
{
int P0 = (tri_list[k].m2 < 3)?(m_indices[i + tri_list[k].m2]):(base_idx + (tri_list[k].m2 - 3));
int P1 = (tri_list[k].m3 < 3)?(m_indices[i + tri_list[k].m3]):(base_idx + (tri_list[k].m3 - 3));
int P2 = (tri_list[k].m4 < 3)?(m_indices[i + tri_list[k].m4]):(base_idx + (tri_list[k].m4 - 3));
AppendTriangle(P0, P1, P2, 0);
}
#endif
}
#if 1
//Main case
if (Result >= 0)
{
for (int k = 0; k < tri_list.Count(); k++)
{
int tri_idx = ((tri_list.Count() == 1)?(i):(tri_base_idx + k * 3));

//Triangle Kill Test
if (//csgu : CSGUnion() -> m0_Outside + m1_Outside
(csg_operation == CSG_UNION && tri_list[k].m1 == LEAF_BACK) ||
//csgs : CSGSubstract() -> m0_Outside + m1_Inside-inverted
(csg_operation == CSG_SUBSTRACT &&
((mesh_id == 0 && tri_list[k].m1 == LEAF_BACK) ||
(mesh_id == 1 && tri_list[k].m1 == LEAF_FRONT))) ||
//csga : CSGAnd() -> Inside + Inside
(csg_operation == CSG_AND && tri_list[k].m1 == LEAF_FRONT))
{
triangle_to_kill.Push(tri_idx);
}

//Triangle Invert Test
if (//csgs : CSGSubstract() -> m0_Outside + m1_Inside-inverted
(csg_operation == CSG_SUBSTRACT && mesh_id == 1 && tri_list[k].m1 == LEAF_BACK) ||
//csgx : CSGXor() -> Outside/Inside-inverted + Outside/Inside-inverted
(csg_operation == CSG_XOR && tri_list[k].m1 == LEAF_BACK))
{
//a Xor means we will share vertices with the outside, so duplicate the vertices.
//TODO : This operation disconnect all triangle, in some cases, not a good thing.
if (csg_operation == CSG_XOR)
{
for (int l = 0; l < 3; l++)
{
AddDuplicateVertex(m_indices[tri_idx + l]);
m_indices[tri_idx + l] = m_vert.Count() - 1;
}
}
m_indices[tri_idx + 1] += m_indices[tri_idx + 2];
m_indices[tri_idx + 2] = m_indices[tri_idx + 1] - m_indices[tri_idx + 2];
m_indices[tri_idx + 1] = m_indices[tri_idx + 1] - m_indices[tri_idx + 2];
ComputeNormals(tri_idx, 3);
}
}
}
#endif
vert_list.Empty();
tri_list.Empty();
}
}

for (int i = 0; i < m_vert.Count(); i++)
if (length(m_vert[i].m2) < 1.0f)
i = i;

int dir = 1;
for (int i = 0; i >= 0 && i < triangle_to_kill.Count() - 1; i += dir)
{
if (triangle_to_kill[i] < triangle_to_kill[i + 1] && dir < 0)
dir = 1;
if (triangle_to_kill[i] == triangle_to_kill[i + 1])
{
triangle_to_kill.Remove(i);
dir = -1;
}
if (triangle_to_kill[i] > triangle_to_kill[i + 1])
{
triangle_to_kill[i] += triangle_to_kill[i + 1];
triangle_to_kill[i + 1] = triangle_to_kill[i] - triangle_to_kill[i + 1];
triangle_to_kill[i] = triangle_to_kill[i] - triangle_to_kill[i + 1];
dir = -1;
}
if (i == 0 && dir == -1)
dir = 1;
}
for (int i = triangle_to_kill.Count() - 1; i >= 0; i--)
m_indices.Remove(triangle_to_kill[i], 3);

m_cursors.Last().m1 = m_vert.Count();
m_cursors.Last().m2 = m_indices.Count();

#if 0
UpdateVertexDict(vertex_dict);

for (int t0 = 0; t0 < m_indices.Count(); t0 += 3)
{
for (int t1 = t0 + 3; t1 < m_indices.Count(); t1 += 3)
{
int CommonVertices = 0;
//Search for common vertices, if > 1 the two triangle share a side, so no split is required.
for (int k = 0; k < 3; k++)
{
int ref_master = FindVertexInDict(m_indices[t0 + k], vertex_dict);
if (ref_master != -1)
{
if (vertex_dict[ref_master].m2 != VX_MASTER)
ref_master = vertex_dict[ref_master].m2;
for (int l = 0; l < 3; l++)
{
int test_master = FindVertexInDict(m_indices[t1 + l], vertex_dict);
if (test_master != -1)
{
if (vertex_dict[test_master].m2 != VX_MASTER)
test_master = vertex_dict[test_master].m2;
if (test_master == ref_master)
{
CommonVertices++;
break;
}
}
}
}
}

if (CommonVertices < 2)
{
vec3 iP0, iP1;
//Build the triangle intersection list
if (TriangleIsectTriangle(m_vert[m_indices[t0]].m1, m_vert[m_indices[t0 + 1]].m1, m_vert[m_indices[t0 + 2]].m1,
m_vert[m_indices[t1]].m1, m_vert[m_indices[t1 + 1]].m1, m_vert[m_indices[t1 + 2]].m1,
iP0, iP1))
{
int CurIdx = FindTriangleInDict(t0, triangle_isec);
if (CurIdx == -1)
{
CurIdx = triangle_isec.Count();
triangle_isec.Push(t0, Array<vec3, vec3, vec3>());
}
triangle_isec[CurIdx].m2.Push(iP0, iP1, vec3(.0f));
CurIdx = FindTriangleInDict(t1, triangle_isec);
if (CurIdx == -1)
{
CurIdx = triangle_isec.Count();
triangle_isec.Push(t1, Array<vec3, vec3, vec3>());
}
triangle_isec[CurIdx].m2.Push(iP0, iP1, vec3(.0f));
}
}
}
}

/* seems to be counter-productive in some rare cases. */
/*
//Every intersection has been found, let's remove those that exist twice.
for(int i = 0; i < triangle_isec.Count(); i++)
{
for(int j = 0; j < triangle_isec[i].m2.Count(); j++)
{
for(int k = j + 1; k < triangle_isec[i].m2.Count(); k++)
{
//if the two Dir-vector are parallel & the fist Dir-vector is parallel to the (P0, P1)-vector, this is the same intersection, so kill it.
if (abs(dot(normalize(triangle_isec[i].m2[j].m2 - triangle_isec[i].m2[j].m1),
normalize(triangle_isec[i].m2[k].m2 - triangle_isec[i].m2[k].m1)))
>= 1.0 &&
abs(dot(normalize(triangle_isec[i].m2[j].m2 - triangle_isec[i].m2[j].m1),
normalize(triangle_isec[i].m2[k].m1 - triangle_isec[i].m2[j].m1)))
>= 1.0 )
triangle_isec[i].m2.Remove(k--);
}
}
}
*/

//Now, the triangle intersection tab should be nice and cosy, so we can start actually cutting some triangles.
vec3 isecV[2] = { vec3(.0f), vec3(.0f) };
int isecI[2] = { -1, -1 };
int v_idx0 = 0; int v_idx1 = 0;
int new_v_idx[2] = { 0, 0 };
vec3 n0(.0f); vec3 n1(.0f);
vec4 c0(.0f); vec4 c1(.0f);
for(int i = 0; i < triangle_isec.Count(); i++)
{
int tri_idx = triangle_isec[i].m1;
for(int j = 0; j < triangle_isec[i].m2.Count(); j++)
{
//Get intersection on actual triangle sides.
if (RayIsectTriangleSide(m_vert[m_indices[tri_idx]].m1, m_vert[m_indices[tri_idx + 1]].m1, m_vert[m_indices[tri_idx + 2]].m1,
triangle_isec[i].m2[j].m1, triangle_isec[i].m2[j].m2,
isecV[0], isecI[0], isecV[1], isecI[1]))
{
//Check if the found intersections point are in the triangle. If not, ignore.
//Cases are :
// 1) at least one dot is negative (one point in the triangle).
// 2) the two dot are positive but the intersection point are on all parts of the triangle, and therefore negative.
//If one of the point is on one side, some calculations tweak are needed.
//If the two points are on the triangle sides, just go with it.
bool should_proceed_with_cutting = true;
//find out if points are on one of the side
int p0_tri_idx = ((sqlength(triangle_isec[i].m2[j].m1 - isecV[0]) < CSG_EPSILON)?(0):(
(sqlength(triangle_isec[i].m2[j].m1 - isecV[1]) < CSG_EPSILON)?(1):(-1)));
int p1_tri_idx = ((sqlength(triangle_isec[i].m2[j].m2 - isecV[0]) < CSG_EPSILON)?(0):(
(sqlength(triangle_isec[i].m2[j].m2 - isecV[1]) < CSG_EPSILON)?(1):(-1)));
if (p0_tri_idx < 0 || p1_tri_idx < 0)
{
float dot0 = (p0_tri_idx >= 0)?(1.0f):(dot(triangle_isec[i].m2[j].m1 - isecV[0],
triangle_isec[i].m2[j].m1 - isecV[1]));
float dot1 = (p1_tri_idx >= 0)?(1.0f):(dot(triangle_isec[i].m2[j].m2 - isecV[0],
triangle_isec[i].m2[j].m2 - isecV[1]));
float dot2 = dot(triangle_isec[i].m2[j].m1 - isecV[(p0_tri_idx == -1)?(0):(1 - p0_tri_idx)],
triangle_isec[i].m2[j].m2 - isecV[(p1_tri_idx == -1)?(0):(1 - p1_tri_idx)]);
should_proceed_with_cutting = (((dot0 < .0f) || dot1 < .0f) || (dot0 > .0f && dot1 > .0f && dot2 < .0f));
}
if (should_proceed_with_cutting)
{
//Add the new vertices
int b_idx = 0;
for(int k = 0; k < 2; k++)
{
if (b_idx == isecI[k])
b_idx++;

new_v_idx[k] = m_vert.Count();
AddVertex(isecV[k]);
//bad calculations of normal there.
n0 = m_vert[m_indices[tri_idx + isecI[k]]].m2;
n1 = m_vert[m_indices[tri_idx + (isecI[k] + 1) % 3]].m2;
SetCurVertNormal(normalize((n0 + n1) * .5f));
//color
#if 0
c0 = m_vert[m_indices[tri_idx + isecI[k]]].m3;
c1 = m_vert[m_indices[tri_idx + (isecI[k] + 1) % 3]].m3;
SetCurVertColor((c0 + c1) * .5f);
#else
SetCurVertColor(vec4(1.0f, 0.0f, 0.0f, 1.0f));
#endif
}

//small trick, b_idx is the side index that has no intersection.
v_idx0 = (b_idx == 1)?(1):(0);
v_idx1 = (b_idx == 1)?(0):(1);

//Add the new triangles
AppendTriangle(m_indices[tri_idx + b_idx], new_v_idx[v_idx0], new_v_idx[v_idx1], 0);
AppendTriangle(m_indices[tri_idx + ((b_idx + 2) % 3)], new_v_idx[v_idx1], new_v_idx[v_idx0], 0);
//Replace the current triangle by on of the new one, instead of erasing it.
m_indices[tri_idx + ((b_idx + 2) % 3)] = new_v_idx[v_idx0];

if (j + 1 < triangle_isec[i].m2.Count())
{
triangle_isec[i].m2.Remove(j--);
//add the two new triangle to the checklist.
triangle_isec.Push(m_indices.Count() - 6, triangle_isec[i].m2);
triangle_isec.Push(m_indices.Count() - 3, triangle_isec[i].m2);
}
}
}
}
}
#endif
//DONE for the splitting !
}


//-------------------

void EasyMesh::ToggleScaleWinding()
{
m_ignore_winding_on_scale = !m_ignore_winding_on_scale;
@@ -434,7 +831,7 @@ void EasyMesh::AppendCapsule(int ndivisions, float h, float r)
/* Fill in the icosahedron vertices, rotating them so that there
* is a vertex at [0 1 0] and [0 -1 0] after normalisation. */
float phi = 0.5f + 0.5f * sqrt(5.f);
mat3 mat = mat3::rotate(asin(1.f / sqrt(2.f + phi)) * (180.f / M_PI),
mat3 mat = mat3::rotate(asin(1.f / sqrt(2.f + phi)) * (180.f / (float)M_PI),
vec3(0.f, 0.f, 1.f));
for (int i = 0; i < 4; i++)
{
@@ -538,12 +935,12 @@ void EasyMesh::AppendTorus(int ndivisions, float r1, float r2)
{
int i2 = (i + di) % nidiv;
int j2 = (j + dj) % njdiv;
float x = 0.5f * (r1 + r2) + 0.5 * (r2 - r1) * lol::cos(2.0 * M_PI * i2 / nidiv);
float y = 0.5f * (r2 - r1) * lol::sin(2.0 * M_PI * i2 / nidiv);
float x = 0.5f * (r1 + r2) + 0.5f * (r2 - r1) * (float)lol::cos(2.0 * M_PI * i2 / nidiv);
float y = 0.5f * (r2 - r1) * (float)lol::sin(2.0 * M_PI * i2 / nidiv);
float z = 0.0f;

float ca = lol::cos(2.0 * M_PI * j2 / njdiv);
float sa = lol::sin(2.0 * M_PI * j2 / njdiv);
float ca = (float)lol::cos(2.0 * M_PI * j2 / njdiv);
float sa = (float)lol::sin(2.0 * M_PI * j2 / njdiv);
float x2 = x * ca - z * sa;
float z2 = z * ca + x * sa;



+ 23
- 5
src/easymesh/easymesh.h View File

@@ -1,9 +1,9 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -32,10 +32,26 @@ public:
void MeshConvert(Shader* ProvidedShader = NULL);
void Render(mat4 const &model, float damage = 0.f);

private:
void UpdateVertexDict(Array< int, int > &vertex_dict);
//DEBUG
public:
#define CSG_UNION 0
#define CSG_SUBSTRACT 1
#define CSG_AND 2
#define CSG_XOR 3

void MeshCsg(int csg_operation);
void CsgUnion() { MeshCsg(CSG_UNION); }
void CsgSubstract() { MeshCsg(CSG_SUBSTRACT); }
void CsgAnd() { MeshCsg(CSG_AND); }
void CsgXor() { MeshCsg(CSG_XOR); }

public:
void OpenBrace();
void CloseBrace();

void ToggleScaleWinding();
void ToggleScaleWinding();
void SetCurColor(vec4 const &color);
void SetCurColor2(vec4 const &color);

@@ -92,9 +108,11 @@ public:
private:
vec4 m_color, m_color2;
Array<uint16_t> m_indices;
//<coord, norm, color>
Array<vec3, vec3, vec4> m_vert;
//<vert count, indices count>
Array<int, int> m_cursors;
bool m_ignore_winding_on_scale;
bool m_ignore_winding_on_scale;

/* FIXME: put this in a separate class so that we can copy meshes. */
struct


+ 1
- 1
src/easymesh/shiny.lolfx View File

@@ -65,7 +65,7 @@ void main(void)

/* World properties */
float ambient_mul = 0.5;
vec3 ambient_color = vec3(0.0, 0.0, 0.0);
vec3 ambient_color = vec3(0.5, 0.5, 0.5);
vec3 diffuse_color = vec3(0.4, 0.4, 0.4);
vec3 specular_color = vec3(1.0, 1.0, 0.6);



+ 340
- 405
src/generated/easymesh-parser.cpp
File diff suppressed because it is too large
View File


+ 67
- 36
src/generated/easymesh-parser.h View File

@@ -1,8 +1,8 @@
/* A Bison parser, made by GNU Bison 2.5. */
/* A Bison parser, made by GNU Bison 2.4.2. */

/* Skeleton interface for Bison LALR(1) parsers in C++
Copyright (C) 2002-2011 Free Software Foundation, Inc.
Copyright (C) 2002-2010 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -40,6 +40,20 @@
#include <string>
#include <iostream>
#include "stack.hh"


namespace lol {

/* Line 34 of lalr1.cc */
#line 49 "generated/easymesh-parser.h"
class position;
class location;

} // lol

/* Line 34 of lalr1.cc */
#line 56 "generated/easymesh-parser.h"

#include "location.hh"

/* Enabling traces. */
@@ -60,11 +74,30 @@
# define YYTOKEN_TABLE 0
#endif

/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
If N is 0, then set CURRENT to the empty location which ends
the previous symbol: RHS[0] (always defined). */

#ifndef YYLLOC_DEFAULT
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (N) \
{ \
(Current).begin = (Rhs)[1].begin; \
(Current).end = (Rhs)[N].end; \
} \
else \
{ \
(Current).begin = (Current).end = (Rhs)[0].end; \
} \
} while (false)
#endif


namespace lol {

/* Line 35 of lalr1.cc */
#line 68 "generated/easymesh-parser.h"
/* Line 34 of lalr1.cc */
#line 101 "generated/easymesh-parser.h"

/// A Bison parser.
class EasyMeshParser
@@ -75,7 +108,7 @@ namespace lol {
union semantic_type
{

/* Line 35 of lalr1.cc */
/* Line 34 of lalr1.cc */
#line 36 "easymesh/easymesh-parser.y"

float fval;
@@ -85,8 +118,8 @@ namespace lol {



/* Line 35 of lalr1.cc */
#line 90 "generated/easymesh-parser.h"
/* Line 34 of lalr1.cc */
#line 123 "generated/easymesh-parser.h"
};
#else
typedef YYSTYPE semantic_type;
@@ -119,23 +152,27 @@ namespace lol {
T_TRANSLATE = 275,
T_SCALE = 276,
T_TOGGLESCALEWINDING = 277,
T_CHAMFER = 278,
T_CYLINDER = 279,
T_BOX = 280,
T_SMOOTHCHAMFBOX = 281,
T_FLATCHAMFBOX = 282,
T_SPHERE = 283,
T_CAPSULE = 284,
T_STAR = 285,
T_EXPANDEDSTAR = 286,
T_DISC = 287,
T_TRIANGLE = 288,
T_QUAD = 289,
T_COG = 290,
T_TORUS = 291,
T_ERROR = 292,
NUMBER = 293,
COLOR = 294
T_CSGUNION = 278,
T_CSGSUBSTRACT = 279,
T_CSGAND = 280,
T_CSGXOR = 281,
T_CHAMFER = 282,
T_CYLINDER = 283,
T_BOX = 284,
T_SMOOTHCHAMFBOX = 285,
T_FLATCHAMFBOX = 286,
T_SPHERE = 287,
T_CAPSULE = 288,
T_STAR = 289,
T_EXPANDEDSTAR = 290,
T_DISC = 291,
T_TRIANGLE = 292,
T_QUAD = 293,
T_COG = 294,
T_TORUS = 295,
T_ERROR = 296,
NUMBER = 297,
COLOR = 298
};

};
@@ -209,14 +246,6 @@ namespace lol {
/// The location stack.
location_stack_type yylocation_stack_;

/// Whether the given \c yypact_ value indicates a defaulted state.
/// \param yyvalue the value to check
static bool yy_pact_value_is_default_ (int yyvalue);

/// Whether the given \c yytable_ value indicates a syntax error.
/// \param yyvalue the value to check
static bool yy_table_value_is_error_ (int yyvalue);

/// Internal symbol numbers.
typedef unsigned char token_number_type;
/* Tables. */
@@ -224,7 +253,7 @@ namespace lol {
static const signed char yypact_[];
static const signed char yypact_ninf_;

/// For a state, default reduction number.
/// For a state, default rule to reduce.
/// Unless\a yytable_ specifies something else to do.
/// Zero means the default is an error.
static const unsigned char yydefact_[];
@@ -255,8 +284,10 @@ namespace lol {
static const char* const yytname_[];
#endif

#if YYERROR_VERBOSE
/// Convert the symbol name \a n to a form suitable for a diagnostic.
static std::string yytnamerr_ (const char *n);
virtual std::string yytnamerr_ (const char *n);
#endif

#if YYDEBUG
/// A type to store symbol numbers and -1.
@@ -314,8 +345,8 @@ namespace lol {

} // lol

/* Line 35 of lalr1.cc */
#line 319 "generated/easymesh-parser.h"
/* Line 34 of lalr1.cc */
#line 350 "generated/easymesh-parser.h"





+ 140
- 118
src/generated/easymesh-scanner.cpp View File

@@ -330,8 +330,8 @@ typedef unsigned char YY_CHAR;
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;

#define YY_NUM_RULES 46
#define YY_END_OF_BUFFER 47
#define YY_NUM_RULES 50
#define YY_END_OF_BUFFER 51
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@@ -339,16 +339,16 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static yyconst flex_int16_t yy_accept[75] =
static yyconst flex_int16_t yy_accept[81] =
{ 0,
0, 0, 47, 45, 44, 43, 45, 45, 40, 45,
39, 41, 42, 45, 45, 45, 45, 17, 7, 0,
0, 39, 39, 0, 22, 23, 26, 0, 0, 29,
30, 33, 3, 19, 20, 21, 8, 9, 10, 1,
14, 15, 16, 0, 0, 4, 5, 6, 0, 0,
39, 0, 25, 27, 0, 0, 0, 34, 2, 11,
12, 13, 18, 35, 24, 28, 31, 32, 36, 0,
37, 0, 38, 0
0, 0, 51, 49, 48, 47, 49, 49, 44, 49,
43, 45, 46, 49, 49, 49, 49, 17, 7, 0,
0, 43, 43, 0, 26, 27, 30, 0, 0, 33,
34, 37, 3, 0, 19, 20, 21, 8, 9, 10,
1, 14, 15, 16, 0, 0, 4, 5, 6, 0,
0, 43, 0, 29, 31, 0, 0, 0, 38, 0,
2, 11, 12, 13, 18, 39, 28, 32, 35, 36,
24, 23, 22, 25, 40, 0, 41, 0, 42, 0
} ;

static yyconst flex_int32_t yy_ec[256] =
@@ -365,8 +365,8 @@ static yyconst flex_int32_t yy_ec[256] =
11, 1, 12, 1, 1, 1, 13, 14, 15, 16,

17, 18, 19, 20, 1, 1, 1, 1, 21, 1,
22, 23, 24, 25, 26, 27, 1, 1, 28, 29,
30, 31, 1, 1, 1, 1, 1, 1, 1, 1,
22, 23, 24, 25, 26, 27, 28, 1, 29, 30,
31, 32, 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,
@@ -383,76 +383,78 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1
} ;

static yyconst flex_int32_t yy_meta[32] =
static yyconst flex_int32_t yy_meta[33] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
1, 1, 2, 2, 2, 2, 2, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1
1, 1
} ;

static yyconst flex_int16_t yy_base[83] =
static yyconst flex_int16_t yy_base[89] =
{ 0,
0, 0, 102, 103, 103, 103, 0, 25, 27, 93,
29, 103, 103, 33, 80, 11, 14, 23, 48, 0,
91, 48, 54, 61, 103, 57, 103, 72, 82, 103,
57, 74, 103, 103, 103, 103, 103, 103, 103, 81,
103, 103, 103, 52, 66, 103, 103, 103, 0, 85,
84, 68, 103, 103, 76, 75, 68, 103, 103, 103,
103, 103, 103, 0, 103, 103, 103, 103, 0, 0,
0, 0, 103, 103, 85, 84, 83, 82, 73, 71,
66, 61
0, 0, 109, 110, 110, 110, 0, 26, 28, 100,
30, 110, 110, 34, 19, 11, 23, 41, 61, 0,
99, 58, 59, 72, 110, 44, 110, 80, 90, 110,
47, 82, 110, 84, 110, 110, 110, 110, 110, 110,
88, 110, 110, 110, 51, 71, 110, 110, 110, 0,
90, 88, 72, 110, 110, 80, 76, 69, 110, 71,
110, 110, 110, 110, 110, 0, 110, 110, 110, 110,
110, 110, 110, 110, 0, 0, 0, 0, 110, 110,
86, 84, 83, 77, 62, 57, 44, 42
} ;

static yyconst flex_int16_t yy_def[83] =
static yyconst flex_int16_t yy_def[89] =
{ 0,
74, 1, 74, 74, 74, 74, 75, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 76,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 77, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 78, 74, 74, 74, 74, 79, 80,
81, 82, 74, 0, 74, 74, 74, 74, 74, 74,
74, 74
80, 1, 80, 80, 80, 80, 81, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 82,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 83,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 84, 80, 80, 80, 80,
80, 80, 80, 80, 85, 86, 87, 88, 80, 0,
80, 80, 80, 80, 80, 80, 80, 80
} ;

static yyconst flex_int16_t yy_nxt[135] =
static yyconst flex_int16_t yy_nxt[143] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 4, 4,
12, 13, 14, 4, 15, 4, 4, 4, 4, 4,
16, 4, 4, 4, 17, 18, 19, 4, 4, 4,
4, 21, 22, 21, 22, 21, 22, 40, 24, 34,
35, 36, 37, 38, 39, 24, 25, 26, 27, 28,
29, 41, 42, 43, 21, 22, 30, 24, 31, 32,
44, 23, 73, 24, 24, 50, 50, 72, 51, 52,
24, 56, 71, 45, 70, 53, 46, 47, 48, 57,
60, 61, 62, 69, 64, 49, 20, 68, 67, 66,
65, 51, 51, 63, 59, 58, 55, 54, 23, 33,

23, 74, 3, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74
4, 4, 21, 22, 21, 22, 21, 22, 33, 24,
35, 36, 37, 79, 34, 78, 24, 25, 26, 27,
28, 29, 38, 39, 40, 41, 53, 30, 77, 31,
32, 57, 54, 76, 21, 22, 23, 24, 24, 58,
42, 43, 44, 45, 24, 24, 51, 51, 75, 52,
62, 63, 64, 71, 66, 50, 46, 20, 70, 69,
47, 48, 49, 68, 67, 52, 72, 52, 73, 65,

74, 61, 60, 59, 56, 55, 23, 23, 80, 3,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80
} ;

static yyconst flex_int16_t yy_chk[135] =
static yyconst flex_int16_t yy_chk[143] =
{ 0,
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, 8, 8, 9, 9, 11, 11, 18, 11, 16,
16, 16, 17, 17, 17, 11, 14, 14, 14, 14,
14, 18, 18, 18, 22, 22, 14, 22, 14, 14,
19, 23, 82, 23, 22, 24, 24, 81, 24, 26,
23, 31, 80, 19, 79, 26, 19, 19, 19, 31,
44, 44, 44, 78, 77, 76, 75, 57, 56, 55,
52, 51, 50, 45, 40, 32, 29, 28, 21, 15,

10, 3, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74
1, 1, 8, 8, 9, 9, 11, 11, 15, 11,
16, 16, 16, 88, 15, 87, 11, 14, 14, 14,
14, 14, 17, 17, 17, 18, 26, 14, 86, 14,
14, 31, 26, 85, 22, 22, 23, 22, 23, 31,
18, 18, 18, 19, 22, 23, 24, 24, 84, 24,
45, 45, 45, 60, 83, 82, 19, 81, 58, 57,
19, 19, 19, 56, 53, 52, 60, 51, 60, 46,

60, 41, 34, 32, 29, 28, 21, 10, 3, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80
} ;

/* The intent behind this definition is that it'll catch
@@ -467,9 +469,9 @@ static yyconst flex_int16_t yy_chk[135] =
//
// Lol Engine
//
// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2009-2013 Cédric Lecacheur <jordx@free.fr>
// (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -501,7 +503,7 @@ typedef lol::EasyMeshParser::token_type token_type;
#define yyterminate() return token::T_END
#define YY_NO_UNISTD_H
#define YY_USER_ACTION yylloc->columns(yyleng);
#line 505 "generated/easymesh-scanner.cpp"
#line 507 "generated/easymesh-scanner.cpp"

#define INITIAL 0

@@ -614,7 +616,7 @@ YY_DECL
yylloc->step();


#line 618 "generated/easymesh-scanner.cpp"
#line 620 "generated/easymesh-scanner.cpp"

if ( !(yy_init) )
{
@@ -667,13 +669,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 75 )
if ( yy_current_state >= 81 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp;
}
while ( yy_current_state != 74 );
while ( yy_current_state != 80 );
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);

@@ -801,71 +803,91 @@ YY_RULE_SETUP
case 22:
YY_RULE_SETUP
#line 74 "easymesh/easymesh-scanner.l"
{ return token::T_BOX; }
{ return token::T_CSGUNION; }
YY_BREAK
case 23:
YY_RULE_SETUP
#line 75 "easymesh/easymesh-scanner.l"
{ return token::T_CYLINDER; }
{ return token::T_CSGSUBSTRACT; }
YY_BREAK
case 24:
YY_RULE_SETUP
#line 76 "easymesh/easymesh-scanner.l"
{ return token::T_CAPSULE; }
{ return token::T_CSGAND; }
YY_BREAK
case 25:
YY_RULE_SETUP
#line 77 "easymesh/easymesh-scanner.l"
{ return token::T_COG; }
{ return token::T_CSGXOR; }
YY_BREAK
case 26:
YY_RULE_SETUP
#line 78 "easymesh/easymesh-scanner.l"
{ return token::T_DISC; }
#line 79 "easymesh/easymesh-scanner.l"
{ return token::T_BOX; }
YY_BREAK
case 27:
YY_RULE_SETUP
#line 79 "easymesh/easymesh-scanner.l"
{ return token::T_EXPANDEDSTAR; }
#line 80 "easymesh/easymesh-scanner.l"
{ return token::T_CYLINDER; }
YY_BREAK
case 28:
YY_RULE_SETUP
#line 80 "easymesh/easymesh-scanner.l"
{ return token::T_FLATCHAMFBOX; }
#line 81 "easymesh/easymesh-scanner.l"
{ return token::T_CAPSULE; }
YY_BREAK
case 29:
YY_RULE_SETUP
#line 81 "easymesh/easymesh-scanner.l"
{ return token::T_QUAD; }
#line 82 "easymesh/easymesh-scanner.l"
{ return token::T_COG; }
YY_BREAK
case 30:
YY_RULE_SETUP
#line 82 "easymesh/easymesh-scanner.l"
{ return token::T_STAR; }
#line 83 "easymesh/easymesh-scanner.l"
{ return token::T_DISC; }
YY_BREAK
case 31:
YY_RULE_SETUP
#line 83 "easymesh/easymesh-scanner.l"
{ return token::T_SMOOTHCHAMFBOX; }
#line 84 "easymesh/easymesh-scanner.l"
{ return token::T_EXPANDEDSTAR; }
YY_BREAK
case 32:
YY_RULE_SETUP
#line 84 "easymesh/easymesh-scanner.l"
{ return token::T_SPHERE; }
#line 85 "easymesh/easymesh-scanner.l"
{ return token::T_FLATCHAMFBOX; }
YY_BREAK
case 33:
YY_RULE_SETUP
#line 85 "easymesh/easymesh-scanner.l"
{ return token::T_TRIANGLE; }
#line 86 "easymesh/easymesh-scanner.l"
{ return token::T_QUAD; }
YY_BREAK
case 34:
YY_RULE_SETUP
#line 86 "easymesh/easymesh-scanner.l"
{ return token::T_TORUS; }
#line 87 "easymesh/easymesh-scanner.l"
{ return token::T_STAR; }
YY_BREAK
case 35:
YY_RULE_SETUP
#line 88 "easymesh/easymesh-scanner.l"
{ return token::T_SMOOTHCHAMFBOX; }
YY_BREAK
case 36:
YY_RULE_SETUP
#line 89 "easymesh/easymesh-scanner.l"
{ return token::T_SPHERE; }
YY_BREAK
case 37:
YY_RULE_SETUP
#line 90 "easymesh/easymesh-scanner.l"
{ return token::T_TRIANGLE; }
YY_BREAK
case 38:
YY_RULE_SETUP
#line 91 "easymesh/easymesh-scanner.l"
{ return token::T_TORUS; }
YY_BREAK
case 39:
YY_RULE_SETUP
#line 93 "easymesh/easymesh-scanner.l"
{
uint32_t tmp = std::strtol(yytext + 1, NULL, 16);
yylval->u32val = 0x11000000u * (tmp >> 8)
@@ -874,9 +896,9 @@ YY_RULE_SETUP
| 0x000000ffu;
return token::COLOR; }
YY_BREAK
case 36:
case 40:
YY_RULE_SETUP
#line 95 "easymesh/easymesh-scanner.l"
#line 100 "easymesh/easymesh-scanner.l"
{
uint32_t tmp = std::strtol(yytext + 1, NULL, 16);
yylval->u32val = 0x11000000u * (tmp >> 12)
@@ -885,64 +907,64 @@ YY_RULE_SETUP
| 0x00000011u * (tmp & 0xf);
return token::COLOR; }
YY_BREAK
case 37:
case 41:
YY_RULE_SETUP
#line 102 "easymesh/easymesh-scanner.l"
#line 107 "easymesh/easymesh-scanner.l"
{
yylval->u32val = 0xffu
| 0x100u * (uint32_t)std::strtol(yytext + 1, NULL, 16);
return token::COLOR; }
YY_BREAK
case 38:
case 42:
YY_RULE_SETUP
#line 106 "easymesh/easymesh-scanner.l"
#line 111 "easymesh/easymesh-scanner.l"
{
yylval->u32val = (uint32_t)std::strtol(yytext + 1, NULL, 16);
return token::COLOR; }
YY_BREAK
case 39:
case 43:
YY_RULE_SETUP
#line 109 "easymesh/easymesh-scanner.l"
#line 114 "easymesh/easymesh-scanner.l"
{
yylval->fval = std::atof(yytext); return token::NUMBER; }
YY_BREAK
case 40:
case 44:
YY_RULE_SETUP
#line 111 "easymesh/easymesh-scanner.l"
#line 116 "easymesh/easymesh-scanner.l"
{ return token_type('-'); }
YY_BREAK
case 41:
case 45:
YY_RULE_SETUP
#line 112 "easymesh/easymesh-scanner.l"
#line 117 "easymesh/easymesh-scanner.l"
{ return token_type('['); }
YY_BREAK
case 42:
case 46:
YY_RULE_SETUP
#line 113 "easymesh/easymesh-scanner.l"
#line 118 "easymesh/easymesh-scanner.l"
{ return token_type(']'); }
YY_BREAK
case 43:
case 47:
YY_RULE_SETUP
#line 114 "easymesh/easymesh-scanner.l"
#line 119 "easymesh/easymesh-scanner.l"
{ /* ignore this */ }
YY_BREAK
case 44:
/* rule 44 can match eol */
case 48:
/* rule 48 can match eol */
YY_RULE_SETUP
#line 115 "easymesh/easymesh-scanner.l"
#line 120 "easymesh/easymesh-scanner.l"
{ /* ignore this */ }
YY_BREAK
case 45:
case 49:
YY_RULE_SETUP
#line 116 "easymesh/easymesh-scanner.l"
#line 121 "easymesh/easymesh-scanner.l"
{ return token::T_ERROR; }
YY_BREAK
case 46:
case 50:
YY_RULE_SETUP
#line 118 "easymesh/easymesh-scanner.l"
#line 123 "easymesh/easymesh-scanner.l"
ECHO;
YY_BREAK
#line 946 "generated/easymesh-scanner.cpp"
#line 968 "generated/easymesh-scanner.cpp"
case YY_STATE_EOF(INITIAL):
yyterminate();

@@ -1324,7 +1346,7 @@ int yyFlexLexer::yy_get_next_buffer()
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 75 )
if ( yy_current_state >= 81 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1352,11 +1374,11 @@ int yyFlexLexer::yy_get_next_buffer()
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 75 )
if ( yy_current_state >= 81 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 74);
yy_is_jam = (yy_current_state == 80);

return yy_is_jam ? 0 : yy_current_state;
}
@@ -1843,7 +1865,7 @@ void EasyMeshfree (void * ptr )

#define YYTABLES_NAME "yytables"

#line 118 "easymesh/easymesh-scanner.l"
#line 123 "easymesh/easymesh-scanner.l"





+ 2
- 0
src/lolcore.vcxproj View File

@@ -240,6 +240,7 @@
<ClCompile Include="debug\record.cpp" />
<ClCompile Include="debug\stats.cpp" />
<ClCompile Include="dict.cpp" />
<ClCompile Include="easymesh\csgbsp.cpp" />
<ClCompile Include="easymesh\easymesh-compiler.cpp" />
<ClCompile Include="easymesh\easymesh.cpp" />
<ClCompile Include="eglapp.cpp" />
@@ -555,6 +556,7 @@
<ClInclude Include="debug\record.h" />
<ClInclude Include="debug\stats.h" />
<ClInclude Include="dict.h" />
<ClInclude Include="easymesh\csgbsp.h" />
<ClInclude Include="easymesh\easymesh-compiler.h" />
<ClInclude Include="easymesh\easymesh.h" />
<ClInclude Include="eglapp.h" />


+ 6
- 0
src/lolcore.vcxproj.filters View File

@@ -657,6 +657,9 @@
<ClCompile Include="math\geometry.cpp">
<Filter>math</Filter>
</ClCompile>
<ClCompile Include="easymesh\csgbsp.cpp">
<Filter>easymesh</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="image\image.h">
@@ -1634,6 +1637,9 @@
<ClInclude Include="lol\math\geometry.h">
<Filter>lol\math</Filter>
</ClInclude>
<ClInclude Include="easymesh\csgbsp.h">
<Filter>easymesh</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<LolFxCompile Include="gpu\emptymaterial.lolfx">


+ 35
- 20
tutorial/05_easymesh.cpp View File

@@ -1,7 +1,8 @@
//
// Lol Engine - EasyMesh tutorial
//
// Copyright: (c) 2011-2012 Sam Hocevar <sam@hocevar.net>
// Copyright: (c) 2011-2013 Sam Hocevar <sam@hocevar.net>
// (c) 2012-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -28,20 +29,30 @@ public:
m_gears.Push(EasyMesh(), mat4(1.0f), 180.0f / 18);
m_gears.Push(EasyMesh(), mat4(1.0f), 180.0f / 18);

m_gears[0].m1.Compile("sc#f9f scb#f9f acg 12 10 5 5 20 20 5 5 0.1 0 s .1 .1 .1");
m_gears[0].m1.Compile("[sc#00f ab 8 1 8 ty -.25]\
[sc#f9f scb#f9f acg 12 10 5 5 20 20 5 5 0.1 0 s .1 .1 .1 ty -.1 csgu]\
[sc#fff scb#000 acg 12 10 10 10 20 20 5 5 0.1 0 s .05 .05 .05 tx -1.5 ty .3 csgu]\
[sc#00f ab 5 3 9 tx 2.5 csgs]\
[[ sc#fff ab 3 1.4 2 tx -2 tz -2 \
[sc#fff ab 2.1 .7 1.1 ty .5 tx -1.4 tz -1.4 csgs] mz] csgu] \
");
//m_gears[0].m1.Compile("[sc#f9f scb#f9f acg 12 10 5 5 20 20 5 5 0.1 0 s .1 .1 .1 [sc#00f ab 3 1 2 ty .25 tx 1 csgs]]");
m_gears[1].m1.Compile("sc#ff9 scb#ff9 acg 54 10 95 95 90 90 -5 -5 0.1 0 s .1 .1 .1");
m_gears[2].m1.Compile("sc#9ff scb#9ff acg 18 10 5 5 30 30 5 5 0.1 0 s .1 .1 .1");
m_gears[3].m1.Compile("sc#9ff scb#9ff acg 18 10 5 5 30 30 5 5 0.1 0 s .1 .1 .1");
m_gears[4].m1.Compile("sc#9ff scb#9ff acg 18 10 5 5 30 30 5 5 0.1 0 s .1 .1 .1");
//m_gears[2].m1.Compile("sc#9ff scb#9ff acg 18 10 5 5 30 30 5 5 0.1 0 s .1 .1 .1 [sc#00f scb#00f ab 2 2 2 tx 1.5]");
//m_gears[3].m1.Compile("sc#9ff scb#9ff acg 18 10 5 5 30 30 5 5 0.1 0 s .1 .1 .1 [sc#00f scb#00f ab 2 2 2 tx 1.5]");
//m_gears[4].m1.Compile("sc#9ff scb#9ff acg 18 10 5 5 30 30 5 5 0.1 0 s .1 .1 .1 [sc#00f scb#00f ab 2 2 2 tx 1.5]");
m_gears[2].m1.Compile("[sc#0f0 ab 2 2 2 t .8 .8 .8 rx 20 ry 20 [sc#00f ab 2 2 2 tx 0 csgu]]");
m_gears[3].m1.Compile("[sc#0f0 ab 2 2 2 t .8 .8 .8 rx 20 ry 20 [sc#00f ab 2 2 2 tx 0 csgs]]");
m_gears[4].m1.Compile("[sc#0f0 ab 2 2 2 t .8 .8 .8 rx 20 ry 20 [sc#00f ab 2 2 2 tx 0 csga]]");

m_angle = 0;

m_camera = new Camera(vec3(0.f, 600.f, 0.f),
vec3(0.f, 0.f, 0.f),
vec3(0, 1, 0));
m_camera->SetPerspective(70.f, 960.f, 600.f, .1f, 1000.f);
m_camera->SetPerspective(30.f, 960.f, 600.f, .1f, 1000.f);
m_camera->SetTarget(vec3(0.f, -1.f, 0.f));
m_camera->SetPosition(vec3(-15.f, 10.f, 0.f));
m_camera->SetPosition(vec3(-15.f, 5.f, 0.f));
Ticker::Ref(m_camera);

m_ready = false;
@@ -58,24 +69,28 @@ public:

m_angle += seconds * 70.0f;
m_mat = mat4::rotate(10.0f, vec3(0, 0, 1))
* mat4::rotate(m_angle, vec3(0, 1, 0));

m_gears[0].m3 += seconds * 150.0f;
m_gears[1].m3 += seconds * 150.0f * -2 / 9;
m_gears[2].m3 += seconds * 150.0f * -2 / 3;
m_gears[3].m3 += seconds * 150.0f * -2 / 3;
m_gears[4].m3 += seconds * 150.0f * -2 / 3;

m_gears[0].m2 = mat4::translate(vec3(0, 0, 0))
* mat4::rotate(m_gears[0].m3, vec3(0, 1, 0));
* mat4::rotate(100, vec3(0, 1, 0));
// * mat4::rotate(m_angle, vec3(0, 1, 0));

m_gears[0].m3 += seconds * 20.0f;
m_gears[1].m3 += seconds * 20.0f * -2 / 9;
m_gears[2].m3 += seconds * 20.0f * -2 / 3;
m_gears[3].m3 += seconds * 20.0f * -2 / 3;
m_gears[4].m3 += seconds * 20.0f * -2 / 3;

m_gears[0].m2 = mat4::translate(vec3(0, -1, 0))
* mat4::rotate(m_gears[0].m3 - 130.0f, vec3(0, 1, 0))
* mat4::rotate(40.0f, vec3(0, 0, 1));
m_gears[1].m2 = mat4::translate(vec3(0, 0, 0))
* mat4::rotate(m_gears[1].m3, vec3(0, 1, 0));
m_gears[2].m2 = mat4::translate(vec3(0, 0, 5.5f))
* mat4::rotate(m_gears[2].m3, vec3(0, 1, 0));
* mat4::rotate(m_gears[2].m3 - 40.0f, vec3(0, 1, 0))
* mat4::rotate(90.0f, vec3(0, 0, 1));
m_gears[3].m2 = mat4::translate(vec3(5.5f * lol::sqrt(3.f) * 0.5f, 0, -5.5f * 0.5f))
* mat4::rotate(m_gears[3].m3, vec3(0, 1, 0));
* mat4::rotate(m_gears[3].m3 - 140.0f, vec3(0, 1, 0))
* mat4::rotate(-70.0f, vec3(0, 0, 1));
m_gears[4].m2 = mat4::translate(vec3(-5.5f * lol::sqrt(3.f) * 0.5f, 0, -5.5f * 0.5f))
* mat4::rotate(m_gears[4].m3, vec3(0, 1, 0));
* mat4::rotate(m_gears[4].m3 - 80.0f, vec3(0, 1, 0));
}

virtual void TickDraw(float seconds)


Loading…
Cancel
Save