From 96972cdc4d5191cb3f239a269d5f94d4830ade04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20=E2=80=98Touky=E2=80=99=20Huet?= Date: Mon, 18 Feb 2013 22:20:11 +0000 Subject: [PATCH] easymesh : Bitfield big Fuckup. Never code drunk. --- src/easymesh/easymesh.cpp | 294 +++++++++++++++-------- src/easymesh/easymesh.h | 353 ++++++++++++++++++++++++++-- test/MeshViewer.cpp | 5 +- test/MeshViewerBuffer.txt | 6 +- test/PhysicObject.h | 2 +- test/Physics/Include/EasyPhysics.h | 2 +- test/data/MeshViewerTestTexture.png | Bin 2337 -> 2570 bytes 7 files changed, 537 insertions(+), 125 deletions(-) diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index 82f03921..8c3ffdde 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -102,9 +102,9 @@ DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode) { bool with_UV = false; m_render_mode = render_mode; - m_vert_decl_flags = (VertexUsage::Position << 1) | - (VertexUsage::Normal << 1) | - (VertexUsage::Color << 1); + m_vert_decl_flags = (1 << VertexUsage::Position) | + (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color); if (render_mode == DebugRenderMode::Default) m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shiny)); @@ -117,7 +117,7 @@ DefaultShaderData::DefaultShaderData(DebugRenderMode render_mode) else if (render_mode == DebugRenderMode::UV) { m_shader = Shader::Create(LOLFX_RESOURCE_NAME(shinydebugUV)); - m_vert_decl_flags |= (VertexUsage::TexCoord << 1); + m_vert_decl_flags |= (1 << VertexUsage::TexCoord); with_UV = true; } SetupDefaultData(with_UV); @@ -241,22 +241,22 @@ void GpuEasyMeshData::SetupVertexData(uint16_t vdecl_flags, EasyMesh* src_mesh) memcpy(mesh, vbo_data, vbo_bytes); \ new_vbo->Unlock(); - if (vdecl_flags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | - (VertexUsage::Color<<1) | (VertexUsage::TexCoord<<1))) + if (vdecl_flags == ((1 << VertexUsage::Position) | (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color) | (1 << VertexUsage::TexCoordExt))) { new_vdecl = new VertexDeclaration( - VertexStream( + VertexStream( VertexUsage::Position, VertexUsage::Normal, VertexUsage::Color, VertexUsage::TexCoord)); - Array vertexlist; + Array vertexlist; for (int i = 0; i < src_mesh->m_vert.Count(); i++) vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_normal, (u8vec4)(src_mesh->m_vert[i].m_color * 255.f), - src_mesh->m_vert[i].m_texcoord.xy); + src_mesh->m_vert[i].m_texcoord); vbo_data = &vertexlist[0]; vbo_bytes = vertexlist.Bytes(); @@ -264,22 +264,22 @@ void GpuEasyMeshData::SetupVertexData(uint16_t vdecl_flags, EasyMesh* src_mesh) COPY_VBO; } - else if (vdecl_flags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | - (VertexUsage::Color<<1) | (VertexUsage::TexCoordExt<<1))) + else if (vdecl_flags == ((1 << VertexUsage::Position) | (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color) | (1 << VertexUsage::TexCoord))) { new_vdecl = new VertexDeclaration( - VertexStream( + VertexStream( VertexUsage::Position, VertexUsage::Normal, VertexUsage::Color, VertexUsage::TexCoord)); - Array vertexlist; + Array vertexlist; for (int i = 0; i < src_mesh->m_vert.Count(); i++) vertexlist.Push(src_mesh->m_vert[i].m_coord, src_mesh->m_vert[i].m_normal, (u8vec4)(src_mesh->m_vert[i].m_color * 255.f), - src_mesh->m_vert[i].m_texcoord); + src_mesh->m_vert[i].m_texcoord.xy); vbo_data = &vertexlist[0]; vbo_bytes = vertexlist.Bytes(); @@ -287,8 +287,8 @@ void GpuEasyMeshData::SetupVertexData(uint16_t vdecl_flags, EasyMesh* src_mesh) COPY_VBO; } - else if (vdecl_flags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | - (VertexUsage::Color<<1))) + else if (vdecl_flags == ((1 << VertexUsage::Position) | (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color))) { new_vdecl = new VertexDeclaration( VertexStream( @@ -335,16 +335,16 @@ void GpuEasyMeshData::RenderMeshData(mat4 const &model) vdecl->Bind(); - if (vflags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | - (VertexUsage::Color<<1) | (VertexUsage::TexCoord<<1))) + if (vflags == ((1 << VertexUsage::Position) | (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color) | (1 << VertexUsage::TexCoord))) { vdecl->SetStream(vbo, *gpu_sd.GetAttribute(lol::String("in_Vertex")), *gpu_sd.GetAttribute(lol::String("in_Normal")), *gpu_sd.GetAttribute(lol::String("in_Color")), *gpu_sd.GetAttribute(lol::String("in_TexCoord"))); } - else if (vflags == ((VertexUsage::Position<<1) | (VertexUsage::Normal<<1) | - (VertexUsage::Color<<1))) + else if (vflags == ((1 << VertexUsage::Position) | (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color))) { vdecl->SetStream(vbo, *gpu_sd.GetAttribute(lol::String("in_Vertex")), *gpu_sd.GetAttribute(lol::String("in_Normal")), @@ -359,8 +359,7 @@ void GpuEasyMeshData::RenderMeshData(mat4 const &model) //----------------------------------------------------------------------------- EasyMesh::EasyMesh() - : m_color(0), m_color2(0), m_ignore_winding_on_scale(0), - m_texcoord_offset(vec2(.0f)), m_texcoord_scale(vec2(1.f)) + : m_build_data(NULL) { m_cursors.Push(0, 0); } @@ -369,7 +368,9 @@ EasyMesh::EasyMesh() bool EasyMesh::Compile(char const *command) { EasyMeshCompiler mc(*this); - return mc.ParseString(command); + bool res = mc.ParseString(command); + delete(m_build_data); + return res; } //----------------------------------------------------------------------------- @@ -399,9 +400,9 @@ void EasyMesh::MeshConvert(Shader* provided_shader) { if (provided_shader) { - GpuShaderData *new_gpu_sdata = new DefaultShaderData(((VertexUsage::Position<<1) | - (VertexUsage::Normal<<1) | - (VertexUsage::Color<<1)), + GpuShaderData *new_gpu_sdata = new DefaultShaderData(((1 << VertexUsage::Position) | + (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color)), provided_shader, false); m_gpu_data.AddGpuData(new_gpu_sdata, this); @@ -766,25 +767,25 @@ void EasyMesh::MeshCsg(CSGUsage csg_operation) //----------------------------------------------------------------------------- void EasyMesh::ToggleScaleWinding() { - m_ignore_winding_on_scale = !m_ignore_winding_on_scale; + BD()->Toggle(MeshBuildOperation::Scale_Winding); } //----------------------------------------------------------------------------- void EasyMesh::SetCurColor(vec4 const &color) { - m_color = color; + BD()->Color() = color; } //----------------------------------------------------------------------------- void EasyMesh::SetCurColor2(vec4 const &color) { - m_color2 = color; + BD()->Color2() = color; } //----------------------------------------------------------------------------- void EasyMesh::AddVertex(vec3 const &coord) { - m_vert.Push(VertexData(coord, vec3(0.f, 1.f, 0.f), m_color)); + m_vert.Push(VertexData(coord, vec3(0.f, 1.f, 0.f), BD()->Color())); } //----------------------------------------------------------------------------- @@ -1054,8 +1055,15 @@ void EasyMesh::SetVertColor(vec4 const &color) //----------------------------------------------------------------------------- void EasyMesh::SetTexCoordData(vec2 const &new_offset, vec2 const &new_scale) { - m_texcoord_offset = new_offset; - m_texcoord_scale = 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; } //----------------------------------------------------------------------------- @@ -1077,9 +1085,9 @@ void EasyMesh::SetCurVertTexCoord(vec2 const &texcoord) } //----------------------------------------------------------------------------- -void EasyMesh::SetCurVertTexCoord(vec4 const &texcoord) +void EasyMesh::SetCurVertTexCoord2(vec2 const &texcoord) { - m_vert[m_vert.Count() - 1].m_texcoord = texcoord; + m_vert[m_vert.Count() - 1].m_texcoord = vec4(m_vert[m_vert.Count() - 1].m_texcoord.xy, texcoord); } //----------------------------------------------------------------------------- @@ -1237,7 +1245,7 @@ void EasyMesh::Scale(vec3 const &s) } /* Flip winding if the scaling involves mirroring */ - if (!m_ignore_winding_on_scale && s.x * s.y * s.z < 0) + if (!BD()->IsEnabled(MeshBuildOperation::Scale_Winding) && s.x * s.y * s.z < 0) { for (int i = m_cursors.Last().m2; i < m_indices.Count(); i += 3) { @@ -1280,10 +1288,10 @@ void EasyMesh::AppendCylinder(int nsides, float h, float d1, float d2, float r2 = d2 * .5f; //SAVE - vec4 Saved_Color = m_color; - vec4 Saved_Color2 = m_color2; - vec2 Save_texcoord_offset = m_texcoord_offset; - vec2 Save_texcoord_scale = m_texcoord_scale; + vec4 Saved_Color = BD()->Color(); + vec4 Saved_Color2 = BD()->Color2(); + vec2 Save_texcoord_offset = BD()->TexCoordOffset(); + vec2 Save_texcoord_scale = BD()->TexCoordScale(); int vbase = m_vert.Count(); @@ -1307,9 +1315,9 @@ void EasyMesh::AppendCylinder(int nsides, float h, float d1, float d2, * means duplicating the vertices again... */ for (int i = 0; i < nsides; i++) { - AddVertex(p1); SetCurVertNormal(n); SetCurVertTexCoord(uv1); - AddVertex(p2); SetCurVertNormal(n); SetCurVertTexCoord(uv2); - SetCurVertColor(m_color2); + AddVertex(p1); SetCurVertNormal(n); SetCurVertTexCoord(uv1); SetCurVertTexCoord2(uv1); + AddVertex(p2); SetCurVertNormal(n); SetCurVertTexCoord(uv2); SetCurVertTexCoord2(uv2); + SetCurVertColor(BD()->Color2()); if (smooth) { @@ -1324,9 +1332,9 @@ void EasyMesh::AppendCylinder(int nsides, float h, float d1, float d2, if (!smooth) { - AddVertex(p1); SetCurVertNormal(n); SetCurVertTexCoord(uv1); - AddVertex(p2); SetCurVertNormal(n); SetCurVertTexCoord(uv2); - SetCurVertColor(m_color2); + AddVertex(p1); SetCurVertNormal(n); SetCurVertTexCoord(uv1); SetCurVertTexCoord2(uv1); + AddVertex(p2); SetCurVertNormal(n); SetCurVertTexCoord(uv2); SetCurVertTexCoord2(uv2); + SetCurVertColor(BD()->Color2()); AppendQuad(i * 4 + 2, i * 4 + 3, i * 4 + 1, i * 4, vbase); if (dualside) @@ -1342,13 +1350,13 @@ void EasyMesh::AppendCylinder(int nsides, float h, float d1, float d2, OpenBrace(); //LOWER DISC SetTexCoordData(vec2(.0f, .5f), vec2(.5f, .5f)); - SetCurColor(m_color); + SetCurColor(BD()->Color()); AppendDisc(nsides, d1); Translate(vec3(.0f, h, .0f)); RotateX(180.0f); //UPPER DISC SetTexCoordData(vec2(.5f, .5f), vec2(.5f, .5f)); - SetCurColor(m_color2); + SetCurColor(BD()->Color2()); AppendDisc(nsides, d2); Translate(vec3(.0f, h * .5f, .0f)); CloseBrace(); @@ -1492,6 +1500,7 @@ void EasyMesh::AppendCapsule(int ndivisions, float h, float d) else new_uv = uv[rid[0]]; SetCurVertTexCoord(vec2(0.f, 1.f) - new_uv); + SetCurVertTexCoord2(vec2(0.f, 1.f) - new_uv); } AppendTriangle(0, 2, 1, m_vert.Count() - 3); } @@ -1545,6 +1554,7 @@ void EasyMesh::AppendTorus(int ndivisions, float d1, float d2) AddVertex(vec3(x2, y, z2)); SetCurVertTexCoord(vec2((float)(i + di) / (float)nidiv, (float)(j + dj) / (float)nidiv)); + SetCurVertTexCoord2(vec2((float)(i + di) / (float)nidiv, (float)(j + dj) / (float)nidiv)); } AppendTriangle(0, 2, 3, m_vert.Count() - 4); @@ -1586,62 +1596,125 @@ void EasyMesh::AppendBox(vec3 const &size, float chamf, bool smooth) vec3 d = size * 0.5f; + MeshType mt = MeshType::Box; + TexCoordPos bl = TexCoordPos::BL; + TexCoordPos br = TexCoordPos::BR; + TexCoordPos tl = TexCoordPos::TL; + TexCoordPos tr = TexCoordPos::TR; + + //-- //Side vertices + //-- + MeshFaceType mft = MeshFaceType::BoxFront; AddVertex(vec3(-d.x, -d.y, -d.z - chamf)); - SetCurVertTexCoord(vec2(0.f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x, +d.y, -d.z - chamf)); - SetCurVertTexCoord(vec2(0.f, 0.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, +d.y, -d.z - chamf)); - SetCurVertTexCoord(vec2(.5f, 0.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, -d.y, -d.z - chamf)); - SetCurVertTexCoord(vec2(.5f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- + mft = MeshFaceType::BoxLeft; AddVertex(vec3(-d.x - chamf, -d.y, +d.z)); - SetCurVertTexCoord(vec2(.5f, 0.5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x - chamf, +d.y, +d.z)); - SetCurVertTexCoord(vec2(.5f, 0.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x - chamf, +d.y, -d.z)); - SetCurVertTexCoord(vec2(1.f, 0.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x - chamf, -d.y, -d.z)); - SetCurVertTexCoord(vec2(1.f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- + mft = MeshFaceType::BoxBack; AddVertex(vec3(+d.x, -d.y, +d.z + chamf)); - SetCurVertTexCoord(vec2(0.f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, +d.y, +d.z + chamf)); - SetCurVertTexCoord(vec2(0.f, 0.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x, +d.y, +d.z + chamf)); - SetCurVertTexCoord(vec2(.5f, 0.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x, -d.y, +d.z + chamf)); - SetCurVertTexCoord(vec2(.5f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- + mft = MeshFaceType::BoxRight; AddVertex(vec3(+d.x + chamf, -d.y, -d.z)); - SetCurVertTexCoord(vec2(.5f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x + chamf, +d.y, -d.z)); - SetCurVertTexCoord(vec2(.5f, .0f)); + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x + chamf, +d.y, +d.z)); - SetCurVertTexCoord(vec2(1.f, .0f)); + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x + chamf, -d.y, +d.z)); - SetCurVertTexCoord(vec2(1.f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- //Bottom vertices + //-- + mft = MeshFaceType::BoxBottom; AddVertex(vec3(-d.x, -d.y - chamf, +d.z)); - SetCurVertTexCoord(vec2(.5f, 1.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x, -d.y - chamf, -d.z)); - SetCurVertTexCoord(vec2(.5f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, -d.y - chamf, -d.z)); - SetCurVertTexCoord(vec2(.0f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, -d.y - chamf, +d.z)); - SetCurVertTexCoord(vec2(.0f, 1.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- //Top vertices + //-- + mft = MeshFaceType::BoxTop; AddVertex(vec3(-d.x, +d.y + chamf, -d.z)); - SetCurVertTexCoord(vec2(1.f, 1.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(-d.x, +d.y + chamf, +d.z)); - SetCurVertTexCoord(vec2(1.f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, +d.y + chamf, +d.z)); - SetCurVertTexCoord(vec2(.5f, .5f)); + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + //-- AddVertex(vec3(+d.x, +d.y + chamf, -d.z)); - SetCurVertTexCoord(vec2(.5f, 1.f)); + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); /* The 6 quads on each side of the box */ for (int i = 0; i < 24; i += 4) @@ -1707,7 +1780,7 @@ void EasyMesh::AppendStar(int nbranches, float d1, float d2, int vbase = m_vert.Count(); float maxr = max(r1, r2); - AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); + AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); SetCurVertTexCoord2(vec2(.5f, .5f)); mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f); vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f); @@ -1719,13 +1792,13 @@ void EasyMesh::AppendStar(int nbranches, float d1, float d2, for (int i = 0; i < nbranches; i++) { - AddVertex(p1); SetCurVertTexCoord(uv1.xz + vec2(.5f)); + AddVertex(p1); SetCurVertTexCoord(uv1.xz + vec2(.5f)); SetCurVertTexCoord2(uv1.xz + vec2(.5f)); if (fade2) - SetCurVertColor(m_color2); + SetCurVertColor(BD()->Color2()); - AddVertex(p2); SetCurVertTexCoord(uv2.xz + vec2(.5f)); + AddVertex(p2); SetCurVertTexCoord(uv2.xz + vec2(.5f)); SetCurVertTexCoord2(uv2.xz + vec2(.5f)); if (fade) - SetCurVertColor(m_color2); + SetCurVertColor(BD()->Color2()); AppendQuad(0, 2 * i + 1, 2 * i + 2, (2 * i + 3) % (2 * nbranches), vbase); @@ -1746,7 +1819,7 @@ void EasyMesh::AppendExpandedStar(int nbranches, float d1, float d2, float extra int vbase = m_vert.Count(); float maxr = (float)max(max(r1, r2), max(r1 + extrar, r2 + extrar)); - AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); + AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); SetCurVertTexCoord2(vec2(.5f, .5f)); mat3 rotmat = mat3::rotate(180.0f / nbranches, 0.f, 1.f, 0.f); vec3 p1(r1, 0.f, 0.f), p2(r2, 0.f, 0.f), @@ -1762,10 +1835,10 @@ void EasyMesh::AppendExpandedStar(int nbranches, float d1, float d2, float extra for (int i = 0; i < nbranches; i++) { - AddVertex(p1); SetCurVertTexCoord(uv1.xz + vec2(.5f)); - AddVertex(p2); SetCurVertTexCoord(uv2.xz + vec2(.5f)); - AddVertex(p3); SetCurVertTexCoord(uv3.xz + vec2(.5f)); SetCurVertColor(m_color2); - AddVertex(p4); SetCurVertTexCoord(uv4.xz + vec2(.5f)); SetCurVertColor(m_color2); + AddVertex(p1); SetCurVertTexCoord(uv1.xz + vec2(.5f)); SetCurVertTexCoord2(uv1.xz + vec2(.5f)); + AddVertex(p2); SetCurVertTexCoord(uv2.xz + vec2(.5f)); SetCurVertTexCoord2(uv2.xz + vec2(.5f)); + AddVertex(p3); SetCurVertTexCoord(uv3.xz + vec2(.5f)); SetCurVertTexCoord2(uv3.xz + vec2(.5f)); SetCurVertColor(BD()->Color2()); + AddVertex(p4); SetCurVertTexCoord(uv4.xz + vec2(.5f)); SetCurVertTexCoord2(uv4.xz + vec2(.5f)); SetCurVertColor(BD()->Color2()); int j = (i + 1) % nbranches; AppendQuad(0, 4 * i + 1, 4 * i + 2, 4 * j + 1, vbase); @@ -1787,7 +1860,7 @@ void EasyMesh::AppendDisc(int nsides, float d, int fade) int vbase = m_vert.Count(); - AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); + AddVertex(vec3(0.f, 0.f, 0.f)); SetCurVertTexCoord(vec2(.5f, .5f)); SetCurVertTexCoord2(vec2(.5f, .5f)); mat3 rotmat = mat3::rotate(360.0f / nsides, 0.f, 1.f, 0.f); vec3 p1(r, 0.f, 0.f); @@ -1795,9 +1868,9 @@ void EasyMesh::AppendDisc(int nsides, float d, int fade) for (int i = 0; i < nsides; i++) { - AddVertex(p1); SetCurVertTexCoord(uv.xz + vec2(.5f, .5f)); + AddVertex(p1); SetCurVertTexCoord(uv.xz + vec2(.5f, .5f)); SetCurVertTexCoord2(uv.xz + vec2(.5f, .5f)); if (fade) - SetCurVertColor(m_color2); + SetCurVertColor(BD()->Color2()); AppendTriangle(0, i + 1, ((i + 1) % nsides) + 1, vbase); p1 = rotmat * p1; uv = rotmat * uv; @@ -1813,15 +1886,15 @@ void EasyMesh::AppendSimpleTriangle(float d, int fade) mat3 m = mat3::rotate(120.f, 0.f, 1.f, 0.f); vec3 p(0.f, 0.f, size); - AddVertex(p); SetCurVertTexCoord(vec2(.5f, 0.133975f)); + AddVertex(p); SetCurVertTexCoord(vec2(.5f, 0.133975f)); SetCurVertTexCoord2(vec2(.5f, 0.133975f)); p = m * p; - AddVertex(p); SetCurVertTexCoord(vec2(0.f, 1.f)); + AddVertex(p); SetCurVertTexCoord(vec2(0.f, 1.f)); SetCurVertTexCoord2(vec2(0.f, 1.f)); if (fade) - SetCurVertColor(m_color2); + SetCurVertColor(BD()->Color2()); p = m * p; - AddVertex(p); SetCurVertTexCoord(vec2(1.f, 1.f)); + AddVertex(p); SetCurVertTexCoord(vec2(1.f, 1.f)); SetCurVertTexCoord2(vec2(1.f, 1.f)); if (fade) - SetCurVertColor(m_color2); + SetCurVertColor(BD()->Color2()); AppendTriangle(0, 1, 2, m_vert.Count() - 3); } @@ -1835,12 +1908,31 @@ void EasyMesh::AppendSimpleQuad(float size, int fade) //----------------------------------------------------------------------------- void EasyMesh::AppendSimpleQuad(vec2 p1, vec2 p2, float z, int fade) { - AddVertex(vec3(p2.x, z, -p1.y)); SetCurVertTexCoord(vec2(1.f, 0.f)); - AddVertex(vec3(p2.x, z, -p2.y)); SetCurVertTexCoord(vec2(0.f, 0.f)); - AddVertex(vec3(p1.x, z, -p2.y)); SetCurVertTexCoord(vec2(0.f, 1.f)); - if (fade) SetCurVertColor(m_color2); - AddVertex(vec3(p1.x, z, -p1.y)); SetCurVertTexCoord(vec2(1.f, 1.f)); - if (fade) SetCurVertColor(m_color2); + MeshType mt = MeshType::Quad; + MeshFaceType mft = MeshFaceType::QuadDefault; + + //-- + AddVertex(vec3(p2.x, z, -p1.y)); + TexCoordPos br = TexCoordPos::BR; + SetCurVertTexCoord(BD()->TexCoord(mt, br, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, br, mft)); + //-- + AddVertex(vec3(p2.x, z, -p2.y)); + TexCoordPos bl = TexCoordPos::BL; + SetCurVertTexCoord(BD()->TexCoord(mt, bl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, bl, mft)); + //-- + AddVertex(vec3(p1.x, z, -p2.y)); + TexCoordPos tl = TexCoordPos::TL; + SetCurVertTexCoord(BD()->TexCoord(mt, tl, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tl, mft)); + if (fade) SetCurVertColor(BD()->Color2()); + //-- + AddVertex(vec3(p1.x, z, -p1.y)); + TexCoordPos tr = TexCoordPos::TR; + SetCurVertTexCoord(BD()->TexCoord(mt, tr, mft)); + SetCurVertTexCoord2(BD()->TexCoord2(mt, tr, mft)); + if (fade) SetCurVertColor(BD()->Color2()); AppendQuad(0, 1, 2, 3, m_vert.Count() - 4); ComputeNormals(m_indices.Count() - 6, 6); @@ -2065,18 +2157,28 @@ void EasyMesh::AppendCog(int nbsides, float h, float d10, float d20, else add = upadd; SetCurVertTexCoord(tmp * vec2(.25f) + add); + SetCurVertTexCoord2(tmp * vec2(.25f) + add); } else if (m == 0 || m == 1) //inner Logic + { SetCurVertTexCoord(uv[d]); + SetCurVertTexCoord2(uv[d]); + } else //Cog logic { if (m == 2 && n % 3 == 2) + { SetCurVertTexCoord(vec2(1.f, (d == 2)?(0.f):(1.f)) * CogUV[0] + CogUV[1]); + SetCurVertTexCoord2(vec2(1.f, (d == 2)?(0.f):(1.f)) * CogUV[0] + CogUV[1]); + } else + { SetCurVertTexCoord(uv[d]); + SetCurVertTexCoord2(uv[d]); + } } if (d >= 6) - SetCurVertColor(m_color2); + SetCurVertColor(BD()->Color2()); } int l = -4; diff --git a/src/easymesh/easymesh.h b/src/easymesh/easymesh.h index 39e02b3f..9716b701 100644 --- a/src/easymesh/easymesh.h +++ b/src/easymesh/easymesh.h @@ -109,6 +109,324 @@ private: int m_indexcount; }; + +struct MeshBuildOperation +{ + enum Value + { + //When this flag is up, negative scaling will not invert faces. + Scale_Winding = 1 << 0, + + All = 0xffffffff + } + m_value; + + inline MeshBuildOperation(Value v) : m_value(v) {} + inline MeshBuildOperation(uint64_t i) : m_value((Value)i) {} + inline operator Value() { return m_value; } +}; + +struct MeshType +{ + enum Value + { + Triangle = 0, + Quad, + Box, + Sphere, + Capsule, + Torus, + Cylinder, + Disc, + Star, + ExpandedStar, + Cog, + + Max + } + m_value; + + inline MeshType(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +//TODO : Add other Build type +struct TexCoordBuildType +{ + enum Value + { + TriangleDefault = 0, + QuadDefault = 0, + BoxDefault = 0, + SphereDefault = 0, + CapsuleDefault = 0, + TorusDefault = 0, + CylinderDefault = 0, + DiscDefault = 0, + StarDefault = 0, + ExpandedStarDefault = 0, + CogDefault = 0, + + Max + } + m_value; + + inline TexCoordBuildType() : m_value(TriangleDefault) {} + inline TexCoordBuildType(Value v) : m_value(v) {} + inline TexCoordBuildType(int v) : m_value((Value)v) {} + inline operator Value() { return m_value; } +}; + +struct MeshFaceType +{ + enum Value + { + BoxFront = 0, + BoxLeft = 1, + BoxBack = 2, + BoxRight = 3, + BoxTop = 4, + BoxBottom = 5, + QuadDefault = 0, + + Max + } + m_value; + + inline MeshFaceType(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +struct TexCoordPos +{ + enum Value + { + BL, //BottomLeft + BR, //BottomRight + TL, //TopLeft + TR //TopRight + } + m_value; + + inline TexCoordPos(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + +class EasyMeshBuildData +{ +public: + EasyMeshBuildData() + { + m_color = vec4(0.f, 0.f, 0.f, 1.f); + m_color2 = vec4(0.f, 0.f, 0.f, 1.f); + m_texcoord_offset = vec2(0.f); + m_texcoord_offset2 = vec2(0.f); + m_texcoord_scale = vec2(1.f); + m_texcoord_scale2 = vec2(1.f); + m_build_flags = 0; + for (int i = 0; i < MeshType::Max; ++i) + { + m_texcoord_build_type[i] = TexCoordBuildType::TriangleDefault; + m_texcoord_build_type2[i] = TexCoordBuildType::TriangleDefault; + } + } + + inline vec4 &Color() { return m_color; } + inline vec4 &Color2() { return m_color2; } + inline vec2 &TexCoordOffset() { return m_texcoord_offset; } + inline vec2 &TexCoordScale() { return m_texcoord_scale; } + inline vec2 &TexCoordOffset2() { return m_texcoord_offset2; } + inline vec2 &TexCoordScale2() { return m_texcoord_scale2; } + + //UV1 + void SetTexCoordBuildType(MeshType mt, TexCoordBuildType tcbt) { m_texcoord_build_type[mt] = (1 << (tcbt + 1)) | (m_texcoord_build_type[mt] & 1); } + TexCoordBuildType GetTexCoordBuildType(MeshType mt) + { + int flag = ((m_texcoord_build_type[mt] & ~(1)) >> 1); + int i = 0; + while (flag >>= 1) + i++; + return TexCoordBuildType(i); + } + void SetTexCoordCustomBuild(MeshType mt, MeshFaceType face, vec2 BL, vec2 TR) + { + if (face >= m_texcoord_custom_build[mt].Count()) + m_texcoord_custom_build[mt].Resize(face + 1); + m_texcoord_custom_build[mt][face].m1 = BL; + m_texcoord_custom_build[mt][face].m2 = TR; + m_texcoord_build_type[mt] |= 1; + } + void ClearTexCoordCustomBuild(MeshType mt) { m_texcoord_build_type[mt] &= ~1; } + /* FIXME : Do something better ? */ + vec2 TexCoord(MeshType mt, TexCoordPos tcp, MeshFaceType face) + { + vec2 BL = vec2(0.f); + vec2 TR = vec2(0.f); + if (m_texcoord_build_type[mt] & 1 && face < m_texcoord_custom_build[mt].Count()) + { + BL = m_texcoord_custom_build[mt][face].m1; + TR = m_texcoord_custom_build[mt][face].m2; + } + else + { + TexCoordBuildType tcbt = GetTexCoordBuildType(mt); + if (mt == MeshType::Triangle) + mt = mt; + else if (mt == MeshType::Quad) + { + //There's nothin' else than QuadDefault + BL = vec2(0.f); + TR = vec2(1.f); + } + else if (mt == MeshType::Box) + { + vec2 data[][2] = + { //TexCoordBuildType::BoxDefault + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f, .5f), vec2(.5f, 1.f) }, + { vec2(.5f, .5f), vec2(1.f, 1.f) } + }; + BL = data[face][0]; //[tcbt] + TR = data[face][1]; //[tcbt] + } + else if (mt == MeshType::Sphere) + mt = mt; + else if (mt == MeshType::Capsule) + mt = mt; + else if (mt == MeshType::Torus) + mt = mt; + else if (mt == MeshType::Cylinder) + mt = mt; + else if (mt == MeshType::Disc) + mt = mt; + else if (mt == MeshType::Star) + mt = mt; + else if (mt == MeshType::ExpandedStar) + mt = mt; + else if (mt == MeshType::Cog) + mt = mt; + } + + vec2 res = vec2(.0f); + if (tcp == TexCoordPos::BL) + res = BL; + else if (tcp == TexCoordPos::BR) + res = vec2(TR.x, BL.y); + else if (tcp == TexCoordPos::TL) + res = vec2(BL.x, TR.y); + else if (tcp == TexCoordPos::TR) + res = TR; + + return res * m_texcoord_scale + m_texcoord_offset2; + } + + //UV2 + void SetTexCoordBuildType2(MeshType mt, TexCoordBuildType tcbt) { m_texcoord_build_type2[mt] = (1 << (tcbt + 1)) | (m_texcoord_build_type2[mt] & 1); } + TexCoordBuildType GetTexCoordBuildType2(MeshType mt) + { + int flag = ((m_texcoord_build_type2[mt] & ~(1)) >> 1); + int i = 0; + while (flag >>= 1) + i++; + return TexCoordBuildType(i); + } + void SetTexCoordCustomBuild2(MeshType mt, MeshFaceType face, vec2 BL, vec2 TR) + { + if (face >= m_texcoord_custom_build2[mt].Count()) + m_texcoord_custom_build2[mt].Resize(face + 1); + m_texcoord_custom_build2[mt][face].m1 = BL; + m_texcoord_custom_build2[mt][face].m2 = TR; + m_texcoord_build_type2[mt] |= 1; + } + void ClearTexCoordCustomBuild2(MeshType mt) { m_texcoord_build_type2[mt] &= ~1; } + vec2 TexCoord2(MeshType mt, TexCoordPos tcp, MeshFaceType face) + { + vec2 BL = vec2(0.f); + vec2 TR = vec2(0.f); + if (m_texcoord_build_type2[mt] & 1 && face < m_texcoord_custom_build2[mt].Count()) + { + BL = m_texcoord_custom_build2[mt][face].m1; + TR = m_texcoord_custom_build2[mt][face].m2; + } + else + { + TexCoordBuildType tcbt = GetTexCoordBuildType2(mt); + if (mt == MeshType::Triangle) + mt = mt; + else if (mt == MeshType::Quad) + { + //There's nothin' else than QuadDefault + BL = vec2(0.f); + TR = vec2(1.f); + } + else if (mt == MeshType::Box) + { + vec2 data[][2] = + { //TexCoordBuildType::BoxDefault + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f), vec2(.5f) }, + { vec2(.5f, 0.f), vec2(1.f, .5f) }, + { vec2(0.f, .5f), vec2(.5f, 1.f) }, + { vec2(.5f, .5f), vec2(1.f, 1.f) } + }; + BL = data[face][0]; //[tcbt] + TR = data[face][1]; //[tcbt] + } + else if (mt == MeshType::Sphere) + mt = mt; + else if (mt == MeshType::Capsule) + mt = mt; + else if (mt == MeshType::Torus) + mt = mt; + else if (mt == MeshType::Cylinder) + mt = mt; + else if (mt == MeshType::Disc) + mt = mt; + else if (mt == MeshType::Star) + mt = mt; + else if (mt == MeshType::ExpandedStar) + mt = mt; + else if (mt == MeshType::Cog) + mt = mt; + } + + vec2 res = vec2(.0f); + if (tcp == TexCoordPos::BL) + res = BL; + else if (tcp == TexCoordPos::BR) + res = vec2(TR.x, BL.y); + else if (tcp == TexCoordPos::TL) + res = vec2(BL.x, TR.y); + else if (tcp == TexCoordPos::TR) + res = TR; + + return res * m_texcoord_scale + m_texcoord_offset2; + } + + inline bool IsEnabled(MeshBuildOperation mbo) { return (m_build_flags & mbo) != 0; } + inline void Enable(MeshBuildOperation mbo) { m_build_flags |= mbo; } + inline void Disable(MeshBuildOperation mbo) { m_build_flags &= ~mbo; } + inline void Toggle(MeshBuildOperation mbo) { m_build_flags ^= mbo; } + inline void Set(MeshBuildOperation mbo, bool value) { if (value) Enable(mbo); else Disable(mbo); } + +public: + vec4 m_color; + vec4 m_color2; + vec2 m_texcoord_offset; + vec2 m_texcoord_offset2; + vec2 m_texcoord_scale; + vec2 m_texcoord_scale2; + int m_texcoord_build_type[MeshType::Max]; + Array m_texcoord_custom_build[MeshType::Max]; + int m_texcoord_build_type2[MeshType::Max]; + Array m_texcoord_custom_build2[MeshType::Max]; + uint16_t m_build_flags; +}; + /* A safe enum for MeshCSG operations. */ struct CSGUsage { @@ -176,21 +494,6 @@ struct Axis inline operator Value() { return m_value; } }; -struct MeshBuildOperation -{ - enum Value - { - Scale_Winding = 1 << 0, - - All = 0xffffffff - } - m_value; - - inline MeshBuildOperation(Value v) : m_value(v) {} - inline MeshBuildOperation(uint64_t i) : m_value((Value)i) {} - inline operator Value() { return m_value; } -}; - class EasyMesh { friend class EasyMeshParser; @@ -255,11 +558,12 @@ public: //DEBUG //------------------------------------------------------------------------- void SetVertColor(vec4 const &color); void SetTexCoordData(vec2 const &new_offset, vec2 const &new_scale); + void SetTexCoordData2(vec2 const &new_offset, vec2 const &new_scale); void SetCurVertNormal(vec3 const &normal); void SetCurVertColor(vec4 const &color); void SetCurVertTexCoord(vec2 const &texcoord); - void SetCurVertTexCoord(vec4 const &texcoord); + void SetCurVertTexCoord2(vec2 const &texcoord); public: //------------------------------------------------------------------------- @@ -504,22 +808,25 @@ public: vec3 const &GetVertexLocation(int i) { return m_vert[i].m_coord; } private: - vec4 m_color, m_color2; Array m_indices; Array m_vert; // Array m_cursors; - //When this flag is up, negative scaling will not invert faces. - bool m_ignore_winding_on_scale; - //Texture coordinate modifiers. - vec2 m_texcoord_offset; - vec2 m_texcoord_scale; friend class GpuEasyMeshData; GpuEasyMeshData m_gpu_data; -}; +public: + inline EasyMeshBuildData* BD() + { + if (!m_build_data) + m_build_data = new EasyMeshBuildData(); + return m_build_data; + }; +private: + class EasyMeshBuildData* m_build_data; +}; } /* namespace lol */ #endif /* __EASYMESH_EASYMESH_H__ */ diff --git a/test/MeshViewer.cpp b/test/MeshViewer.cpp index b3c15a9d..9803e956 100644 --- a/test/MeshViewer.cpp +++ b/test/MeshViewer.cpp @@ -353,8 +353,11 @@ public: #if WITH_FUR m_meshes[i].m1.MeshConvert(Shader::Create(LOLFX_RESOURCE_NAME(shinyfur))); #else - m_meshes[i].m1.MeshConvert(m_texture_shader); + //m_meshes[i].m1.MeshConvert(m_texture_shader); //m_meshes[i].m1.MeshConvert(); + m_meshes[i].m1.MeshConvert(new DefaultShaderData(((1 << VertexUsage::Position) | (1 << VertexUsage::Normal) | + (1 << VertexUsage::Color) | (VertexUsage::TexCoord)), + m_texture_shader, true)); #endif m_meshes[i].m2 = true; } diff --git a/test/MeshViewerBuffer.txt b/test/MeshViewerBuffer.txt index 1ff9ddac..6cb5e1a7 100644 --- a/test/MeshViewerBuffer.txt +++ b/test/MeshViewerBuffer.txt @@ -1,7 +1,7 @@ -[sc#fff scb#fff ato 20 8 12 rx0] -[sc#fff scb#fff acg 8 2 5 1 6 8 4 2 .1 1] +//[sc#fff scb#fff ato 20 8 12 rx0] +//[sc#fff scb#fff acg 8 2 5 1 6 8 4 2 .1 1] -//[sc#fff ab 4 4 4 smth 0 1 1 ]//twy 45 0 bdxy 90 0 splt 5 tz 2 +[sc#fff ab 4 4 4 smth 0 1 1 ]//twy 45 0 bdxy 90 0 splt 5 tz 2 //[sc#88f ab 4 4 4 tx 4 ab 4 4 4 tx -2 tax .4 .4 0] //[sc#88f ab .25 1 1 tx .25 ab .25 1 1 tx .25 ab .25 1 1 tx .25 ab .25 1 1 tx .125 stx 10 0 0] // tax -2 0 0 0 diff --git a/test/PhysicObject.h b/test/PhysicObject.h index 65893d94..e878d7a1 100644 --- a/test/PhysicObject.h +++ b/test/PhysicObject.h @@ -218,7 +218,7 @@ public: } m_physics->SetCollisionChannel(0, 0xFF); - //m_physics->SetCollisionChannel(ColGroup, (1<SetCollisionChannel(ColGroup, (1 << ColGroup)|(1)); m_physics->SetMass(base_mass); m_physics->SetTransform(base_location); m_physics->InitBodyToRigid(); diff --git a/test/Physics/Include/EasyPhysics.h b/test/Physics/Include/EasyPhysics.h index 90ce04b7..93578db1 100644 --- a/test/Physics/Include/EasyPhysics.h +++ b/test/Physics/Include/EasyPhysics.h @@ -111,7 +111,7 @@ public: { if (CanChangeCollisionChannel()) { - m_collision_group = (1<vp3s41{UY_kZS1 zn~<{z%;)i?4lv|L&mJ2Yr15AhJK1Tv4gP#hV?VdS*Vo`{nqCeV_V?w0Y1H4r0JseX zz?TtV1egQHV&DTfz&ckwRo$TjU18AIFJF%ZRfYt)! zd1@#7xpSAs$+cq+SaHBJL`k+L&r`b*u+K79g1K{-kd|x59MDP!r1E==R4W}2^LHHQ zuXR9jW`_qOosrD}v11sg)DExLQ*$rH?td!;K$a<;yDJ1d4gJ|_&&gOfz#{_x*lL9XeDSR_`e5Epacu+0araAkcxQB z4q>g7+(;_j(|c^{Ev`~K`Z>Xr_K(>iwOWk#AMK2g5nu#tul~#d=74PvB672jn}h?oOj++hTS9iro90qcN$ zu|^TK4p@31CV^(ZA@V7w#a$1u60{Pu5?o;5_*tM*2gLn>%hdzInjoYut9Iw<4MJWEJXtIC80e@uw19pZg z_XVs2_B~((#QH(}_u)^7SO-`KSO@%O`m5-G%mGJR4H^N39jjZAWX$V zD?h&|Irvkm16tijO09Q$X@BHe-N)Y>q^fRhdnpIBy03SH$$qOymfA4_C_=s4OC#6n zJ|m!agvoxZNS4}}ru*Q}_cZo%AAEfez8(m8Uc>&r959XgI~V}>!2tL+0*nB2z*r1? z00&qH>_b2;f`LU9_07b|M zr~=^QX3`lnM{CC?`$hoO18O5c_Nf|BJ3iSr0%(rbMu6>B|Tq1p(LeTq=+ z_+;M*pa|7Qfb3I*YR4!0MgZmM7=hOPDNo1oTlZHH(7HdZ*5Ycgb${0CD+Itkg4&Q^}YaxJaiBd!&!i|d~9#61BfGHdvhIN1c3500s=(L0oxu(?hmMQocfysmL8xa zVjZB8JoYySm;)9bAjHrdmD{ZZw>^-oAW?+mc5{F^;AkAs_j6s-5QoStPd7LV zI14O1z<^OJKGfe8A#=c{2V4(Gqyw6xa=V@dtONE_btE!gRGY8NdH3!srfDlG=^xaKv#3=76OKm@+7DTL)-+eQJ832+8fv0)Nf|3l9*2^r~JR#)4d z1>`K?wScrctg<}yr#ULO>sbKK2UrJK2W)!4YXO?vneFl%ryFz*a2B|F7BB*?jsWX` zt0TZ1Ui{VWs0TF&3K(H^Kpg?14p1M6 zs>4+ERe#6pT@_ZJ#|SV2_Ay`%Fb4nzRMOG2fT#o12cq)_bdFCQZ=5z1vv_ z&>XI9r?o)u_TCXD`@JJf_Kg6FQ15n%Q15mlpdELF$$sw$ll^}&0oL(#N+L#cb&+qvDq8nAPK|9@)*t;nzSN_M9fS#=I8UosE=&}z%-Q9k5}3xK$IZZWtAw# z1KAd7c7JbKOlCEvc@t&qp73l^T%~8LD?7klO?Gwhq$ZE6lEZ9oDFw?2kzPQkU?7j$ zzDRs>7>6*J6%X_%HbV?HA>2X*S=M4-)d0!0IyHpIYwiZyd7^m;c*%-IR@bYzyxyY=%sb8IDj zZr7as6DPggj|q7=v)+q>BbR9Fjb%`_3t@WXUFiIcu)ql2C+UE5eSiC%;`BX(?%4Xw z?F;YQey{4P(<1LHwSmSakkke0@D_vdYI;!X1u88r3))B)}orDr89hx!3`(Q|vkRQ?|Tld|S{ z71<+OH@$56P-3d&BAl!kAv-lRGm3)XEc`wcr|LGPF%FYMRkZ!b;%lZ|O|sdYTHff1 zGC-NR07sm5sOnTiRHmm4atjW2+!w3huk3lveW;67TH6wu=n02~B?DoavJm2NV(jX? zp(EtT4jDoq<-HLW;mS^d>M709*y|m_Vy%~yHWw;PnqrNQ+a+J1?RP(svW@O0{lKum zJ4Hb9w*U==PqwJ$@5ebJTT=8)@uR|#3`E?(f1-6!CqQynr)gzG;ZSgTfOI7`w#Zv6 z=shS)p_0UGV&(oq^1o%zfFoNs%eiF#bx8B*41 zQ=s%jfk$-l$;*06YT$HM&3uWa!P7$h8>j{_^o^&@%Y}iVMq>z3Nl5uP#kWL8OO8x zN6*Z_qSX9bVMk3M6NB8Xh6z2lD$u2zA|Ay#IMoqW+nj@*axtWM>4)BkhFMkZZ)kq+ zCr@9?Q-0#>{W@)M`passA&0{R(xUH;Jw6!Ydf>N)d?Du>38renQY3{U;R`aTp5}Qo zO+*N=#8SDvOh4X(!m8x0^pUp+UgPDCnQ;x6G9}~6!{RCD=A)MCaOO7aH8p%gY1U;u z6ZOS8=u-!oGfx+|lePEASFiSrv_a`;H6Yy(d%SH1|Jag`R(9dLqHr=77Sg^mnd1wK zQZo>IO0jje|C`lj*EeSbpUS~+INLinvzScLk29X3hA{4NIJvdU%BVRu^oa|gE% ziC_|6^eliDdXrA8h=U)2XMYXTbn>u9<1z((dsR~$-qG;MAGr%c>(UUR$L(E`0igIF Y&#dLOUBJ%D3cwU=eF6m6yhX?V1uFuW>;M1&