|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- //
- // EasyMesh-Internal— Internal operations
- //
- // Copyright © 2012—2020 Sam Hocevar <sam@hocevar.net>
- // © 2009—2015 Cédric Lecacheur <jordx@free.fr>
- // © 2009—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
- //
- // Lol Engine is free software. It comes without any warranty, to
- // the extent permitted by applicable law. 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 the WTFPL Task Force.
- // See http://www.wtfpl.net/ for more details.
- //
-
- #include <lol/engine-internal.h>
-
- namespace lol
- {
-
- //-----------------------------------------------------------------------------
- void EasyMesh::AddVertex(vec3 const &coord)
- {
- m_vert.push(VertexData(coord, vec3(0.f, 1.f, 0.f), BD()->ColorA()));
- m_state = MeshRender::NeedConvert;
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::AddDupVertex(int i)
- {
- m_vert << m_vert[i];
- m_state = MeshRender::NeedConvert;
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::AddLerpVertex(int i, int j, float alpha) { AddLerpVertex(m_vert[i], m_vert[j], alpha); }
- void EasyMesh::AddLerpVertex(VertexData const &vi, VertexData const &vj, float alpha)
- {
- m_vert.push(GetLerpVertex(vi, vj, alpha));
- m_state = MeshRender::NeedConvert;
- }
-
- //-----------------------------------------------------------------------------
- VertexData EasyMesh::GetLerpVertex(int i, int j, float alpha) { return GetLerpVertex(m_vert[i], m_vert[j], alpha); }
- VertexData EasyMesh::GetLerpVertex(VertexData const &vi, VertexData const &vj, float alpha)
- {
- return VertexData(
- lol::lerp(vi.m_coord, vj.m_coord, alpha),
- lol::lerp(vi.m_normal, vj.m_normal, alpha),
- lol::lerp(vi.m_color, vj.m_color, alpha),
- lol::lerp(vi.m_texcoord, vj.m_texcoord, alpha),
- ((alpha < .5f) ? (vi.m_bone_id) : (vj.m_bone_id)), /* FIXME ? */
- lol::lerp(vi.m_bone_weight, vj.m_bone_weight, alpha));
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::AddQuad(int i1, int i2, int i3, int i4, int base, bool duplicate)
- {
- if (duplicate)
- {
- int vbase = m_vert.count();
- AddDupVertex(base + i1);
- AddDupVertex(base + i2);
- AddDupVertex(base + i3);
- AddDupVertex(base + i4);
-
- AddQuad(0, 1, 2, 3, vbase);
- }
- else
- {
- if (BD()->IsEnabled(MeshBuildOperation::QuadWeighting) &&
- !BD()->IsEnabled(MeshBuildOperation::IgnoreQuadWeighting))
- {
- int i5 = m_vert.count();
- AddLerpVertex(GetLerpVertex(base + i1, base + i3, .5f),
- GetLerpVertex(base + i2, base + i4, .5f), .5f);
- m_indices << i1 + base;
- m_indices << i2 + base;
- m_indices << i5;
-
- m_indices << i2 + base;
- m_indices << i3 + base;
- m_indices << i5;
-
- m_indices << i4 + base;
- m_indices << i1 + base;
- m_indices << i5;
-
- m_indices << i5;
- m_indices << i3 + base;
- m_indices << i4 + base;
- }
- else
- {
- m_indices << i1 + base;
- m_indices << i2 + base;
- m_indices << i3 + base;
-
- m_indices << i4 + base;
- m_indices << i1 + base;
- m_indices << i3 + base;
- }
- }
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::AddTriangle(int i1, int i2, int i3, int base, bool duplicate)
- {
- if (duplicate)
- {
- m_indices << (uint16_t)m_vert.count(); AddDupVertex(base + i1);
- m_indices << (uint16_t)m_vert.count(); AddDupVertex(base + i2);
- m_indices << (uint16_t)m_vert.count(); AddDupVertex(base + i3);
- }
- else
- {
- m_indices << base + i1;
- m_indices << base + i2;
- m_indices << base + i3;
- }
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::ComputeNormals(int start, int vcount)
- {
-
- if (BD()->IsEnabled(MeshBuildOperation::CommandExecution) &&
- BD()->IsEnabled(MeshBuildOperation::PostBuildComputeNormals))
- return;
-
- easy_array< easy_array<vec3> > normals;
- normals.resize(m_vert.count());
- for (int i = 0; i < vcount; i += 3)
- {
- vec3 v0 = m_vert[m_indices[start + i + 2]].m_coord
- - m_vert[m_indices[start + i + 0]].m_coord;
- vec3 v1 = m_vert[m_indices[start + i + 1]].m_coord
- - m_vert[m_indices[start + i + 0]].m_coord;
- vec3 n = normalize(cross(v1, v0));
-
- for (int j = 0; j < 3; j++)
- normals[m_indices[start + i + j]] << n;
- }
-
- for (int i = 0; i < normals.count(); i++)
- {
- if (normals[i].count() > 0)
- {
- //remove doubles
- for (int j = 0; j < normals[i].count(); ++j)
- for (int k = j + 1; k < normals[i].count(); ++k)
- if (1.f - dot(normals[i][k], normals[i][j]) < .00001f)
- normals[i].remove(k--);
-
- vec3 newv = vec3::zero;
- for (int j = 0; j < normals[i].count(); ++j)
- newv += normals[i][j];
- m_vert[i].m_normal = normalize(newv / (float)normals[i].count());
- }
- }
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::VerticesCleanup()
- {
- easy_array<int> vert_ids;
- vert_ids.resize(m_vert.count(), 0);
-
- //1: Remove triangles with two vertices on each other
- for (int i = 0; i < m_indices.count(); i += 3)
- {
- bool remove = false;
- for (int j = 0; !remove && j < 3; ++j)
- if (length(m_vert[m_indices[i + j]].m_coord - m_vert[m_indices[i + (j + 1) % 3]].m_coord) < .00001f)
- remove = true;
- if (remove)
- {
- m_indices.remove_swap(i, 3);
- i -= 3;
- }
- else
- {
- //1.5: Mark all used vertices
- for (int j = 0; j < 3; ++j)
- vert_ids[m_indices[i + j]] = 1;
- }
- }
-
- //2: Remove all unused vertices
- easy_array<VertexData> old_vert = m_vert;
- int shift = 0;
- m_vert.clear();
- for (int i = 0; i < vert_ids.count(); ++i)
- {
- //Unused vertex, update the shift quantity instead of keeping it.
- if (vert_ids[i] == 0)
- shift++;
- else
- m_vert << old_vert[i];
- //Always mark it with the shift quantity
- vert_ids[i] = shift;
- }
-
- //3: Update the indices
- for (int i = 0; i < m_indices.count(); ++i)
- m_indices[i] -= vert_ids[m_indices[i]];
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::VerticesMerge()
- {
- if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
- {
- BD()->CmdStack().AddCmd(EasyMeshCmdType::VerticesMerge);
- return;
- }
-
- //1: Crunch all vertices in the dictionnary
- VertexDictionnary vert_dict;
- for (int i = std::get<0>(m_cursors.last()); i < m_vert.count(); i++)
- vert_dict.RegisterVertex(i, m_vert[i].m_coord);
-
- //2: Update the indices
- for (int i = 0; i < m_indices.count(); ++i)
- {
- int master = vert_dict.FindVertexMaster(m_indices[i]);
- if (master >= 0)
- m_indices[i] = master;
- }
-
- //2: Cleanup
- VerticesCleanup();
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::VerticesSeparate()
- {
- if (BD()->IsEnabled(MeshBuildOperation::CommandRecording))
- {
- BD()->CmdStack().AddCmd(EasyMeshCmdType::VerticesSeparate);
- return;
- }
-
- easy_array< easy_array<int> > new_ids;
- easy_array<int> vert_ids;
- vert_ids.resize(m_vert.count(), 0);
-
- //1: Mark all used vertices
- for (int i = 0; i < m_indices.count(); ++i)
- vert_ids[m_indices[i]]++;
-
- //2: Update the vertices
- int vbase = std::get<0>(m_cursors.last());
- int vcount = m_vert.count();
- new_ids.resize(vcount);
- for (int i = vbase; i < vcount; i++)
- {
- while (vert_ids[i] > 1)
- {
- //Add duplicate
- new_ids[i] << m_vert.count();
- AddDupVertex(i);
- vert_ids[i]--;
- }
- }
-
- //3: Update the indices
- for (int i = 0; i < m_indices.count(); ++i)
- {
- if (new_ids[m_indices[i]].count())
- {
- int j = new_ids[m_indices[i]].pop();
- m_indices[i] = j;
- }
- }
-
- //4: Cleanup
- VerticesCleanup();
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::ComputeTexCoord(float uv_scale, int uv_offset)
- {
- (void)uv_scale; (void)uv_offset;
- #if 0
- VertexDictionnary vert_dict;
- easy_array<int> tri_list;
-
- tri_list.Reserve(m_indices.count() - std::get<1>(m_cursors.last()));
- for (int i = std::get<1>(m_cursors.last()); i < m_indices.count(); i++)
- {
- vert_dict.RegisterVertex(m_indices[i], m_vert[m_indices[i]].m_coord);
- tri_list << m_indices[i];
- }
-
- //full triangle count
- easy_array<int> tri_done;
- easy_array<int> tri_check;
- int tri_count = (m_indices.count() - std::get<1>(m_cursors.last())) / 3;
-
- tri_check << tri_list[0];
-
- while (tri_check.count())
- {
- int cur_tri = tri_check[0];
- int v[3] = { tri_list[cur_tri + uv_offset % 3], tri_list[cur_tri + (1 + uv_offset) % 3], tri_list[cur_tri + (2 + uv_offset) % 3] };
- vec2 uv[3] = { m_vert[tri_list[cur_tri]].m_texcoord.xy, m_vert[tri_list[cur_tri + 1]].m_texcoord.xy, m_vert[tri_list[cur_tri + 2]].m_texcoord.xy };
- for (int j = 0; j < 3; j++)
- {
- if (uv[j] != vec2(-1.0f) && uv[j] == uv[(j + 1) % 3])
- {
- uv[0] = vec2(-1.0f);
- uv[1] = vec2(-1.0f);
- uv[2] = vec2(-1.0f);
- break;
- }
- }
- int uv_set = 0;
- for (int j = 0; j < 3; j++)
- uv_set += (uv[j].x < 0.f)?(0):(1);
-
- //this case shouldn't happen.
- if (uv_set == 1)
- {
- /*
- for (int j = 0; j < 3; j++)
- {
- if (uv[j] != vec2(-1.0f))
- {
- uv[(j + 1) % 2] = uv[j] + vec2(.0f, uv_scale * length(std::get<0>(m_vert[v[j]]) - std::get<0>(m_vert[v[(j + 1) % 3]])));
- uv_set = 2;
- break;
- }
- }
- */
- }
- //No UV is set, let's do the arbitrary set and use the basic method.
- if (uv_set == 0)
- {
- float new_dot = FLT_MAX;
- int base_i = 0;
- for (int j = 0; j < 3; j++)
- {
- float tmp_dot = abs(dot(normalize(m_vert[v[(j + 1) % 3]].m_coord - m_vert[v[j]].m_coord),
- normalize(m_vert[v[(j + 2) % 3]].m_coord - m_vert[v[j]].m_coord)));
- if (tmp_dot < new_dot)
- {
- base_i = j;
- new_dot = tmp_dot;
- }
- }
- uv[base_i] = vec2(.0f);
- uv[(base_i + 1) % 3] = vec2(.0f, uv_scale * length(m_vert[v[base_i]].m_coord - m_vert[v[(base_i + 1) % 3]].m_coord));
- uv_set = 2;
- }
- //2 points have been set, let's figure the third
- if (uv_set == 2)
- {
- {
- //invert values so the two set uv are in [0, 1] slots.
- int new_v[3];
- vec2 new_uv[3];
- bool ignore_set = false;
- if (uv[0].x >= 0.f && uv[1].x < 0.f)
- {
- new_v[0] = v[2]; new_v[1] = v[0]; new_v[2] = v[1];
- new_uv[0] = uv[2]; new_uv[1] = uv[0]; new_uv[2] = uv[1];
- }
- else if (uv[0].x < 0.f && uv[1].x >= 0.f)
- {
- new_v[0] = v[1]; new_v[1] = v[2]; new_v[2] = v[0];
- new_uv[0] = uv[1]; new_uv[1] = uv[2]; new_uv[2] = uv[0];
- }
- else
- ignore_set = true;
- if (!ignore_set)
- {
- v[0] = new_v[0]; v[1] = new_v[1]; v[2] = new_v[2];
- uv[0] = new_uv[0]; uv[1] = new_uv[1]; uv[2] = new_uv[2];
- }
- }
-
- //Do this to be sure the normal is OK.
- ComputeNormals(cur_tri, 3);
- vec3 v01 = normalize(m_vert[v[1]].m_coord - m_vert[v[0]].m_coord);
- vec3 v02 = m_vert[v[2]].m_coord - m_vert[v[0]].m_coord;
- vec3 v_dir = normalize(cross(m_vert[m_indices[cur_tri]].m_normal, v01));
- vec2 texu_dir = uv[1] - uv[0];
- vec2 texv_dir = vec2(texu_dir.y, texu_dir.x);
- //Final calculations
- uv[2] = texu_dir * dot(v01, v02) + texv_dir * dot(v_dir, v02);
-
- //Set UV on ALL matching vertices!
- easy_array<int> matching_vert;
- for (int i = 0; i < 3; i++)
- {
- #if 1
- //This marks all same position UV to the same values
- //Deactivation is a test.
- matching_vert << v[i];
- vert_dict.FindMatchingVertices(v[i], matching_vert);
- for (int j = 0; j < matching_vert.count(); j++)
- if (m_vert[matching_vert[j]].m_texcoord.xy == vec2(-1.0f))
- m_vert[matching_vert[j]].m_texcoord = vec4(abs(uv[i]), m_vert[matching_vert[j]].m_texcoord.zw);
- #else
- m_vert[v[i]].m_texcoord = abs(uv[i]);
- #endif
- }
-
- tri_done << cur_tri;
- tri_check.remove(0);
-
- //Get connected triangles and go from there.
- for (int j = 0; j < 3; j++)
- {
- #if 1
- //This finds triangle that are connected to this triangle
- vert_dict.FindConnectedTriangles(ivec2(v[j], v[(j + 1) % 3]), tri_list, tri_check, &tri_done);
- #else
- //This finds triangle that are connected to the vertices of this triangle
- vert_dict.FindConnectedTriangles(v[j], tri_list, tri_check, &tri_done);
- #endif
- }
- }
- else if (uv_set == 3)
- {
- for (int j = 0; j < 3; j++)
- {
- m_vert[tri_list[cur_tri]].m_texcoord = vec4(vec2(-1.0f), m_vert[tri_list[cur_tri]].m_texcoord.zw);
- m_vert[tri_list[cur_tri + 1]].m_texcoord = vec4(vec2(-1.0f), m_vert[tri_list[cur_tri + 1]].m_texcoord.zw);
- m_vert[tri_list[cur_tri + 2]].m_texcoord = vec4(vec2(-1.0f), m_vert[tri_list[cur_tri + 2]].m_texcoord.zw);
- }
-
- //uv[0] = vec2(-1.0f);
- //uv[1] = vec2(-1.0f);
- //uv[2] = vec2(-1.0f);
- /*
- bool tri_present = false;
- for (int j = 0; j < tri_done.count(); j++)
- if (cur_tri == tri_done[j])
- tri_present = true;
- if (!tri_present)
- tri_done << cur_tri;
- tri_check.remove(0);
- */
- }
-
- if (tri_check.count() == 0 && tri_done.count() != tri_count)
- {
- //look for unset triangle
- for (int i = 0; !tri_check.count() && i < tri_list.count(); i += 3)
- {
- bool tri_present = false;
- for (int j = 0; j < tri_done.count(); j++)
- if (i == tri_done[j])
- tri_present = true;
- if (!tri_present)
- tri_check << i;
- }
- }
- }
- #endif
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::SetTexCoordData(vec2 const &new_offset, vec2 const &new_scale)
- {
- BD()->TexCoordOffset() = new_offset;
- BD()->TexCoordScale() = new_scale;
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::SetTexCoordData2(vec2 const &new_offset, vec2 const &new_scale)
- {
- BD()->TexCoordOffset2() = new_offset;
- BD()->TexCoordScale2() = new_scale;
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::SetCurVertNormal(vec3 const &normal)
- {
- m_vert.last().m_normal = normal;
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::SetCurVertColor(vec4 const &col)
- {
- m_vert.last().m_color = col;
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::SetCurVertTexCoord(vec2 const &texcoord)
- {
- m_vert.last().m_texcoord = vec4(texcoord, m_vert.last().m_texcoord.zw);
- }
-
- //-----------------------------------------------------------------------------
- void EasyMesh::SetCurVertTexCoord2(vec2 const &texcoord)
- {
- m_vert.last().m_texcoord = vec4(m_vert.last().m_texcoord.xy, texcoord);
- }
-
- } /* namespace lol */
-
|