From 4393a437522780b8875ba1113c124f9e738cc211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20=E2=80=98Touky=E2=80=99=20Huet?= Date: Thu, 17 Jan 2013 20:49:29 +0000 Subject: [PATCH] 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, CsgSubstract, CsgAnd, CsgXor 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. --- src/Makefile.am | 1 + src/core.h | 1 + src/easymesh/csgbsp.cpp | 553 +++++++++++++++++++++ src/easymesh/csgbsp.h | 78 +++ src/easymesh/easymesh-compiler.cpp | 6 +- src/easymesh/easymesh-compiler.h | 6 +- src/easymesh/easymesh-parser.y | 49 +- src/easymesh/easymesh-scanner.l | 11 +- src/easymesh/easymesh.cpp | 415 +++++++++++++++- src/easymesh/easymesh.h | 28 +- src/easymesh/shiny.lolfx | 2 +- src/generated/easymesh-parser.cpp | 745 +++++++++++++---------------- src/generated/easymesh-parser.h | 103 ++-- src/generated/easymesh-scanner.cpp | 258 +++++----- src/lolcore.vcxproj | 2 + src/lolcore.vcxproj.filters | 6 + tutorial/05_easymesh.cpp | 55 ++- 17 files changed, 1694 insertions(+), 625 deletions(-) create mode 100644 src/easymesh/csgbsp.cpp create mode 100644 src/easymesh/csgbsp.h diff --git a/src/Makefile.am b/src/Makefile.am index 5bfd6fc6..10cd1845 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/core.h b/src/core.h index 05ae07e1..8f147800 100644 --- a/src/core.h +++ b/src/core.h @@ -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 diff --git a/src/easymesh/csgbsp.cpp b/src/easymesh/csgbsp.cpp new file mode 100644 index 00000000..e262fce7 --- /dev/null +++ b/src/easymesh/csgbsp.cpp @@ -0,0 +1,553 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2010-2013 Benjamin "Touky" Huet +// 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 +# 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 +# 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) +{ + // + Array< int, vec3, vec3, vec3 > tri_to_process; + // + 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. + // 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. + // + 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 */ + diff --git a/src/easymesh/csgbsp.h b/src/easymesh/csgbsp.h new file mode 100644 index 00000000..4e4c16f6 --- /dev/null +++ b/src/easymesh/csgbsp.h @@ -0,0 +1,78 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2010-2013 Benjamin "Touky" Huet +// 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. + // 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 m_tree; +}; + +} /* namespace lol */ + +#endif /* __CSGBSP_CSGBSP_H__ */ + diff --git a/src/easymesh/easymesh-compiler.cpp b/src/easymesh/easymesh-compiler.cpp index 552fc71d..d7f92897 100644 --- a/src/easymesh/easymesh-compiler.cpp +++ b/src/easymesh/easymesh-compiler.cpp @@ -1,9 +1,9 @@ // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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 diff --git a/src/easymesh/easymesh-compiler.h b/src/easymesh/easymesh-compiler.h index cfaa129b..1d777062 100644 --- a/src/easymesh/easymesh-compiler.h +++ b/src/easymesh/easymesh-compiler.h @@ -1,9 +1,9 @@ // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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 diff --git a/src/easymesh/easymesh-parser.y b/src/easymesh/easymesh-parser.y index b0e6675c..988e1427 100644 --- a/src/easymesh/easymesh-parser.y +++ b/src/easymesh/easymesh-parser.y @@ -2,9 +2,9 @@ // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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: diff --git a/src/easymesh/easymesh-scanner.l b/src/easymesh/easymesh-scanner.l index f5af709c..e6cb5caa 100644 --- a/src/easymesh/easymesh-scanner.l +++ b/src/easymesh/easymesh-scanner.l @@ -2,9 +2,9 @@ // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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; } diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index f459c017..875d49b2 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -1,9 +1,9 @@ // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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. > + Array< int, Array< vec3, vec3, vec3 > > triangle_isec; + //keep a track of the intersection point on the triangle. + 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()); + } + 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()); + } + 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; diff --git a/src/easymesh/easymesh.h b/src/easymesh/easymesh.h index 08c8dfe9..29f19b9b 100644 --- a/src/easymesh/easymesh.h +++ b/src/easymesh/easymesh.h @@ -1,9 +1,9 @@ // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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 m_indices; + // Array m_vert; + // Array 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 diff --git a/src/easymesh/shiny.lolfx b/src/easymesh/shiny.lolfx index 26d453f8..7faf35af 100644 --- a/src/easymesh/shiny.lolfx +++ b/src/easymesh/shiny.lolfx @@ -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); diff --git a/src/generated/easymesh-parser.cpp b/src/generated/easymesh-parser.cpp index 19ce466c..ede49c8a 100644 --- a/src/generated/easymesh-parser.cpp +++ b/src/generated/easymesh-parser.cpp @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.4.2. */ /* Skeleton implementation 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 @@ -35,15 +35,15 @@ /* First part of user declarations. */ -/* Line 293 of lalr1.cc */ +/* Line 310 of lalr1.cc */ #line 1 "easymesh/easymesh-parser.y" // // Lol Engine // -// Copyright: (c) 2010-2012 Sam Hocevar -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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 @@ -61,7 +61,7 @@ -/* Line 293 of lalr1.cc */ +/* Line 310 of lalr1.cc */ #line 66 "generated/easymesh-parser.cpp" @@ -69,8 +69,8 @@ /* User implementation prologue. */ -/* Line 299 of lalr1.cc */ -#line 65 "easymesh/easymesh-parser.y" +/* Line 316 of lalr1.cc */ +#line 66 "easymesh/easymesh-parser.y" #include "easymesh/easymesh-compiler.h" @@ -78,7 +78,7 @@ #define yylex mc.m_lexer->lex -/* Line 299 of lalr1.cc */ +/* Line 316 of lalr1.cc */ #line 83 "generated/easymesh-parser.cpp" #ifndef YY_ @@ -93,26 +93,6 @@ # endif #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). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (N) \ - { \ - (Current).begin = YYRHSLOC (Rhs, 1).begin; \ - (Current).end = YYRHSLOC (Rhs, N).end; \ - } \ - else \ - { \ - (Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \ - } \ - while (false) -#endif - /* Suppress unused-variable warnings by "using" E. */ #define YYUSE(e) ((void) (e)) @@ -164,8 +144,9 @@ do { \ namespace lol { -/* Line 382 of lalr1.cc */ -#line 169 "generated/easymesh-parser.cpp" +/* Line 379 of lalr1.cc */ +#line 149 "generated/easymesh-parser.cpp" +#if YYERROR_VERBOSE /* Return YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is @@ -204,6 +185,7 @@ namespace lol { return yystr; } +#endif /// Build a parser object. EasyMeshParser::EasyMeshParser (class EasyMeshCompiler& mc_yyarg) @@ -304,18 +286,6 @@ namespace lol { } #endif - inline bool - EasyMeshParser::yy_pact_value_is_default_ (int yyvalue) - { - return yyvalue == yypact_ninf_; - } - - inline bool - EasyMeshParser::yy_table_value_is_error_ (int yyvalue) - { - return yyvalue == yytable_ninf_; - } - int EasyMeshParser::parse () { @@ -337,7 +307,7 @@ namespace lol { /// Location of the lookahead. location_type yylloc; /// The locations where the error started and ended. - location_type yyerror_range[3]; + location_type yyerror_range[2]; /// $$. semantic_type yyval; @@ -375,7 +345,7 @@ namespace lol { /* Try to take a decision without lookahead. */ yyn = yypact_[yystate]; - if (yy_pact_value_is_default_ (yyn)) + if (yyn == yypact_ninf_) goto yydefault; /* Read a lookahead token. */ @@ -408,8 +378,8 @@ namespace lol { yyn = yytable_[yyn]; if (yyn <= 0) { - if (yy_table_value_is_error_ (yyn)) - goto yyerrlab; + if (yyn == 0 || yyn == yytable_ninf_) + goto yyerrlab; yyn = -yyn; goto yyreduce; } @@ -465,29 +435,29 @@ namespace lol { { case 7: -/* Line 690 of lalr1.cc */ -#line 89 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 90 "easymesh/easymesh-parser.y" { mc.m_mesh.OpenBrace(); } break; case 8: -/* Line 690 of lalr1.cc */ -#line 93 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 94 "easymesh/easymesh-parser.y" { mc.m_mesh.CloseBrace(); } break; case 14: -/* Line 690 of lalr1.cc */ -#line 108 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 109 "easymesh/easymesh-parser.y" { mc.m_mesh.SetCurColor(vec4((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (yysemantic_stack_[(2) - (2)].args).f3)); } break; case 15: -/* Line 690 of lalr1.cc */ -#line 109 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 110 "easymesh/easymesh-parser.y" { uint32_t x = (yysemantic_stack_[(2) - (2)].u32val); vec4 v(x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); mc.m_mesh.SetCurColor(vec4(v) * (1. / 255)); } @@ -495,15 +465,15 @@ namespace lol { case 16: -/* Line 690 of lalr1.cc */ -#line 112 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 113 "easymesh/easymesh-parser.y" { mc.m_mesh.SetCurColor2(vec4((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (yysemantic_stack_[(2) - (2)].args).f3)); } break; case 17: -/* Line 690 of lalr1.cc */ -#line 113 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 114 "easymesh/easymesh-parser.y" { uint32_t x = (yysemantic_stack_[(2) - (2)].u32val); vec4 v(x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); mc.m_mesh.SetCurColor2(vec4(v) * (1. / 255)); } @@ -511,339 +481,356 @@ namespace lol { case 18: -/* Line 690 of lalr1.cc */ -#line 119 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 120 "easymesh/easymesh-parser.y" { mc.m_mesh.Chamfer((yysemantic_stack_[(2) - (2)].args).f0); } break; case 19: -/* Line 690 of lalr1.cc */ -#line 120 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 121 "easymesh/easymesh-parser.y" { mc.m_mesh.Translate(vec3((yysemantic_stack_[(2) - (2)].args).f0, 0, 0)); } break; case 20: -/* Line 690 of lalr1.cc */ -#line 121 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 122 "easymesh/easymesh-parser.y" { mc.m_mesh.Translate(vec3(0, (yysemantic_stack_[(2) - (2)].args).f0, 0)); } break; case 21: -/* Line 690 of lalr1.cc */ -#line 122 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 123 "easymesh/easymesh-parser.y" { mc.m_mesh.Translate(vec3(0, 0, (yysemantic_stack_[(2) - (2)].args).f0)); } break; case 22: -/* Line 690 of lalr1.cc */ -#line 123 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 124 "easymesh/easymesh-parser.y" { mc.m_mesh.Translate(vec3((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2)); } break; case 23: -/* Line 690 of lalr1.cc */ -#line 124 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 125 "easymesh/easymesh-parser.y" { mc.m_mesh.RotateX((yysemantic_stack_[(2) - (2)].args).f0); } break; case 24: -/* Line 690 of lalr1.cc */ -#line 125 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 126 "easymesh/easymesh-parser.y" { mc.m_mesh.RotateY((yysemantic_stack_[(2) - (2)].args).f0); } break; case 25: -/* Line 690 of lalr1.cc */ -#line 126 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 127 "easymesh/easymesh-parser.y" { mc.m_mesh.RotateZ((yysemantic_stack_[(2) - (2)].args).f0); } break; case 26: -/* Line 690 of lalr1.cc */ -#line 127 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 128 "easymesh/easymesh-parser.y" { mc.m_mesh.TaperX((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2); } break; case 27: -/* Line 690 of lalr1.cc */ -#line 128 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 129 "easymesh/easymesh-parser.y" { mc.m_mesh.TaperY((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2); } break; case 28: -/* Line 690 of lalr1.cc */ -#line 129 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 130 "easymesh/easymesh-parser.y" { mc.m_mesh.TaperZ((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2); } break; case 29: -/* Line 690 of lalr1.cc */ -#line 130 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 131 "easymesh/easymesh-parser.y" { mc.m_mesh.Scale(vec3((yysemantic_stack_[(2) - (2)].args).f0, 1.0, 1.0)); } break; case 30: -/* Line 690 of lalr1.cc */ -#line 131 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 132 "easymesh/easymesh-parser.y" { mc.m_mesh.Scale(vec3(1.0, (yysemantic_stack_[(2) - (2)].args).f0, 1.0)); } break; case 31: -/* Line 690 of lalr1.cc */ -#line 132 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 133 "easymesh/easymesh-parser.y" { mc.m_mesh.Scale(vec3(1.0, 1.0, (yysemantic_stack_[(2) - (2)].args).f0)); } break; case 32: -/* Line 690 of lalr1.cc */ -#line 133 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 134 "easymesh/easymesh-parser.y" { mc.m_mesh.Scale(vec3((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2)); } break; case 33: -/* Line 690 of lalr1.cc */ -#line 134 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 135 "easymesh/easymesh-parser.y" { mc.m_mesh.MirrorX(); } break; case 34: -/* Line 690 of lalr1.cc */ -#line 135 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 136 "easymesh/easymesh-parser.y" { mc.m_mesh.MirrorY(); } break; case 35: -/* Line 690 of lalr1.cc */ -#line 136 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 137 "easymesh/easymesh-parser.y" { mc.m_mesh.MirrorZ(); } break; case 36: -/* Line 690 of lalr1.cc */ -#line 137 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 138 "easymesh/easymesh-parser.y" { mc.m_mesh.ToggleScaleWinding(); } break; case 37: -/* Line 690 of lalr1.cc */ +/* Line 677 of lalr1.cc */ +#line 139 "easymesh/easymesh-parser.y" + { mc.m_mesh.CsgUnion(); } + break; + + case 38: + +/* Line 677 of lalr1.cc */ +#line 140 "easymesh/easymesh-parser.y" + { mc.m_mesh.CsgSubstract(); } + break; + + case 39: + +/* Line 677 of lalr1.cc */ #line 141 "easymesh/easymesh-parser.y" + { mc.m_mesh.CsgAnd(); } + break; + + case 40: + +/* Line 677 of lalr1.cc */ +#line 142 "easymesh/easymesh-parser.y" + { mc.m_mesh.CsgXor(); } + break; + + case 41: + +/* Line 677 of lalr1.cc */ +#line 146 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendCylinder((int)(yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (yysemantic_stack_[(2) - (2)].args).f3, (int)(yysemantic_stack_[(2) - (2)].args).f4, (int)(yysemantic_stack_[(2) - (2)].args).f5); } break; - case 38: + case 42: -/* Line 690 of lalr1.cc */ -#line 144 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 149 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendBox(vec3((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2)); } break; - case 39: + case 43: -/* Line 690 of lalr1.cc */ -#line 145 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 150 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendSmoothChamfBox(vec3((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2), (yysemantic_stack_[(2) - (2)].args).f3); } break; - case 40: + case 44: -/* Line 690 of lalr1.cc */ -#line 147 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 152 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendFlatChamfBox(vec3((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2), (yysemantic_stack_[(2) - (2)].args).f3); } break; - case 41: + case 45: -/* Line 690 of lalr1.cc */ -#line 149 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 154 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendSphere((yysemantic_stack_[(2) - (2)].args).f0, vec3((yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (yysemantic_stack_[(2) - (2)].args).f3)); } break; - case 42: + case 46: -/* Line 690 of lalr1.cc */ -#line 151 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 156 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendCapsule((yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2); } break; - case 43: + case 47: -/* Line 690 of lalr1.cc */ -#line 152 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 157 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendTorus((int)(yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2); } break; - case 44: + case 48: -/* Line 690 of lalr1.cc */ -#line 153 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 158 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendStar((int)(yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (int)(yysemantic_stack_[(2) - (2)].args).f3, (int)(yysemantic_stack_[(2) - (2)].args).f4); } break; - case 45: + case 49: -/* Line 690 of lalr1.cc */ -#line 155 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 160 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendExpandedStar((int)(yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (yysemantic_stack_[(2) - (2)].args).f3); } break; - case 46: + case 50: -/* Line 690 of lalr1.cc */ -#line 157 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 162 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendDisc((int)(yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (int)(yysemantic_stack_[(2) - (2)].args).f2); } break; - case 47: + case 51: -/* Line 690 of lalr1.cc */ -#line 158 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 163 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendSimpleTriangle((yysemantic_stack_[(2) - (2)].args).f0, (int)(yysemantic_stack_[(2) - (2)].args).f1); } break; - case 48: + case 52: -/* Line 690 of lalr1.cc */ -#line 159 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 164 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendSimpleQuad((yysemantic_stack_[(2) - (2)].args).f0, (int)(yysemantic_stack_[(2) - (2)].args).f1); } break; - case 49: + case 53: -/* Line 690 of lalr1.cc */ -#line 160 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 165 "easymesh/easymesh-parser.y" { mc.m_mesh.AppendCog((int)(yysemantic_stack_[(2) - (2)].args).f0, (yysemantic_stack_[(2) - (2)].args).f1, (yysemantic_stack_[(2) - (2)].args).f2, (yysemantic_stack_[(2) - (2)].args).f3, (yysemantic_stack_[(2) - (2)].args).f4, (yysemantic_stack_[(2) - (2)].args).f5, (yysemantic_stack_[(2) - (2)].args).f6, (yysemantic_stack_[(2) - (2)].args).f7, (yysemantic_stack_[(2) - (2)].args).f8, (int)(yysemantic_stack_[(2) - (2)].args).f9); } break; - case 50: + case 54: -/* Line 690 of lalr1.cc */ -#line 165 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 170 "easymesh/easymesh-parser.y" { (yyval.args).f0 = (yysemantic_stack_[(1) - (1)].fval); } break; - case 51: + case 55: -/* Line 690 of lalr1.cc */ -#line 166 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 171 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f1 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 52: + case 56: -/* Line 690 of lalr1.cc */ -#line 167 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 172 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f2 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 53: + case 57: -/* Line 690 of lalr1.cc */ -#line 168 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 173 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f3 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 54: + case 58: -/* Line 690 of lalr1.cc */ -#line 169 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 174 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f4 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 55: + case 59: -/* Line 690 of lalr1.cc */ -#line 170 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 175 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f5 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 56: + case 60: -/* Line 690 of lalr1.cc */ -#line 171 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 176 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f6 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 57: + case 61: -/* Line 690 of lalr1.cc */ -#line 172 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 177 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f7 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 58: + case 62: -/* Line 690 of lalr1.cc */ -#line 173 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 178 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f8 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 59: + case 63: -/* Line 690 of lalr1.cc */ -#line 174 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 179 "easymesh/easymesh-parser.y" { (yyval.args) = (yysemantic_stack_[(2) - (1)].args); (yyval.args).f9 = (yysemantic_stack_[(2) - (2)].fval); } break; - case 60: + case 64: -/* Line 690 of lalr1.cc */ -#line 177 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 182 "easymesh/easymesh-parser.y" { (yyval.fval) = (yysemantic_stack_[(1) - (1)].fval); } break; - case 61: + case 65: -/* Line 690 of lalr1.cc */ -#line 178 "easymesh/easymesh-parser.y" +/* Line 677 of lalr1.cc */ +#line 183 "easymesh/easymesh-parser.y" { (yyval.fval) = -(yysemantic_stack_[(2) - (2)].fval); } break; -/* Line 690 of lalr1.cc */ -#line 833 "generated/easymesh-parser.cpp" +/* Line 677 of lalr1.cc */ +#line 831 "generated/easymesh-parser.cpp" default: break; } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action - invokes YYABORT, YYACCEPT, or YYERROR immediately after altering - yychar. In the case of YYABORT or YYACCEPT, an incorrect - destructor might then be invoked immediately. In the case of - YYERROR, subsequent parser actions might lead to an incorrect - destructor call or verbose syntax error message before the - lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1_[yyn], &yyval, &yyloc); yypop_ (yylen); @@ -867,20 +854,14 @@ namespace lol { | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yytranslate_ (yychar); - /* If not already recovering from an error, report this error. */ if (!yyerrstatus_) { ++yynerrs_; - if (yychar == yyempty_) - yytoken = yyempty_; error (yylloc, yysyntax_error_ (yystate, yytoken)); } - yyerror_range[1] = yylloc; + yyerror_range[0] = yylloc; if (yyerrstatus_ == 3) { /* If just tried and failed to reuse lookahead token after an @@ -915,7 +896,7 @@ namespace lol { if (false) goto yyerrorlab; - yyerror_range[1] = yylocation_stack_[yylen - 1]; + yyerror_range[0] = yylocation_stack_[yylen - 1]; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ yypop_ (yylen); @@ -932,7 +913,7 @@ namespace lol { for (;;) { yyn = yypact_[yystate]; - if (!yy_pact_value_is_default_ (yyn)) + if (yyn != yypact_ninf_) { yyn += yyterror_; if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yyterror_) @@ -947,7 +928,7 @@ namespace lol { if (yystate_stack_.height () == 1) YYABORT; - yyerror_range[1] = yylocation_stack_[0]; + yyerror_range[0] = yylocation_stack_[0]; yydestruct_ ("Error: popping", yystos_[yystate], &yysemantic_stack_[0], &yylocation_stack_[0]); @@ -956,10 +937,10 @@ namespace lol { YY_STACK_PRINT (); } - yyerror_range[2] = yylloc; + yyerror_range[1] = yylloc; // Using YYLLOC is tempting, but would change the location of // the lookahead. YYLOC is available though. - YYLLOC_DEFAULT (yyloc, yyerror_range, 2); + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); yysemantic_stack_.push (yylval); yylocation_stack_.push (yyloc); @@ -982,13 +963,7 @@ namespace lol { yyreturn: if (yychar != yyempty_) - { - /* Make sure we have latest lookahead translation. See comments - at user semantic actions for why this is necessary. */ - yytoken = yytranslate_ (yychar); - yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, - &yylloc); - } + yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ @@ -1007,197 +982,155 @@ namespace lol { // Generate an error message. std::string - EasyMeshParser::yysyntax_error_ (int yystate, int yytoken) + EasyMeshParser::yysyntax_error_ (int yystate, int tok) { - std::string yyres; - // Number of reported tokens (one for the "unexpected", one per - // "expected"). - size_t yycount = 0; - // Its maximum. - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - // Arguments of yyformat. - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - - /* There are many possibilities here to consider: - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yytoken) is - if this state is a consistent state with a default action. - Thus, detecting the absence of a lookahead is sufficient to - determine that there is no unexpected or expected token to - report. In that case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is - a consistent state with a default action. There might have - been a previous inconsistent state, consistent state with a - non-default action, or user semantic action that manipulated - yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state - merging (from LALR or IELR) and default reductions corrupt the - expected token list. However, the list is correct for - canonical LR with one exception: it will still contain any - token that will not be accepted due to an error action in a - later state. - */ - if (yytoken != yyempty_) - { - yyarg[yycount++] = yytname_[yytoken]; - int yyn = yypact_[yystate]; - if (!yy_pact_value_is_default_ (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = yylast_ - yyn + 1; - int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_; - for (int yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck_[yyx + yyn] == yyx && yyx != yyterror_ - && !yy_table_value_is_error_ (yytable_[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - break; - } - else - yyarg[yycount++] = yytname_[yyx]; - } - } - } - - char const* yyformat = 0; - switch (yycount) + std::string res; + YYUSE (yystate); +#if YYERROR_VERBOSE + int yyn = yypact_[yystate]; + if (yypact_ninf_ < yyn && yyn <= yylast_) { -#define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -#undef YYCASE_ + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = yylast_ - yyn + 1; + int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_; + int count = 0; + for (int x = yyxbegin; x < yyxend; ++x) + if (yycheck_[x + yyn] == x && x != yyterror_) + ++count; + + // FIXME: This method of building the message is not compatible + // with internationalization. It should work like yacc.c does it. + // That is, first build a string that looks like this: + // "syntax error, unexpected %s or %s or %s" + // Then, invoke YY_ on this string. + // Finally, use the string as a format to output + // yytname_[tok], etc. + // Until this gets fixed, this message appears in English only. + res = "syntax error, unexpected "; + res += yytnamerr_ (yytname_[tok]); + if (count < 5) + { + count = 0; + for (int x = yyxbegin; x < yyxend; ++x) + if (yycheck_[x + yyn] == x && x != yyterror_) + { + res += (!count++) ? ", expecting " : " or "; + res += yytnamerr_ (yytname_[x]); + } + } } - - // Argument number. - size_t yyi = 0; - for (char const* yyp = yyformat; *yyp; ++yyp) - if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount) - { - yyres += yytnamerr_ (yyarg[yyi++]); - ++yyp; - } - else - yyres += *yyp; - return yyres; + else +#endif + res = YY_("syntax error"); + return res; } /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ - const signed char EasyMeshParser::yypact_ninf_ = -48; + const signed char EasyMeshParser::yypact_ninf_ = -10; const signed char EasyMeshParser::yypact_[] = { - 37, -27, 89, -32, -32, -32, -32, -48, -32, -32, - -32, -32, -48, -32, -32, -32, -32, -48, -32, -32, - -48, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -48, 5, 13, 37, 37, - 75, -48, -48, -48, -48, -48, -48, -32, -32, -32, - -32, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -32, -32, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -32, -32, -32, -32, -48, -48, -48, - -48, -48, -25, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48 + -3, 18, 27, 16, 16, 16, 16, -10, 16, 16, + 16, 16, -10, 16, 16, 16, 16, -10, 16, 16, + -10, -10, -10, -10, -10, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, -10, + 40, 48, -3, -3, 79, -10, -10, -10, -10, -10, + -10, 16, 16, 16, 16, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, 16, 16, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, 16, 16, 16, + 16, -10, -10, -10, -10, -10, 5, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10 }; - /* YYDEFACT[S] -- default reduction number in state S. Performed when - YYTABLE doesn't specify something else to do. Zero means the - default is an error. */ + /* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ const unsigned char EasyMeshParser::yydefact_[] = { 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 34, 0, 0, 0, 0, 35, 0, 0, - 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 0, 0, 3, 0, - 5, 9, 11, 12, 13, 60, 15, 0, 0, 0, - 0, 14, 50, 17, 16, 19, 23, 26, 29, 20, - 24, 27, 30, 21, 25, 28, 31, 22, 32, 18, - 0, 0, 37, 38, 39, 40, 41, 42, 44, 45, - 46, 47, 48, 0, 0, 0, 0, 49, 43, 1, - 2, 4, 0, 10, 61, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 8, 6 + 36, 37, 38, 39, 40, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 3, 0, 5, 9, 11, 12, 13, 64, + 15, 0, 0, 0, 0, 14, 54, 17, 16, 19, + 23, 26, 29, 20, 24, 27, 30, 21, 25, 28, + 31, 22, 32, 18, 0, 0, 41, 42, 43, 44, + 45, 46, 48, 49, 50, 51, 52, 0, 0, 0, + 0, 53, 47, 1, 2, 4, 0, 10, 65, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 8, 6 }; /* YYPGOTO[NTERM-NUM]. */ const signed char EasyMeshParser::yypgoto_[] = { - -48, -48, -19, -48, -48, -48, -48, -15, -48, -48, - -48, 109, -4, -1, 6, -7, 1, -48, -48, -48, - -48, -47 + -10, -10, -4, -10, -10, -10, -10, 9, -10, -10, + -10, 43, 36, 115, 122, 23, 26, -10, -10, -10, + -10, -9 }; /* YYDEFGOTO[NTERM-NUM]. */ const signed char EasyMeshParser::yydefgoto_[] = { - -1, 36, 37, 38, 39, 105, 40, 41, 42, 43, - 44, 48, 49, 50, 70, 71, 72, 84, 85, 86, - 87, 52 + -1, 40, 41, 42, 43, 109, 44, 45, 46, 47, + 48, 52, 53, 54, 74, 75, 76, 88, 89, 90, + 91, 56 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF_, syntax error. */ + number is the opposite. If zero, do what YYDEFACT says. */ const signed char EasyMeshParser::yytable_ninf_ = -1; const unsigned char EasyMeshParser::yytable_[] = { - 94, 95, 96, 97, 57, 89, 45, 51, 54, 61, - 47, 45, 46, 90, 65, 47, 104, 67, 68, 91, - 92, 78, 73, 98, 99, 93, 77, 81, 82, 80, - 74, 75, 76, 88, 83, 79, 100, 101, 102, 103, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 0, 0, 0, 35, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 55, 56, 0, 58, 0, 59, 60, 0, - 62, 0, 63, 64, 0, 66, 0, 45, 53, 0, - 69, 47 + 31, 32, 33, 34, 35, 36, 37, 38, 95, 96, + 93, 39, 98, 99, 100, 101, 59, 60, 94, 62, + 108, 63, 64, 97, 66, 82, 67, 68, 49, 70, + 49, 50, 51, 87, 51, 102, 103, 0, 73, 49, + 57, 85, 86, 51, 0, 0, 0, 0, 104, 105, + 106, 107, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 61, 0, 0, 55, 58, 65, 0, 0, 0, 0, + 69, 0, 0, 71, 72, 0, 0, 0, 0, 0, + 0, 0, 77, 0, 0, 0, 81, 0, 0, 84, + 78, 79, 80, 92, 0, 83 }; /* YYCHECK. */ const signed char EasyMeshParser::yycheck_[] = { - 47, 48, 49, 50, 5, 0, 38, 1, 2, 10, - 42, 38, 39, 0, 15, 42, 41, 18, 19, 38, - 39, 28, 23, 70, 71, 40, 27, 31, 32, 30, - 24, 25, 26, 34, 33, 29, 83, 84, 85, 86, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, -1, -1, -1, 40, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 3, 4, -1, 6, -1, 8, 9, -1, - 11, -1, 13, 14, -1, 16, -1, 38, 39, -1, - 21, 42 + 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, + 0, 44, 51, 52, 53, 54, 3, 4, 0, 6, + 45, 8, 9, 44, 11, 32, 13, 14, 42, 16, + 42, 43, 46, 37, 46, 74, 75, -1, 25, 42, + 43, 35, 36, 46, -1, -1, -1, -1, 87, 88, + 89, 90, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 5, -1, -1, 1, 2, 10, -1, -1, -1, -1, + 15, -1, -1, 18, 19, -1, -1, -1, -1, -1, + -1, -1, 27, -1, -1, -1, 31, -1, -1, 34, + 28, 29, 30, 38, -1, 33 }; /* STOS_[STATE-NUM] -- The (internal number of the) accessing @@ -1208,14 +1141,14 @@ namespace lol { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 40, 44, 45, 46, 47, - 49, 50, 51, 52, 53, 38, 39, 42, 54, 55, - 56, 57, 64, 39, 57, 54, 54, 56, 54, 54, - 54, 56, 54, 54, 54, 56, 54, 56, 56, 54, - 57, 58, 59, 56, 57, 57, 57, 56, 58, 57, - 56, 55, 55, 59, 60, 61, 62, 63, 56, 0, - 0, 45, 45, 50, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 41, 48 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 44, + 48, 49, 50, 51, 53, 54, 55, 56, 57, 42, + 43, 46, 58, 59, 60, 61, 68, 43, 61, 58, + 58, 60, 58, 58, 58, 60, 58, 58, 58, 60, + 58, 60, 60, 58, 61, 62, 63, 60, 61, 61, + 61, 60, 62, 61, 60, 59, 59, 63, 64, 65, + 66, 67, 60, 0, 0, 49, 49, 54, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 45, 52 }; #if YYDEBUG @@ -1228,7 +1161,7 @@ namespace lol { 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 91, 93, 45 + 295, 296, 297, 298, 91, 93, 45 }; #endif @@ -1236,13 +1169,13 @@ namespace lol { const unsigned char EasyMeshParser::yyr1_[] = { - 0, 43, 44, 45, 45, 46, 46, 47, 48, 49, - 49, 50, 50, 50, 51, 51, 51, 51, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 64 + 0, 47, 48, 49, 49, 50, 50, 51, 52, 53, + 53, 54, 54, 54, 55, 55, 55, 55, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 68 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -1252,10 +1185,10 @@ namespace lol { 0, 2, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 2 + 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 2 }; #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE @@ -1268,7 +1201,8 @@ namespace lol { "T_ROTATEX", "T_TAPERX", "T_SCALEX", "T_MIRRORX", "T_TRANSLATEY", "T_ROTATEY", "T_TAPERY", "T_SCALEY", "T_MIRRORY", "T_TRANSLATEZ", "T_ROTATEZ", "T_TAPERZ", "T_SCALEZ", "T_MIRRORZ", "T_TRANSLATE", - "T_SCALE", "T_TOGGLESCALEWINDING", "T_CHAMFER", "T_CYLINDER", "T_BOX", + "T_SCALE", "T_TOGGLESCALEWINDING", "T_CSGUNION", "T_CSGSUBSTRACT", + "T_CSGAND", "T_CSGXOR", "T_CHAMFER", "T_CYLINDER", "T_BOX", "T_SMOOTHCHAMFBOX", "T_FLATCHAMFBOX", "T_SPHERE", "T_CAPSULE", "T_STAR", "T_EXPANDEDSTAR", "T_DISC", "T_TRIANGLE", "T_QUAD", "T_COG", "T_TORUS", "T_ERROR", "NUMBER", "COLOR", "'['", "']'", "'-'", "$accept", @@ -1285,23 +1219,24 @@ namespace lol { const EasyMeshParser::rhs_number_type EasyMeshParser::yyrhs_[] = { - 44, 0, -1, 45, 0, -1, 46, -1, 46, 45, - -1, 49, -1, 47, 45, 48, -1, 40, -1, 41, - -1, 50, -1, 49, 50, -1, 51, -1, 52, -1, - 53, -1, 3, 57, -1, 3, 39, -1, 4, 57, - -1, 4, 39, -1, 23, 54, -1, 5, 54, -1, - 10, 54, -1, 15, 54, -1, 20, 56, -1, 6, - 54, -1, 11, 54, -1, 16, 54, -1, 7, 56, - -1, 12, 56, -1, 17, 56, -1, 8, 54, -1, - 13, 54, -1, 18, 54, -1, 21, 56, -1, 9, - -1, 14, -1, 19, -1, 22, -1, 24, 59, -1, - 25, 56, -1, 26, 57, -1, 27, 57, -1, 28, - 57, -1, 29, 56, -1, 36, 56, -1, 30, 58, - -1, 31, 57, -1, 32, 56, -1, 33, 55, -1, - 34, 55, -1, 35, 63, -1, 64, -1, 54, 64, - -1, 55, 64, -1, 56, 64, -1, 57, 64, -1, - 58, 64, -1, 59, 64, -1, 60, 64, -1, 61, - 64, -1, 62, 64, -1, 38, -1, 42, 64, -1 + 48, 0, -1, 49, 0, -1, 50, -1, 50, 49, + -1, 53, -1, 51, 49, 52, -1, 44, -1, 45, + -1, 54, -1, 53, 54, -1, 55, -1, 56, -1, + 57, -1, 3, 61, -1, 3, 43, -1, 4, 61, + -1, 4, 43, -1, 27, 58, -1, 5, 58, -1, + 10, 58, -1, 15, 58, -1, 20, 60, -1, 6, + 58, -1, 11, 58, -1, 16, 58, -1, 7, 60, + -1, 12, 60, -1, 17, 60, -1, 8, 58, -1, + 13, 58, -1, 18, 58, -1, 21, 60, -1, 9, + -1, 14, -1, 19, -1, 22, -1, 23, -1, 24, + -1, 25, -1, 26, -1, 28, 63, -1, 29, 60, + -1, 30, 61, -1, 31, 61, -1, 32, 61, -1, + 33, 60, -1, 40, 60, -1, 34, 62, -1, 35, + 61, -1, 36, 60, -1, 37, 59, -1, 38, 59, + -1, 39, 67, -1, 68, -1, 58, 68, -1, 59, + 68, -1, 60, 68, -1, 61, 68, -1, 62, 68, + -1, 63, 68, -1, 64, 68, -1, 65, 68, -1, + 66, 68, -1, 42, -1, 46, 68, -1 }; /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in @@ -1312,23 +1247,23 @@ namespace lol { 0, 0, 3, 6, 8, 11, 13, 17, 19, 21, 23, 26, 28, 30, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, - 80, 83, 86, 89, 91, 93, 95, 97, 100, 103, - 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, - 136, 138, 141, 144, 147, 150, 153, 156, 159, 162, - 165, 167 + 80, 83, 86, 89, 91, 93, 95, 97, 99, 101, + 103, 105, 108, 111, 114, 117, 120, 123, 126, 129, + 132, 135, 138, 141, 144, 146, 149, 152, 155, 158, + 161, 164, 167, 170, 173, 175 }; /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ const unsigned char EasyMeshParser::yyrline_[] = { - 0, 75, 75, 79, 80, 84, 85, 89, 93, 97, - 98, 102, 103, 104, 108, 109, 112, 113, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 141, 144, 145, - 147, 149, 151, 152, 153, 155, 157, 158, 159, 160, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 177, 178 + 0, 76, 76, 80, 81, 85, 86, 90, 94, 98, + 99, 103, 104, 105, 109, 110, 113, 114, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 146, 149, 150, 152, 154, 156, 157, 158, 160, + 162, 163, 164, 165, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 182, 183 }; // Print the state stack on the debug stream. @@ -1372,12 +1307,12 @@ namespace lol { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 42, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 40, 2, 41, 2, 2, 2, 2, 2, 2, + 2, 44, 2, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1397,7 +1332,7 @@ namespace lol { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39 + 35, 36, 37, 38, 39, 40, 41, 42, 43 }; if ((unsigned int) t <= yyuser_token_number_max_) return translate_table[t]; @@ -1406,26 +1341,26 @@ namespace lol { } const int EasyMeshParser::yyeof_ = 0; - const int EasyMeshParser::yylast_ = 131; + const int EasyMeshParser::yylast_ = 155; const int EasyMeshParser::yynnts_ = 22; const int EasyMeshParser::yyempty_ = -2; - const int EasyMeshParser::yyfinal_ = 89; + const int EasyMeshParser::yyfinal_ = 93; const int EasyMeshParser::yyterror_ = 1; const int EasyMeshParser::yyerrcode_ = 256; - const int EasyMeshParser::yyntokens_ = 43; + const int EasyMeshParser::yyntokens_ = 47; - const unsigned int EasyMeshParser::yyuser_token_number_max_ = 294; + const unsigned int EasyMeshParser::yyuser_token_number_max_ = 298; const EasyMeshParser::token_number_type EasyMeshParser::yyundef_token_ = 2; } // lol -/* Line 1136 of lalr1.cc */ -#line 1425 "generated/easymesh-parser.cpp" +/* Line 1053 of lalr1.cc */ +#line 1360 "generated/easymesh-parser.cpp" -/* Line 1138 of lalr1.cc */ -#line 181 "easymesh/easymesh-parser.y" +/* Line 1055 of lalr1.cc */ +#line 186 "easymesh/easymesh-parser.y" void lol::EasyMeshParser::error(const EasyMeshParser::location_type& l, diff --git a/src/generated/easymesh-parser.h b/src/generated/easymesh-parser.h index 91e80e4d..5640961d 100644 --- a/src/generated/easymesh-parser.h +++ b/src/generated/easymesh-parser.h @@ -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 #include #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" diff --git a/src/generated/easymesh-scanner.cpp b/src/generated/easymesh-scanner.cpp index 3b13f4e9..48acaf24 100644 --- a/src/generated/easymesh-scanner.cpp +++ b/src/generated/easymesh-scanner.cpp @@ -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 -// (c) 2009-2012 Cédric Lecacheur -// (c) 2009-2012 Benjamin Huet +// Copyright: (c) 2010-2013 Sam Hocevar +// (c) 2009-2013 Cédric Lecacheur +// (c) 2009-2013 Benjamin "Touky" Huet // 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" diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 571d91a7..9132720a 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -240,6 +240,7 @@ + @@ -555,6 +556,7 @@ + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index d8cf5dc0..342bb2a4 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -657,6 +657,9 @@ math + + easymesh + @@ -1634,6 +1637,9 @@ lol\math + + easymesh + diff --git a/tutorial/05_easymesh.cpp b/tutorial/05_easymesh.cpp index 60bec787..85a04c5d 100644 --- a/tutorial/05_easymesh.cpp +++ b/tutorial/05_easymesh.cpp @@ -1,7 +1,8 @@ // // Lol Engine - EasyMesh tutorial // -// Copyright: (c) 2011-2012 Sam Hocevar +// Copyright: (c) 2011-2013 Sam Hocevar +// (c) 2012-2013 Benjamin "Touky" Huet // 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)