From 70fa8872de45141eddcd2231aeceae0c13127240 Mon Sep 17 00:00:00 2001 From: aismann Date: Thu, 4 Jan 2024 19:07:13 +0100 Subject: [PATCH] Add extension 'DrawNodeEx' aka 'DrawNode v2' (#1568) --- CMakeOptions.md | 1 + core/CMakeLists.txt | 2 + core/base/Types.cpp | 3 + core/base/Types.h | 2 + extensions/CMakeLists.txt | 4 + extensions/DrawNodeEx/CMakeLists.txt | 7 + extensions/DrawNodeEx/DrawNodeEx.cpp | 1213 ++++++++++++++++ extensions/DrawNodeEx/DrawNodeEx.h | 606 ++++++++ extensions/README.md | 6 + tests/cpp-tests/CMakeLists.txt | 5 + .../Source/DrawNodeExTest/DrawNodeExTest.cpp | 1278 +++++++++++++++++ .../Source/DrawNodeExTest/DrawNodeExTest.h | 199 +++ tests/cpp-tests/Source/controller.cpp | 6 +- tests/cpp-tests/Source/tests.h | 6 + 14 files changed, 3337 insertions(+), 1 deletion(-) create mode 100644 extensions/DrawNodeEx/CMakeLists.txt create mode 100644 extensions/DrawNodeEx/DrawNodeEx.cpp create mode 100644 extensions/DrawNodeEx/DrawNodeEx.h create mode 100644 tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.cpp create mode 100644 tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.h diff --git a/CMakeOptions.md b/CMakeOptions.md index a86b72fe6382..64129d087553 100644 --- a/CMakeOptions.md +++ b/CMakeOptions.md @@ -27,6 +27,7 @@ - AX_ENABLE_EXT_EFFEKSEER: the effekseer extension, default: `FALSE` - AX_ENABLE_EXT_JSONDEFAULT: the UserDefault based on json, default: `FALSE` - AX_ENABLE_EXT_LUA: the lua extension, default: `TRUE` + - AX_ENABLE_EXT_DRAWNODEEX: the DrawNodeEx extension, default: `TRUE` - AX_WITH_XXX: usually user don't need care it - AX_VS_DEPLOYMENT_TARGET: specify windows store deploy target, default: `10.0.17763.0` - AX_USE_COMPAT_GL: whether use compat gl as renderer backend, default: win32: `TRUE`, others: `FALSE` diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index aae8924183b1..ebb328f0e467 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -140,6 +140,8 @@ option(AX_DISABLE_GLES2 "Whether disable GLES2 support" OFF) option(AX_ENABLE_EXT_JSONDEFAULT "Build extension JSONDefault" ON) +option(AX_ENABLE_EXT_DRAWNODEEX "Build extension DrawNodeEx" ON) + if(XCODE) # set(CMAKE_BUILD_WITH_INSTALL_RPATH YES) # set(CMAKE_INSTALL_RPATH "@executable_path/Frameworks") diff --git a/core/base/Types.cpp b/core/base/Types.cpp index 9332ed842794..72b62748014c 100644 --- a/core/base/Types.cpp +++ b/core/base/Types.cpp @@ -244,6 +244,7 @@ Color4F operator/(Color4F lhs, float rhs) * Color constants */ + const Color3B Color3B::WHITE(255, 255, 255); const Color3B Color3B::YELLOW(255, 255, 0); const Color3B Color3B::GREEN(0, 255, 0); @@ -263,6 +264,7 @@ const Color4B Color4B::MAGENTA(255, 0, 255, 255); const Color4B Color4B::BLACK(0, 0, 0, 255); const Color4B Color4B::ORANGE(255, 127, 0, 255); const Color4B Color4B::GRAY(166, 166, 166, 255); +const Color4B Color4B::AX_TRANSPARENT(0, 0, 0, 0); const Color4F Color4F::WHITE(1, 1, 1, 1); const Color4F Color4F::YELLOW(1, 1, 0, 1); @@ -273,6 +275,7 @@ const Color4F Color4F::MAGENTA(1, 0, 1, 1); const Color4F Color4F::BLACK(0, 0, 0, 1); const Color4F Color4F::ORANGE(1, 0.5f, 0, 1); const Color4F Color4F::GRAY(0.65f, 0.65f, 0.65f, 1); +const Color4F Color4F::AX_TRANSPARENT(0, 0, 0, 0); HSV::HSV() {} diff --git a/core/base/Types.h b/core/base/Types.h index 21edf4c24317..b3705f0b9c3f 100644 --- a/core/base/Types.h +++ b/core/base/Types.h @@ -122,6 +122,7 @@ struct AX_DLL Color4B static const Color4B BLACK; static const Color4B ORANGE; static const Color4B GRAY; + static const Color4B AX_TRANSPARENT; // TRANSPARENT is defined on wingdi.h /*Background Modes*/ }; /** @@ -158,6 +159,7 @@ struct AX_DLL Color4F static const Color4F BLACK; static const Color4F ORANGE; static const Color4F GRAY; + static const Color4F AX_TRANSPARENT; // TRANSPARENT is defined on wingdi.h /*Background Modes*/ }; Color4F& operator+=(Color4F& lhs, const Color4F& rhs); diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index 138dbc001dca..b95c8ed22eda 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -119,4 +119,8 @@ if(AX_ENABLE_EXT_JSONDEFAULT) add_subdirectory(JSONDefault) endif() +if(AX_ENABLE_EXT_DRAWNODEEX) + add_subdirectory(DrawNodeEx) +endif() + message(STATUS "Enabled ${_AX_CORE_LIB} extensions:${_AX_EXTENSION_LIBS}") diff --git a/extensions/DrawNodeEx/CMakeLists.txt b/extensions/DrawNodeEx/CMakeLists.txt new file mode 100644 index 000000000000..b2f60ae4be92 --- /dev/null +++ b/extensions/DrawNodeEx/CMakeLists.txt @@ -0,0 +1,7 @@ +set(target_name DrawNodeEx) + +FILE(GLOB DRAWNODEEX_SOURCES *.h;*.cpp;./**/*.h;./**/*.cpp) + +add_library(${target_name} ${DRAWNODEEX_SOURCES}) + +setup_ax_extension_config(${target_name}) diff --git a/extensions/DrawNodeEx/DrawNodeEx.cpp b/extensions/DrawNodeEx/DrawNodeEx.cpp new file mode 100644 index 000000000000..7ddf914e255a --- /dev/null +++ b/extensions/DrawNodeEx/DrawNodeEx.cpp @@ -0,0 +1,1213 @@ +/* Copyright (c) 2012 Scott Lembcke and Howling Moon Software + * Copyright (c) 2012 cocos2d-x.org + * Copyright (c) 2013-2016 Chukong Technologies Inc. + * Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + * Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "extensions/DrawNodeEx/DrawNodeEx.h" +#include // offsetof +#include "base/Types.h" +#include "base/EventType.h" +#include "base/Configuration.h" +#include "renderer/Renderer.h" +#include "base/Director.h" +#include "base/EventListenerCustom.h" +#include "base/EventDispatcher.h" +#include "2d/ActionCatmullRom.h" +#include "base/Utils.h" +#include "renderer/Shaders.h" +#include "renderer/backend/ProgramState.h" +#include "poly2tri/poly2tri.h" + +// USING_NS_AX; +NS_AX_EXT_BEGIN + +static inline Tex2F v2ToTex2F(const Vec2& v) +{ + return {v.x, v.y}; +} + +/** Is a polygon convex? + * @param verts A pointer to point coordinates. + * @param count The number of verts measured in points. + */ +static bool isConvex(const Vec2* verts, int count) +{ + bool isPositive = false, isNegative = false; + for (unsigned int i = 0; i < count; i++) + { + Vec2 A = verts[i]; + Vec2 B = verts[(i + 1) % count]; + Vec2 C = verts[(i + 2) % count]; + + double crossProduct = (B.x - A.x) * (C.y - B.y) - (B.y - A.y) * (C.x - B.x); + + if (crossProduct > 0) + { + isPositive = true; + } + else if (crossProduct < 0) + { + isNegative = true; + } + + if (isPositive && isNegative) + return false; // Polygon is concave + } + + return true; // Polygon is convex +} + +Vec2* DrawNodeEx::transform(const Vec2* vertices, unsigned int count) +{ + Vec2* vert = _abuf.get(count); + for (unsigned int i = 0; i < count; i++) + { + if (_dnRotation == 0.0f) + { + vert[i].x = vertices[i].x * _dnScale.x + _dnPosition.x; + vert[i].y = vertices[i].y * _dnScale.y + _dnPosition.y; + } + else // https://stackoverflow.com/questions/2259476/rotating-a-point-about-another-point-2d + { + float s = sin(_dnRotation); + float c = cos(_dnRotation); + + // translate point back to origin: + vert[i].x = vertices[i].x - _dnCenter.x; + vert[i].y = vertices[i].y - _dnCenter.y; + + // rotate point + float xnew = vert[i].x * c - vert[i].y * s; + float ynew = vert[i].x * s + vert[i].y * c; + + // translate point back: + vert[i].x = xnew + _dnCenter.x; + vert[i].y = ynew + _dnCenter.y; + + // scale and position + vert[i].x = vert[i].x * _dnScale.x + _dnPosition.x; + vert[i].y = vert[i].y * _dnScale.y + _dnPosition.y; + } + } + return vert; +} + +// implementation of DrawNodeEx +DrawNodeEx::DrawNodeEx(float lineWidth) + : _lineWidth(lineWidth) + , _defaultLineWidth(lineWidth) + , _isConvex(false) + , _dnPosition(Vec2::ZERO) + , _dnRotation(0.0f) + , _dnScale(Vec2::ONE) +{ + _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; +#if AX_ENABLE_CACHE_TEXTURE_DATA + // TODO new-renderer: interface setupBuffer removal + + // Need to listen the event only when not use batchnode, because it will use VBO +// auto listener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){ +// /** listen the event that renderer was recreated on Android/WP8 */ +// this->setupBuffer(); +// }); + +// _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); +#endif +} + +DrawNodeEx::~DrawNodeEx() +{ + AX_SAFE_FREE(_bufferTriangle); + AX_SAFE_FREE(_bufferPoint); + AX_SAFE_FREE(_bufferLine); + + freeShaderInternal(_customCommandTriangle); + freeShaderInternal(_customCommandPoint); + freeShaderInternal(_customCommandLine); +} + +DrawNodeEx* DrawNodeEx::create(float defaultLineWidth) +{ + DrawNodeEx* ret = new DrawNodeEx(defaultLineWidth); + if (ret->init()) + { + ret->autorelease(); + ret->_dnVersion = Version::v2; + } + else + { + AX_SAFE_DELETE(ret); + } + return ret; +} + +void DrawNodeEx::ensureCapacity(int count) +{ + AXASSERT(count >= 0, "capacity must be >= 0"); + + if (_bufferCountTriangle + count > _bufferCapacityTriangle) + { + _bufferCapacityTriangle += MAX(_bufferCapacityTriangle, count); + _bufferTriangle = (V2F_C4B_T2F*)realloc(_bufferTriangle, _bufferCapacityTriangle * sizeof(V2F_C4B_T2F)); + + _customCommandTriangle.createVertexBuffer(sizeof(V2F_C4B_T2F), _bufferCapacityTriangle, + CustomCommand::BufferUsage::STATIC); + _customCommandTriangle.updateVertexBuffer(_bufferTriangle, _bufferCapacityTriangle * sizeof(V2F_C4B_T2F)); + } +} + +void DrawNodeEx::ensureCapacityGLPoint(int count) +{ + AXASSERT(count >= 0, "capacity must be >= 0"); + + if (_bufferCountPoint + count > _bufferCapacityPoint) + { + _bufferCapacityPoint += MAX(_bufferCapacityPoint, count); + _bufferPoint = (V2F_C4B_T2F*)realloc(_bufferPoint, _bufferCapacityPoint * sizeof(V2F_C4B_T2F)); + + _customCommandPoint.createVertexBuffer(sizeof(V2F_C4B_T2F), _bufferCapacityPoint, + CustomCommand::BufferUsage::STATIC); + _customCommandPoint.updateVertexBuffer(_bufferPoint, _bufferCapacityPoint * sizeof(V2F_C4B_T2F)); + } +} + +void DrawNodeEx::ensureCapacityGLLine(int count) +{ + AXASSERT(count >= 0, "capacity must be >= 0"); + + if (_bufferCountLine + count > _bufferCapacityLine) + { + _bufferCapacityLine += MAX(_bufferCapacityLine, count); + _bufferLine = (V2F_C4B_T2F*)realloc(_bufferLine, _bufferCapacityLine * sizeof(V2F_C4B_T2F)); + + _customCommandLine.createVertexBuffer(sizeof(V2F_C4B_T2F), _bufferCapacityLine, + CustomCommand::BufferUsage::STATIC); + _customCommandLine.updateVertexBuffer(_bufferLine, _bufferCapacityLine * sizeof(V2F_C4B_T2F)); + } +} + +bool DrawNodeEx::init() +{ + _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; + updateShader(); + ensureCapacity(512); + ensureCapacityGLPoint(64); + ensureCapacityGLLine(256); + + _dirtyTriangle = true; + _dirtyLine = true; + _dirtyPoint = true; + + return true; +} + +void DrawNodeEx::updateShader() +{ + updateShaderInternal(_customCommandTriangle, backend::ProgramType::POSITION_COLOR_LENGTH_TEXTURE, + CustomCommand::DrawType::ARRAY, CustomCommand::PrimitiveType::TRIANGLE); + + updateShaderInternal(_customCommandPoint, backend::ProgramType::POSITION_COLOR_TEXTURE_AS_POINTSIZE, + CustomCommand::DrawType::ARRAY, CustomCommand::PrimitiveType::POINT); + + updateShaderInternal(_customCommandLine, backend::ProgramType::POSITION_COLOR_LENGTH_TEXTURE, + CustomCommand::DrawType::ARRAY, CustomCommand::PrimitiveType::LINE); +} + +void DrawNodeEx::updateShaderInternal(CustomCommand& cmd, + uint32_t programType, + CustomCommand::DrawType drawType, + CustomCommand::PrimitiveType primitiveType) +{ + auto& pipelinePS = cmd.getPipelineDescriptor().programState; + AX_SAFE_RELEASE(pipelinePS); + + auto program = backend::Program::getBuiltinProgram(programType); + pipelinePS = new backend::ProgramState(program); + setVertexLayout(cmd); + cmd.setPrimitiveType(primitiveType); + cmd.setDrawType(drawType); +} + +void DrawNodeEx::setVertexLayout(CustomCommand& cmd) +{ + auto* programState = cmd.getPipelineDescriptor().programState; + programState->validateSharedVertexLayout(backend::VertexLayoutType::DrawNode); +} + +void DrawNodeEx::freeShaderInternal(CustomCommand& cmd) +{ + auto& pipelinePS = cmd.getPipelineDescriptor().programState; + AX_SAFE_RELEASE_NULL(pipelinePS); +} + +void DrawNodeEx::updateBlendState(CustomCommand& cmd) +{ + backend::BlendDescriptor& blendDescriptor = cmd.getPipelineDescriptor().blendDescriptor; + blendDescriptor.blendEnabled = true; + if (_blendFunc == BlendFunc::ALPHA_NON_PREMULTIPLIED) + { + blendDescriptor.sourceRGBBlendFactor = backend::BlendFactor::SRC_ALPHA; + blendDescriptor.destinationRGBBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + blendDescriptor.sourceAlphaBlendFactor = backend::BlendFactor::SRC_ALPHA; + blendDescriptor.destinationAlphaBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + setOpacityModifyRGB(false); + } + else + { + blendDescriptor.sourceRGBBlendFactor = backend::BlendFactor::ONE; + blendDescriptor.destinationRGBBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + blendDescriptor.sourceAlphaBlendFactor = backend::BlendFactor::ONE; + blendDescriptor.destinationAlphaBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + setOpacityModifyRGB(true); + } +} + +void DrawNodeEx::updateUniforms(const Mat4& transform, CustomCommand& cmd) +{ + auto& pipelineDescriptor = cmd.getPipelineDescriptor(); + const auto& matrixP = _director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); + Mat4 matrixMVP = matrixP * transform; + auto mvpLocation = pipelineDescriptor.programState->getUniformLocation("u_MVPMatrix"); + pipelineDescriptor.programState->setUniform(mvpLocation, matrixMVP.m, sizeof(matrixMVP.m)); + + float alpha = _displayedOpacity / 255.0f; + auto alphaUniformLocation = pipelineDescriptor.programState->getUniformLocation("u_alpha"); + pipelineDescriptor.programState->setUniform(alphaUniformLocation, &alpha, sizeof(alpha)); +} + +void DrawNodeEx::draw(Renderer* renderer, const Mat4& transform, uint32_t flags) +{ + if (_bufferCountTriangle) + { + updateBlendState(_customCommandTriangle); + updateUniforms(transform, _customCommandTriangle); + _customCommandTriangle.init(_globalZOrder); + renderer->addCommand(&_customCommandTriangle); + } + + if (_bufferCountPoint) + { + updateBlendState(_customCommandPoint); + updateUniforms(transform, _customCommandPoint); + _customCommandPoint.init(_globalZOrder); + renderer->addCommand(&_customCommandPoint); + } + + if (_bufferCountLine) + { + updateBlendState(_customCommandLine); + updateUniforms(transform, _customCommandLine); + _customCommandLine.init(_globalZOrder); + renderer->addCommand(&_customCommandLine); + } +} + +void DrawNodeEx::drawPoint(const Vec2& position, const float pointSize, const Color4B& color) +{ + ensureCapacityGLPoint(1); + + V2F_C4B_T2F* point = _bufferPoint + _bufferCountPoint; + *point = {position, color, Tex2F(pointSize, 0)}; + + _customCommandPoint.updateVertexBuffer(point, _bufferCountPoint * sizeof(V2F_C4B_T2F), sizeof(V2F_C4B_T2F)); + _bufferCountPoint += 1; + _dirtyPoint = true; + _customCommandPoint.setVertexDrawInfo(0, _bufferCountPoint); +} + +void DrawNodeEx::drawPoints(const Vec2* position, unsigned int numberOfPoints, const Color4B& color) +{ + drawPoints(position, numberOfPoints, 1.f, color); +} + +void DrawNodeEx::drawPoints(const Vec2* position, + unsigned int numberOfPoints, + const float pointSize, + const Color4B& color) +{ + ensureCapacityGLPoint(numberOfPoints); + + V2F_C4B_T2F* point = _bufferPoint + _bufferCountPoint; + for (unsigned int i = 0; i < numberOfPoints; i++) + { + *(point + i) = {position[i], color, Tex2F(pointSize, 0)}; + } + + _customCommandPoint.updateVertexBuffer(point, _bufferCountPoint * sizeof(V2F_C4B_T2F), + numberOfPoints * sizeof(V2F_C4B_T2F)); + _bufferCountPoint += numberOfPoints; + _dirtyPoint = true; + _customCommandPoint.setVertexDrawInfo(0, _bufferCountPoint); +} + +void DrawNodeEx::drawLine(const Vec2& origin, const Vec2& destination, const Color4B& color, float thickness) +{ + if (thickness != 1.0f) + { + drawSegment(origin, destination, thickness, color); + return; + } + else + { + Vec2 line[2] = {origin, destination}; + Vec2* _vertices = transform(line, 2); + + ensureCapacityGLLine(2); + + V2F_C4B_T2F* point = _bufferLine + _bufferCountLine; + + *point = {_vertices[0], color, Tex2F::ZERO}; + *(point + 1) = {_vertices[1], color, Tex2F::ZERO}; + + _customCommandLine.updateVertexBuffer(point, _bufferCountLine * sizeof(V2F_C4B_T2F), 2 * sizeof(V2F_C4B_T2F)); + _bufferCountLine += 2; + _dirtyLine = true; + _customCommandLine.setVertexDrawInfo(0, _bufferCountLine); + } +} + +void DrawNodeEx::drawRect(const Vec2& origin, const Vec2& destination, const Color4B& color, float thickness) +{ + if (thickness != 1.0f) + { + Vec2 line[4] = {{origin}, {Vec2(destination.x, origin.y)}, {destination}, {Vec2(origin.x, destination.y)}}; + + _isConvex = true; + _drawPoly(line, 4, true, color, thickness); + _isConvex = false; + return; + } + else + { + drawLine(origin, Vec2(destination.x, origin.y), color); + drawLine(Vec2(destination.x, origin.y), destination, color); + drawLine(destination, Vec2(origin.x, destination.y), color); + drawLine(Vec2(origin.x, destination.y), origin, color); + } +} + +void DrawNodeEx::drawPoly(const Vec2* poli, + unsigned int numberOfPoints, + bool closePolygon, + const Color4B& color, + float thickness) +{ + if (thickness != 1.0f) + { + _drawPolygon(poli, numberOfPoints, Color4B::AX_TRANSPARENT, thickness, color, closePolygon); + return; + } + else + { + Vec2* _vertices = transform(poli, numberOfPoints); + + unsigned int vertex_count; + if (closePolygon) + { + vertex_count = 2 * numberOfPoints; + } + else + { + vertex_count = 2 * (numberOfPoints - 1); + } + ensureCapacityGLLine(vertex_count); + + V2F_C4B_T2F* point = _bufferLine + _bufferCountLine; + V2F_C4B_T2F* cursor = point; + + unsigned int i = 0; + for (; i < numberOfPoints - 1; i++) + { + *point = {poli[i], color, Tex2F::ZERO}; + *(point + 1) = {poli[i + 1], color, Tex2F::ZERO}; + point += 2; + } + if (closePolygon) + { + *point = {poli[i], color, Tex2F::ZERO}; + *(point + 1) = {poli[0], color, Tex2F::ZERO}; + } + + _customCommandLine.updateVertexBuffer(cursor, _bufferCountLine * sizeof(V2F_C4B_T2F), + vertex_count * sizeof(V2F_C4B_T2F)); + _bufferCountLine += vertex_count; + _customCommandLine.setVertexDrawInfo(0, _bufferCountLine); + } +} + +void DrawNodeEx::drawCircle(const Vec2& center, + float radius, + float angle, + unsigned int segments, + bool drawLineToCenter, + float scaleX, + float scaleY, + const Color4B& color, + float thickness) +{ + const float coef = 2.0f * (float)M_PI / segments; + + auto vertices = _abuf.get(segments + 2); + + for (unsigned int i = 0; i <= segments; i++) + { + float rads = i * coef; + vertices[i].x = radius * cosf(rads + angle) * scaleX + center.x; + vertices[i].y = radius * sinf(rads + angle) * scaleY + center.y; + } + _isConvex = false; + if (thickness != 1.0f) + { + _drawPolygon(vertices, segments, Color4B::AX_TRANSPARENT, thickness, color, true); + } + else + { + if (drawLineToCenter) + { + vertices[segments + 1] = center; + _drawPoly(vertices, segments + 2, true, color, 1.0f); + } + else + _drawPoly(vertices, segments + 1, true, color, thickness); + } + _isConvex = true; +} + +void DrawNodeEx::drawCircle(const Vec2& center, + float radius, + float angle, + unsigned int segments, + bool drawLineToCenter, + const Color4B& color, + float thickness) +{ + drawCircle(center, radius, angle, segments, drawLineToCenter, 1.0f, 1.0f, color, thickness); +} + +void DrawNodeEx::drawStar(const Vec2& center, + float radius1, + float radius2, + unsigned int segments, + const Color4B& color, + float thickness) +{ + const float coef = 2.0f * (float)M_PI / segments; + + float halfAngle = coef / 2.0f; + + auto vertices = _abuf.get(segments * 2); + int i = 0; + for (unsigned int a = 0; a < segments; a++) + { + float rads = a * coef; + vertices[i] = Vec2(center.x + cos(rads) * radius2, center.y + sin(rads) * radius2); + vertices[i + 1] = Vec2(center.x + cos(rads + halfAngle) * radius1, center.y + sin(rads + halfAngle) * radius1); + i += 2; + } + _drawPolygon(vertices, segments*2, Color4B::AX_TRANSPARENT, thickness, color, true); +} + +void DrawNodeEx::drawSolidStar(const Vec2& center, + float radius1, + float radius2, + unsigned int segments, + const Color4B& color, + const Color4B& filledColor, + float thickness) +{ + const float coef = 2.0f * (float)M_PI / segments; + + float halfAngle = coef / 2.0f; + + auto vertices = _abuf.get(segments * 2); + int i = 0; + for (unsigned int a = 0; a < segments; a++) + { + float rads = a * coef; + vertices[i] = Vec2(center.x + cos(rads) * radius2, center.y + sin(rads) * radius2); + vertices[i + 1] = Vec2(center.x + cos(rads + halfAngle) * radius1, center.y + sin(rads + halfAngle) * radius1); + i += 2; + } + _drawPolygon(vertices, segments * 2, filledColor, thickness, color, true); +} + +void DrawNodeEx::drawQuadBezier(const Vec2& origin, + const Vec2& control, + const Vec2& destination, + unsigned int segments, + const Color4B& color, + float thickness) +{ + Vec2* vertices = _abuf.get(segments + 1); + + float t = 0.0f; + for (unsigned int i = 0; i < segments; i++) + { + vertices[i].x = powf(1 - t, 2) * origin.x + 2.0f * (1 - t) * t * control.x + t * t * destination.x; + vertices[i].y = powf(1 - t, 2) * origin.y + 2.0f * (1 - t) * t * control.y + t * t * destination.y; + t += 1.0f / segments; + } + vertices[segments].x = destination.x; + vertices[segments].y = destination.y; + _isConvex = false; + _drawPolygon(vertices, segments, Color4B::AX_TRANSPARENT, thickness, color, false); + _isConvex = true; +} + +void DrawNodeEx::drawCubicBezier(const Vec2& origin, + const Vec2& control1, + const Vec2& control2, + const Vec2& destination, + unsigned int segments, + const Color4B& color, + float thickness) +{ + Vec2* vertices = _abuf.get(segments + 1); + + float t = 0; + for (unsigned int i = 0; i < segments; i++) + { + vertices[i].x = powf(1 - t, 3) * origin.x + 3.0f * powf(1 - t, 2) * t * control1.x + + 3.0f * (1 - t) * t * t * control2.x + t * t * t * destination.x; + vertices[i].y = powf(1 - t, 3) * origin.y + 3.0f * powf(1 - t, 2) * t * control1.y + + 3.0f * (1 - t) * t * t * control2.y + t * t * t * destination.y; + t += 1.0f / segments; + } + vertices[segments].x = destination.x; + vertices[segments].y = destination.y; + _isConvex = true; + _drawPolygon(vertices, segments, Color4B::AX_TRANSPARENT, thickness, color, false); + _isConvex = false; +} + +void DrawNodeEx::drawCardinalSpline(ax::PointArray* config, + float tension, + unsigned int segments, + const Color4B& color, + float thickness) +{ + Vec2* vertices = _abuf.get(segments + 1); + + ssize_t p; + float lt; + float deltaT = 1.0f / config->count(); + + for (unsigned int i = 0; i < segments + 1; i++) + { + + float dt = (float)i / segments; + + // border + if (dt == 1) + { + p = config->count() - 1; + lt = 1; + } + else + { + p = static_cast(dt / deltaT); + lt = (dt - deltaT * (float)p) / deltaT; + } + + // Interpolate + Vec2 pp0 = config->getControlPointAtIndex(p - 1); + Vec2 pp1 = config->getControlPointAtIndex(p + 0); + Vec2 pp2 = config->getControlPointAtIndex(p + 1); + Vec2 pp3 = config->getControlPointAtIndex(p + 2); + + Vec2 newPos = ccCardinalSplineAt(pp0, pp1, pp2, pp3, tension, lt); + vertices[i].x = newPos.x; + vertices[i].y = newPos.y; + } + _isConvex = true; + _drawPolygon(vertices, segments, Color4B::AX_TRANSPARENT, thickness, color, false); + _isConvex = false; +} + +void DrawNodeEx::drawCatmullRom(ax::PointArray* points, unsigned int segments, const Color4B& color, float thickness) +{ + drawCardinalSpline(points, 0.5f, segments, color, thickness); +} + +void DrawNodeEx::drawDot(const Vec2& pos, float radius, const Color4B& color) +{ + unsigned int vertex_count = 2 * 3; + ensureCapacity(vertex_count); + + V2F_C4B_T2F a = {Vec2(pos.x - radius, pos.y - radius), color, Tex2F(-1.0f, -1.0f)}; + V2F_C4B_T2F b = {Vec2(pos.x - radius, pos.y + radius), color, Tex2F(-1.0f, 1.0f)}; + V2F_C4B_T2F c = {Vec2(pos.x + radius, pos.y + radius), color, Tex2F(1.0f, 1.0f)}; + V2F_C4B_T2F d = {Vec2(pos.x + radius, pos.y - radius), color, Tex2F(1.0f, -1.0f)}; + + V2F_C4B_T2F_Triangle* triangles = (V2F_C4B_T2F_Triangle*)(_bufferTriangle + _bufferCountTriangle); + V2F_C4B_T2F_Triangle triangle0 = {a, b, c}; + V2F_C4B_T2F_Triangle triangle1 = {a, c, d}; + triangles[0] = triangle0; + triangles[1] = triangle1; + + _customCommandTriangle.updateVertexBuffer(triangles, _bufferCountTriangle * sizeof(V2F_C4B_T2F), + vertex_count * sizeof(V2F_C4B_T2F)); + _bufferCountTriangle += vertex_count; + _dirtyTriangle = true; + _customCommandTriangle.setVertexDrawInfo(0, _bufferCountTriangle); +} + +void DrawNodeEx::drawRect(const Vec2& p1, + const Vec2& p2, + const Vec2& p3, + const Vec2& p4, + const Color4B& color, + float thickness) +{ + if (thickness != 1.0f) + { + Vec2 line[4] = {{p1}, {p2}, {p3}, {p4}}; + _isConvex = true; + _drawPoly(line, 4, true, color, thickness); + _isConvex = false; + } + else + { + drawLine(p1, p2, color); + drawLine(p2, p3, color); + drawLine(p3, p4, color); + drawLine(p4, p1, color); + } +} + +void DrawNodeEx::drawSegment(const Vec2& from, const Vec2& to, float radius, const Color4B& color) +{ + Vec2 line[2] = {from, to}; + Vec2* _vertices = transform(line, 2); + + unsigned int vertex_count = 6 * 3; + ensureCapacity(vertex_count); + + Vec2 a = _vertices[0]; + Vec2 b = _vertices[1]; + + Vec2 n = ((b - a).getPerp()).getNormalized(); + Vec2 t = n.getPerp(); + + Vec2 nw = n * radius; + Vec2 tw = t * radius; + Vec2 v0 = b - (nw + tw); + Vec2 v1 = b + (nw - tw); + Vec2 v2 = b - nw; + Vec2 v3 = b + nw; + Vec2 v4 = a - nw; + Vec2 v5 = a + nw; + Vec2 v6 = a - (nw - tw); + Vec2 v7 = a + (nw + tw); + + V2F_C4B_T2F_Triangle* triangles = (V2F_C4B_T2F_Triangle*)(_bufferTriangle + _bufferCountTriangle); + + V2F_C4B_T2F_Triangle triangles0 = { + {v0, color, v2ToTex2F(-(n + t))}, + {v1, color, v2ToTex2F(n - t)}, + {v2, color, v2ToTex2F(-n)}, + }; + triangles[0] = triangles0; + + V2F_C4B_T2F_Triangle triangles1 = { + {v3, color, v2ToTex2F(n)}, + {v1, color, v2ToTex2F(n - t)}, + {v2, color, v2ToTex2F(-n)}, + }; + triangles[1] = triangles1; + + V2F_C4B_T2F_Triangle triangles2 = { + {v3, color, v2ToTex2F(n)}, + {v4, color, v2ToTex2F(-n)}, + {v2, color, v2ToTex2F(-n)}, + }; + triangles[2] = triangles2; + + V2F_C4B_T2F_Triangle triangles3 = { + {v3, color, v2ToTex2F(n)}, + {v4, color, v2ToTex2F(-n)}, + {v5, color, v2ToTex2F(n)}, + }; + triangles[3] = triangles3; + + V2F_C4B_T2F_Triangle triangles4 = { + {v6, color, v2ToTex2F(t - n)}, + {v4, color, v2ToTex2F(-n)}, + {v5, color, v2ToTex2F(n)}, + }; + triangles[4] = triangles4; + + V2F_C4B_T2F_Triangle triangles5 = { + {v6, color, v2ToTex2F(t - n)}, + {v7, color, v2ToTex2F(t + n)}, + {v5, color, v2ToTex2F(n)}, + }; + triangles[5] = triangles5; + + _customCommandTriangle.updateVertexBuffer(triangles, _bufferCountTriangle * sizeof(V2F_C4B_T2F), + vertex_count * sizeof(V2F_C4B_T2F)); + _bufferCountTriangle += vertex_count; + _dirtyTriangle = true; + _customCommandTriangle.setVertexDrawInfo(0, _bufferCountTriangle); +} + +void DrawNodeEx::drawPolygon(const Vec2* verts, + int count, + const Color4B& fillColor, + float borderWidth, + const Color4B& borderColor) +{ + _drawPolygon(verts, count, fillColor, borderWidth, borderColor, true); +} + +void DrawNodeEx::drawPolygon(const Vec2* verts, + int count, + float borderWidth, + const Color4B& borderColor) +{ + _drawPolygon(verts, count, Color4B::AX_TRANSPARENT, borderWidth, borderColor, true); +} + +void DrawNodeEx::drawSolidPolygon(const Vec2* verts, + int count, + const Color4B& fillColor, + float borderWidth, + const Color4B& borderColor) +{ + _drawPolygon(verts, count, fillColor, borderWidth, borderColor, true); +} + + + + +void DrawNodeEx::drawSolidRect(const Vec2& origin, const Vec2& destination, const Color4B& color) +{ + Vec2 vertices[] = {origin, Vec2(destination.x, origin.y), destination, Vec2(origin.x, destination.y)}; + _isConvex = true; + _drawPolygon(vertices, 4, color, 0.0f, Color4B(), true); + _isConvex = false; +} + +void DrawNodeEx::drawSolidPoly(const Vec2* poli, unsigned int numberOfPoints, const Color4B& color) +{ + _drawPolygon(poli, numberOfPoints, color, 0.0f, Color4B(), true); +} + +void DrawNodeEx::drawPie(const Vec2& center, + float radius, + float rotation, + int startAngle, + int endAngle, + float scaleX, + float scaleY, + const Color4B& fillColor, + const Color4B& borderColor, + DrawMode drawMode, + float thickness) +{ + // not a real line! + if (startAngle == endAngle) + return; + +#define DEGREES 360 + + const float coef = 2.0f * (float)M_PI / DEGREES; + Vec2* vertices = _abuf.get(DEGREES + 2); + + int n = 0; + float rads = 0; + float _angle = AX_DEGREES_TO_RADIANS(rotation); + + if (startAngle > endAngle) + { + int tmp = endAngle; + endAngle = startAngle; + startAngle = tmp; + } + + for (int i = 0; i <= DEGREES; i++) + { + if (startAngle <= i && endAngle >= i) + { + rads = i * coef; + + float j = radius * cosf(rads + _angle) * scaleX + center.x; + float k = radius * sinf(rads + _angle) * scaleY + center.y; + + vertices[n].x = j; + vertices[n].y = k; + n++; + } + } + switch (drawMode) + { + case DrawMode::Fill: + vertices[n++] = center; + _drawPolygon(vertices, n, fillColor, thickness, borderColor, true); + break; + case DrawMode::Outline: + vertices[n++] = center; + _drawPolygon(vertices, n, Color4B::AX_TRANSPARENT, thickness, borderColor, true); + break; + case DrawMode::Line: + _drawPolygon(vertices, n, Color4B::AX_TRANSPARENT, thickness, borderColor, false); + break; + case DrawMode::Semi: + _drawPolygon(vertices, n, fillColor, thickness, borderColor, true); + break; + + default: + break; + } +} + +void DrawNodeEx::drawSolidCircle(const Vec2& center, + float radius, + float angle, + unsigned int segments, + float scaleX, + float scaleY, + const Color4B& fillColor, + float borderWidth, + const Color4B& borderColor) +{ + const float coef = 2.0f * (float)M_PI / segments; + + Vec2* vertices = _abuf.get(segments); + + for (unsigned int i = 0; i < segments; i++) + { + float rads = i * coef; + float j = radius * cosf(rads + angle) * scaleX + center.x; + float k = radius * sinf(rads + angle) * scaleY + center.y; + + vertices[i].x = j; + vertices[i].y = k; + } + _isConvex = true; + _drawPolygon(vertices, segments, fillColor, borderWidth, borderColor); + _isConvex = false; +} + +void DrawNodeEx::drawSolidCircle(const Vec2& center, + float radius, + float angle, + unsigned int segments, + float scaleX, + float scaleY, + const Color4B& color) +{ + const float coef = 2.0f * (float)M_PI / segments; + + Vec2* vertices = _abuf.get(segments); + + for (unsigned int i = 0; i < segments; i++) + { + float rads = i * coef; + float j = radius * cosf(rads + angle) * scaleX + center.x; + float k = radius * sinf(rads + angle) * scaleY + center.y; + + vertices[i].x = j; + vertices[i].y = k; + } + _isConvex = true; + _drawPolygon(vertices, segments, color, 0.0f, Color4B(), true); + _isConvex = false; +} + +void DrawNodeEx::drawSolidCircle(const Vec2& center, + float radius, + float angle, + unsigned int segments, + const Color4B& color) +{ + drawSolidCircle(center, radius, angle, segments, 1.0f, 1.0f, color); +} + +void DrawNodeEx::drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3, const Color4B& color, float thickness) +{ + Vec2 poli[3] = {p1, p2, p3}; + unsigned int vertex_count = 3; + + if (thickness != 1.0f) + { + _isConvex = true; + _drawPolygon(poli, vertex_count, Color4B::AX_TRANSPARENT, thickness, color, true); + _isConvex = false; + return; + } + Vec2* _vertices = transform(poli, vertex_count); + + ensureCapacity(vertex_count); + + V2F_C4B_T2F a = {_vertices[0], color, Tex2F::ZERO}; + V2F_C4B_T2F b = {_vertices[1], color, Tex2F::ZERO}; + V2F_C4B_T2F c = {_vertices[2], color, Tex2F::ZERO}; + + V2F_C4B_T2F_Triangle* triangles = (V2F_C4B_T2F_Triangle*)(_bufferTriangle + _bufferCountTriangle); + V2F_C4B_T2F_Triangle triangle = {a, b, c}; + triangles[0] = triangle; + + _customCommandTriangle.updateVertexBuffer(triangles, _bufferCountTriangle * sizeof(V2F_C4B_T2F), + vertex_count * sizeof(V2F_C4B_T2F)); + _bufferCountTriangle += vertex_count; + _dirtyTriangle = true; + _customCommandTriangle.setVertexDrawInfo(0, _bufferCountTriangle); +} + +void DrawNodeEx::clear() +{ + _bufferCountTriangle = 0; + _dirtyTriangle = true; + _bufferCountLine = 0; + _dirtyLine = true; + _bufferCountPoint = 0; + _dirtyPoint = true; + _lineWidth = _defaultLineWidth; +} + +const BlendFunc& DrawNodeEx::getBlendFunc() const +{ + return _blendFunc; +} + +void DrawNodeEx::setBlendFunc(const BlendFunc& blendFunc) +{ + _blendFunc = blendFunc; +} + +void DrawNodeEx::setLineWidth(float lineWidth) +{ + _lineWidth = lineWidth; +} + +float DrawNodeEx::getLineWidth() +{ + return this->_lineWidth; +} + +void DrawNodeEx::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) +{ + if (_isolated) + { + // ignore `parentTransform` from parent + Node::visit(renderer, Mat4::IDENTITY, parentFlags); + } + else + { + Node::visit(renderer, parentTransform, parentFlags); + } +} + +void DrawNodeEx::_drawPolygon(const Vec2* verts, + unsigned int count, + const Color4B& fillColor, + float borderWidth, + const Color4B& borderColo, + bool closedPolygon) +{ + AXASSERT(count >= 0, "invalid count value"); + + Vec2* _vertices = transform(verts, count); + + bool outline = (borderColo.a > 0.0f && borderWidth > 0.0f); + + Color4B borderColor = borderColo; + + auto triangle_count = outline ? (3 * count - 2) : (count - 2); + auto vertex_count = 3 * triangle_count; + ensureCapacity(vertex_count); + + V2F_C4B_T2F_Triangle* triangles = (V2F_C4B_T2F_Triangle*)(_bufferTriangle + _bufferCountTriangle); + V2F_C4B_T2F_Triangle* cursor = triangles; + + if (closedPolygon && !_isConvex && count >= 3 && !isConvex(_vertices, count)) + { + std::vector p2pointsStorage; + p2pointsStorage.reserve(count); + std::vector p2points; + p2points.reserve(count); + + for (int i = 0; i < count; ++i) + { + p2points.emplace_back(&p2pointsStorage.emplace_back((float)_vertices[i].x, (float)_vertices[i].y)); + } + p2t::CDT cdt(p2points); + cdt.Triangulate(); + std::vector tris = cdt.GetTriangles(); + + if ((tris.size() * 3) > vertex_count) + { + ensureCapacity((tris.size() * 3)); + triangles = (V2F_C4B_T2F_Triangle*)(_bufferTriangle + _bufferCountTriangle); + cursor = triangles; + } + + for (auto&& t : tris) + { + p2t::Point* vec1 = t->GetPoint(0); + p2t::Point* vec2 = t->GetPoint(1); + p2t::Point* vec3 = t->GetPoint(2); + + V2F_C4B_T2F_Triangle tmp = { + {Vec2(vec1->x, vec1->y), fillColor, Tex2F::ZERO}, + {Vec2(vec2->x, vec2->y), fillColor, Tex2F::ZERO}, + {Vec2(vec3->x, vec3->y), fillColor, Tex2F::ZERO}, + }; + *cursor++ = tmp; + } + } + else + { + for (int i = 0; i < count - 2; i++) + { + V2F_C4B_T2F_Triangle tmp = { + {_vertices[0], fillColor, v2ToTex2F(Vec2::ZERO)}, + {_vertices[i + 1], fillColor, v2ToTex2F(Vec2::ZERO)}, + {_vertices[i + 2], fillColor, v2ToTex2F(Vec2::ZERO)}, + }; + + *cursor++ = tmp; + } + } + if (outline) + { + struct ExtrudeVerts + { + Vec2 offset, n; + }; + struct ExtrudeVerts* extrude = (struct ExtrudeVerts*)malloc(sizeof(struct ExtrudeVerts) * count); + + for (unsigned int i = 0; i < count; i++) + { + Vec2 v0 = _vertices[(i - 1 + count) % count]; + Vec2 v1 = _vertices[i]; + Vec2 v2 = _vertices[(i + 1) % count]; + + Vec2 n1 = ((v1 - v0).getPerp()).getNormalized(); + Vec2 n2 = ((v2 - v1).getPerp()).getNormalized(); + + Vec2 offset = (n1 + n2) * (1.0f / (Vec2::dot(n1, n2) + 1.0f)); + extrude[i] = {offset, n2}; + } + + for (unsigned int i = 0; i < count; i++) + { + int j = (i + 1) % count; + Vec2 v0 = _vertices[i]; + Vec2 v1 = _vertices[j]; + + Vec2 n0 = extrude[i].n; + + Vec2 offset0 = extrude[i].offset; + Vec2 offset1 = extrude[j].offset; + + Vec2 inner0 = v0 - offset0 * borderWidth; + Vec2 inner1 = v1 - offset1 * borderWidth; + Vec2 outer0 = v0 + offset0 * borderWidth; + Vec2 outer1 = v1 + offset1 * borderWidth; + borderColor = borderColo; + if (i >= count - 1 && !closedPolygon) // /-2 ?? + { + borderColor = Color4B::AX_TRANSPARENT; + } + + V2F_C4B_T2F_Triangle tmp1 = {{inner0, borderColor, v2ToTex2F(-n0)}, + {inner1, borderColor, v2ToTex2F(-n0)}, + {outer1, borderColor, v2ToTex2F(n0)}}; + *cursor++ = tmp1; + + V2F_C4B_T2F_Triangle tmp2 = {{inner0, borderColor, v2ToTex2F(-n0)}, + {outer0, borderColor, v2ToTex2F(n0)}, + {outer1, borderColor, v2ToTex2F(n0)}}; + *cursor++ = tmp2; + } + + free(extrude); + } + + _customCommandTriangle.updateVertexBuffer(triangles, _bufferCountTriangle * sizeof(V2F_C4B_T2F), + vertex_count * sizeof(V2F_C4B_T2F)); + _bufferCountTriangle += vertex_count; + _customCommandTriangle.setVertexDrawInfo(0, _bufferCountTriangle); + _dirtyTriangle = true; +} + +void DrawNodeEx::_drawPoly(const Vec2* poli, + unsigned int numberOfPoints, + bool closePolygon, + const Color4B& color, + float thickness) +{ + + if (thickness != 1.0f) + { + if (closePolygon) + { + _drawPolygon(poli, numberOfPoints, Color4B::AX_TRANSPARENT, thickness, color, true); + return; + } + else + { + _drawPolygon(poli, numberOfPoints, Color4B::AX_TRANSPARENT, thickness, color, false); + return; + } + } + else + { + Vec2* _vertices = transform(poli, numberOfPoints); + + unsigned int vertex_count; + if (closePolygon) + { + vertex_count = 2 * numberOfPoints; + } + else + { + vertex_count = 2 * (numberOfPoints - 1); + } + ensureCapacityGLLine(vertex_count); + + V2F_C4B_T2F* point = _bufferLine + _bufferCountLine; + V2F_C4B_T2F* cursor = point; + + unsigned int i = 0; + for (; i < numberOfPoints - 1; i++) + { + *point = {_vertices[i], color, Tex2F::ZERO}; + *(point + 1) = {_vertices[i + 1], color, Tex2F::ZERO}; + point += 2; + } + if (closePolygon) + { + *point = {_vertices[i], color, Tex2F::ZERO}; + *(point + 1) = {_vertices[0], color, Tex2F::ZERO}; + } + + _customCommandLine.updateVertexBuffer(cursor, _bufferCountLine * sizeof(V2F_C4B_T2F), + vertex_count * sizeof(V2F_C4B_T2F)); + _bufferCountLine += vertex_count; + _customCommandLine.setVertexDrawInfo(0, _bufferCountLine); + } +} +NS_AX_EXT_END diff --git a/extensions/DrawNodeEx/DrawNodeEx.h b/extensions/DrawNodeEx/DrawNodeEx.h new file mode 100644 index 000000000000..8f9b610fb3a9 --- /dev/null +++ b/extensions/DrawNodeEx/DrawNodeEx.h @@ -0,0 +1,606 @@ +/* Copyright (c) 2012 Scott Lembcke and Howling Moon Software + * Copyright (c) 2012 cocos2d-x.org + * Copyright (c) 2013-2016 Chukong Technologies Inc. + * Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + * Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Code copied & pasted from SpacePatrol game https://github.com/slembcke/SpacePatrol + * + * Renamed and added some changes for cocos2d + * + */ + +#ifndef __DRAW_NODE_EX_H__ +#define __DRAW_NODE_EX_H__ + +#include "ExtensionMacros.h" +#include "2d/Node.h" +#include "base/Types.h" +#include "renderer/CustomCommand.h" +#include "math/Math.h" +#include "base/any_buffer.h" +#include "axmol.h" + +NS_AX_EXT_BEGIN + +static const int DEFAULT_LINEWIDTH = 2; + +class PointArray; +/** + * @addtogroup _2d + * @{ + */ + +/** @class DrawNodeExt + * @brief Node that draws dots, segments and polygons. + * Faster than the "drawing primitives" since they draws everything in one single batch. + * @since v2.1 + */ +class AX_DLL DrawNodeEx : public ax::Node +{ +public: + /** Different draw modus types. + * + *. + */ + enum DrawMode + { + Fill, + Outline, + Line, + Semi, + }; + + enum class Version + { + v1, // DrawNodeExt cocos2dx/axmol 1.0 + v2, // DrawNodeExt 2.0 + v3, + v4, + }; + + // DrawNodeExt stuff + Version _dnVersion = Version::v1; + ax::Vec2 _dnScale; + ax::Vec2 _dnCenter; + float _dnRotation = 0.0f; + ax::Vec2 _dnPosition; + float _dnLineWidth = 0.0f; + float _dnDefaultLineWidth = 0.0f; + + Version _dnVersionTmp = _dnVersion; + ax::Vec2 _dnScaleTmp = _dnScale; + ax::Vec2 _dnCenterTmp = _dnCenter; + float _dnRotationTmp = _dnRotation; + ax::Vec2 _dnPositionTmp = _dnPosition; + float _dnLineWidthTmp = _dnLineWidth; + + void setDNVersion(ax::extension::DrawNodeEx::Version dnV) { _dnVersion = dnV; }; + void setDNScale(ax::Vec2 scale) { _dnScale = scale; }; + void setDNScaleX(float scaleX) { _dnScale.x = scaleX; }; + void setDNScaleY(float scaleY) { _dnScale.y = scaleY; }; + void setDNRotation(float rotation) { _dnRotation = rotation; }; + float getDNRotation() { return _dnRotation; }; + void setDNCenter(ax::Vec2 center) { _dnCenter = center; }; + ax::Vec2 getDNCenter() { return _dnCenter; }; + void setDNPosition(ax::Vec2 position) { _dnPosition = position; }; + ax::Vec2 getDNPosition() { return _dnPosition; }; + void setDNLineWidth(float lineWidth) { _dnLineWidth = lineWidth; }; + float getDNLineWidth() { return _dnLineWidth; }; + ax::Vec2* transform(const ax::Vec2* vertices, unsigned int count); + void resetDNValues() + { + _dnVersion = Version::v2; + _dnScale = Vec2(1.f, 1.f); + _dnCenter = Vec2(0.f, 0.f); + _dnRotation = 0.0f; + _dnPosition = Vec2(0.f, 0.f); + _dnLineWidth = 1.0f; + }; + void ensureDNValues() + { + _dnVersionTmp = _dnVersion; + _dnScaleTmp = _dnScale; + _dnCenterTmp = _dnCenter; + _dnRotationTmp = _dnRotation; + _dnPositionTmp = _dnPosition; + _dnLineWidthTmp = _dnLineWidth; + }; + void restoreDNValues() + { + _dnVersion = _dnVersionTmp; + _dnScale = _dnScaleTmp; + _dnCenter = _dnCenterTmp; + _dnRotation = _dnRotationTmp; + _dnPosition = _dnPositionTmp; + _dnLineWidth = _dnLineWidthTmp; + }; + + /** creates and initialize a DrawNodeExt node. + * + * @return Return an autorelease object. + */ + static DrawNodeEx* create(float defaultLineWidth = DEFAULT_LINEWIDTH); + + /** Draw a point. + * + * @param point A Vec2 used to point. + * @param pointSize The point size. + * @param color The point color. + * @js NA + */ + void drawPoint(const ax::Vec2& point, const float pointSize, const ax::Color4B& color); + + /** Draw a group point. + * + * @param position A Vec2 pointer. + * @param numberOfPoints The number of points. + * @param color The point color. + * @js NA + */ + void drawPoints(const ax::Vec2* position, unsigned int numberOfPoints, const ax::Color4B& color); + + /** Draw a group point. + * + * @param position A Vec2 pointer. + * @param numberOfPoints The number of points. + * @param pointSize The point size. + * @param color The point color. + * @js NA + */ + void drawPoints(const ax::Vec2* position, + unsigned int numberOfPoints, + const float pointSize, + const ax::Color4B& color); + + /** Draw an line from origin to destination with color. + * + * @param origin The line origin. + * @param destination The line destination. + * @param color The line color. + * @js NA + */ + void drawLine(const ax::Vec2& origin, + const ax::Vec2& destination, + const ax::Color4B& color, + float thickness = 1.0f); + + /** Draws a rectangle given the origin and destination point measured in points. + * The origin and the destination can not have the same x and y coordinate. + * + * @param origin The rectangle origin. + * @param destination The rectangle destination. + * @param color The rectangle color. + */ + void drawRect(const ax::Vec2& origin, const ax::Vec2& destination, const ax::Color4B& color, float thickness = 1); + + /** Draws a polygon given a pointer to point coordinates and the number of vertices measured in points. + * The polygon can be closed or open. + * + * @param poli A pointer to point coordinates. + * @param numberOfPoints The number of vertices measured in points. + * @param closePolygon The polygon can be closed or open. + * @param color The polygon color. + */ + void drawPoly(const ax::Vec2* poli, + unsigned int numberOfPoints, + bool closePolygon, + const ax::Color4B& color, + float thickness = 1); + void _drawPoly(const ax::Vec2* poli, + unsigned int numberOfPoints, + bool closePolygon, + const ax::Color4B& color, + float thickness = 1); + + /** Draws a circle given the center, radius and number of segments. + * + * @param center The circle center point. + * @param radius The circle rotate of radius. + * @param angle The circle angle. + * @param segments The number of segments. + * @param drawLineToCenter Whether or not draw the line from the origin to center. + * @param scaleX The scale value in x. + * @param scaleY The scale value in y. + * @param color Set the circle color. + * @param threshold (optional) Set the threshold which will be draws a better rendered polygon. + */ + void drawCircle(const ax::Vec2& center, + float radius, + float angle, + unsigned int segments, + bool drawLineToCenter, + float scaleX, + float scaleY, + const ax::Color4B& color, + float thickness = 1.0f); // 500 should "simulate/save" the backwards compatibility + + /** Draws a circle given the center, radius and number of segments. + * + * @param center The circle center point. + * @param radius The circle rotate of radius. + * @param angle The circle angle. + * @param segments The number of segments. + * @param drawLineToCenter Whether or not draw the line from the origin to center. + * @param color Set the circle color. + * @param thickness (optional) Set the threshold which will be draws a better rendered polygon. + */ + void drawCircle(const Vec2& center, + float radius, + float angle, + unsigned int segments, + bool drawLineToCenter, + const Color4B& color, + float thickness = 1.0f); // 500 should "simulate/save" the backwards compatibility + + /** Draws a star given the center, radius1, radius2 and number of segments. + * + * @param center The circle center point. + * @param radiusI The inner radius. + * @param radiusO The outer radius. + * @param segments The number of segments. + * @param color Set the star color. + * @param thickness (optional) + */ + void drawStar(const Vec2& center, + float radiusI, + float radiusO, + unsigned int segments, + const Color4B& color, + float thickness = 1.0f); + + void drawSolidStar(const Vec2& center, + float radiusI, + float radiusO, + unsigned int segments, + const Color4B& color, + const Color4B& filledColor, + float thickness = 1.0f); + + /** Draws a quad bezier path. + * + * @param origin The origin of the bezier path. + * @param control The control of the bezier path. + * @param destination The destination of the bezier path. + * @param segments The number of segments. + * @param color Set the quad bezier color. + */ + void drawQuadBezier(const ax::Vec2& origin, + const ax::Vec2& control, + const ax::Vec2& destination, + unsigned int segments, + const ax::Color4B& color, + float thickness = 1.0f); + + /** Draw a cubic bezier curve with color and number of segments + * + * @param origin The origin of the bezier path. + * @param control1 The first control of the bezier path. + * @param control2 The second control of the bezier path. + * @param destination The destination of the bezier path. + * @param segments The number of segments. + * @param color Set the cubic bezier color. + */ + void drawCubicBezier(const ax::Vec2& origin, + const ax::Vec2& control1, + const ax::Vec2& control2, + const ax::Vec2& destination, + unsigned int segments, + const ax::Color4B& color, + float thickness = 1.0f); + + /** Draws a Cardinal Spline path. + * + * @param config A array point. + * @param tension The tension of the spline. + * @param segments The number of segments. + * @param color Set the Spline color. + */ + void drawCardinalSpline(ax::PointArray* config, + float tension, + unsigned int segments, + const ax::Color4B& color, + float thickness = 1.0f); + + /** Draws a Catmull Rom path. + * + * @param points A point array of control point. + * @param segments The number of segments. + * @param color The Catmull Rom color. + */ + void drawCatmullRom(ax::PointArray* points, + unsigned int segments, + const ax::Color4B& color, + float thickness = 1.0f); + + /** draw a dot at a position, with a given radius and color. + * + * @param pos The dot center. + * @param radius The dot radius. + * @param color The dot color. + */ + void drawDot(const ax::Vec2& pos, float radius, const ax::Color4B& color); + + /** Draws a rectangle with 4 points. + * + * @param p1 The rectangle vertex point. + * @param p2 The rectangle vertex point. + * @param p3 The rectangle vertex point. + * @param p4 The rectangle vertex point. + * @param color The rectangle color. + */ + void drawRect(const ax::Vec2& p1, + const ax::Vec2& p2, + const ax::Vec2& p3, + const ax::Vec2& p4, + const ax::Color4B& color, + float thickness = 1); + + /** Draws a solid rectangle given the origin and destination point measured in points. + * The origin and the destination can not have the same x and y coordinate. + * + * @param origin The rectangle origin. + * @param destination The rectangle destination. + * @param color The rectangle color. + * @js NA + */ + void drawSolidRect(const ax::Vec2& origin, const ax::Vec2& destination, const ax::Color4B& color); + + /** Draws a solid polygon given a pointer to CGPoint coordinates, the number of vertices measured in points, and a + * color. + * + * @param poli A solid polygon given a pointer to CGPoint coordinates. + * @param numberOfPoints The number of vertices measured in points. + * @param color The solid polygon color. + * @js NA + */ + void drawSolidPoly(const ax::Vec2* poli, unsigned int numberOfPoints, const ax::Color4B& color); + + /** Draws a solid circle given the center, radius and number of segments. + * @param center The circle center point. + * @param radius The circle rotate of radius. + * @param angle The circle angle. + * @param segments The number of segments. + * @param scaleX The scale value in x. + * @param scaleY The scale value in y. + * @param fillColor The color will fill in polygon. + * @param borderWidth The border of line width. + * @param borderColor The border of line color. + * @js NA + */ + void drawSolidCircle(const ax::Vec2& center, + float radius, + float angle, + unsigned int segments, + float scaleX, + float scaleY, + const ax::Color4B& fillColor, + float borderWidth, + const ax::Color4B& borderColor); + + /** Draws a solid circle given the center, radius and number of segments. + * @param center The circle center point. + * @param radius The circle rotate of radius. + * @param angle The circle angle. + * @param segments The number of segments. + * @param scaleX The scale value in x. + * @param scaleY The scale value in y. + * @param color The solid circle color. + * @js NA + */ + void drawSolidCircle(const ax::Vec2& center, + float radius, + float angle, + unsigned int segments, + float scaleX, + float scaleY, + const ax::Color4B& color); + + /** Draws a solid circle given the center, radius and number of segments. + * @param center The circle center point. + * @param radius The circle rotate of radius. + * @param angle The circle angle. + * @param segments The number of segments. + * @param color The solid circle color. + * @js NA + */ + void drawSolidCircle(const ax::Vec2& center, + float radius, + float angle, + unsigned int segments, + const ax::Color4B& color); + + /** Draws a pie given the center, radius, angle, start angle, end angle and number of segments. + * @param center The circle center point. + * @param radius The circle rotate of radius. + * @param angle The circle angle. + * @param startAngle The start angle. + * @param endAngle The end angle. + * @param scaleX The scale value in x. + * @param scaleY The scale value in y. + * @param color The solid circle color. + * @param DrawMode The draw mode + * @js NA + */ + void drawPie(const ax::Vec2& center, + float radius, + float rotation, + int startAngle, + int endAngle, + float scaleX, + float scaleY, + const ax::Color4B& fillColor, + const ax::Color4B& borderColor, + DrawMode drawMode, + float thickness = 1.0f); + + /** draw a segment with a radius and color. + * + * @param from The segment origin. + * @param to The segment destination. + * @param radius The segment radius. + * @param color The segment color. + */ + void drawSegment(const ax::Vec2& from, const ax::Vec2& to, float radius, const ax::Color4B& color); + + /** draw a polygon with a fill color and line color + * @code + * When this function bound into js or lua,the parameter will be changed + * In js: var drawPolygon(var Arrayofpoints, var fillColor, var width, var borderColor) + * In lua:local drawPolygon(local pointTable,local tableCount,local fillColor,local width,local borderColor) + * @endcode + * @param verts A pointer to point coordinates. + * @param count The number of verts measured in points. + * @param fillColor The color will fill in polygon. + * @param borderWidth The border of line width. + * @param borderColor The border of line color. + * @js NA + */ + void drawPolygon(const ax::Vec2* verts, + int count, + const ax::Color4B& fillColor, + float borderWidth, + const ax::Color4B& borderColor); + + void drawPolygon(const ax::Vec2* verts, int count, float borderWidth, const ax::Color4B& borderColor); + void drawSolidPolygon(const ax::Vec2* verts, + int count, + const ax::Color4B& fillColor, + float borderWidth, + const ax::Color4B& borderColor); + + void _drawPolygon(const ax::Vec2* verts, + unsigned int count, + const ax::Color4B& fillColor, + float borderWidth, + const ax::Color4B& borderColor, + bool closedPolygon = true); + + /** draw a triangle with color. + * + * @param p1 The triangle vertex point. + * @param p2 The triangle vertex point. + * @param p3 The triangle vertex point. + * @param color The triangle color. + * @js NA + */ + + void drawTriangle(const ax::Vec2& p1, + const ax::Vec2& p2, + const ax::Vec2& p3, + const ax::Color4B& color, + float thickness = 1.0f); + + /** Clear the geometry in the node's buffer. */ + void clear(); + /** Get the color mixed mode. + * @lua NA + */ + const ax::BlendFunc& getBlendFunc() const; + /** Set the color mixed mode. + * @code + * When this function bound into js or lua,the parameter will be changed + * In js: var setBlendFunc(var src, var dst) + * @endcode + * @lua NA + */ + void setBlendFunc(const ax::BlendFunc& blendFunc); + + // Overrides + virtual void draw(ax::Renderer* renderer, const ax::Mat4& transform, uint32_t flags) override; + + virtual void visit(ax::Renderer* renderer, const ax::Mat4& parentTransform, uint32_t parentFlags) override; + + void setLineWidth(float lineWidth); + // Get CocosStudio guide lines width. + float getLineWidth(); + + void setIsConvex(bool isConvex) { _isConvex = isConvex; }; // Set backwards compatible with cocos2dx/axmol 2.0 + + /** + * When isolated is set, the position of the node is no longer affected by parent nodes. + * Which means it will be drawn just like a root node. + */ + void setIsolated(bool isolated) { _isolated = isolated; } + + bool isIsolated() const { return _isolated; } + + DrawNodeEx(float lineWidth = DEFAULT_LINEWIDTH); + virtual ~DrawNodeEx(); + virtual bool init() override; + +protected: + void ensureCapacity(int count); + void ensureCapacityGLPoint(int count); + void ensureCapacityGLLine(int count); + + void updateShader(); + void updateShaderInternal(ax::CustomCommand& cmd, + uint32_t programType, + ax::CustomCommand::DrawType drawType, + ax::CustomCommand::PrimitiveType primitiveType); + void freeShaderInternal(ax::CustomCommand& cmd); + + void setVertexLayout(ax::CustomCommand& cmd); + + void updateBlendState(ax::CustomCommand& cmd); + void updateUniforms(const ax::Mat4& transform, ax::CustomCommand& cmd); + + int _bufferCapacityTriangle = 0; + int _bufferCountTriangle = 0; + ax::V2F_C4B_T2F* _bufferTriangle = nullptr; + + int _bufferCapacityPoint = 0; + int _bufferCountPoint = 0; + ax::V2F_C4B_T2F* _bufferPoint = nullptr; + ax::Color4F _pointColor; + int _pointSize = 0; + + int _bufferCapacityLine = 0; + int _bufferCountLine = 0; + ax::V2F_C4B_T2F* _bufferLine = nullptr; + + ax::BlendFunc _blendFunc; + + ax::CustomCommand _customCommandTriangle; + ax::CustomCommand _customCommandPoint; + ax::CustomCommand _customCommandLine; + + bool _dirtyTriangle = false; + bool _dirtyPoint = false; + bool _dirtyLine = false; + bool _isolated = false; + float _lineWidth = 0.0f; + float _defaultLineWidth = 0.0f; + + bool _isConvex = true; + + ax::any_buffer _abuf; + +private: + AX_DISALLOW_COPY_AND_ASSIGN(DrawNodeEx); +}; +/** @} */ +NS_AX_EXT_END + +#endif // __DRAW_NODE_EX_H__ diff --git a/extensions/README.md b/extensions/README.md index 48864bbcea69..053ace4b1251 100644 --- a/extensions/README.md +++ b/extensions/README.md @@ -61,3 +61,9 @@ - Upstream: https://github.com/EsotericSoftware/spine-runtimes - Version: 4.1-c9af18e with changes to adapte axmol - License: Spine Runtimes License + +## DrawNodeEx + +- Upstream: https://github.com/axmolengine/axmol +- Version: 0.9 +- License: MIT diff --git a/tests/cpp-tests/CMakeLists.txt b/tests/cpp-tests/CMakeLists.txt index ef46b683566d..07999cc6039f 100644 --- a/tests/cpp-tests/CMakeLists.txt +++ b/tests/cpp-tests/CMakeLists.txt @@ -539,6 +539,11 @@ if (AX_ENABLE_EXT_EFFEKSEER) list(APPEND GAME_SOURCE Source/EffekseerTest/EffekseerTest.cpp) endif() +if (AX_ENABLE_EXT_DRAWNODEEX) + list(APPEND GAME_HEADER Source/DrawNodeExTest/DrawNodeExTest.h) + list(APPEND GAME_SOURCE Source/DrawNodeExTest/DrawNodeExTest.cpp) +endif() + list(APPEND GAME_SOURCE Source/UITest/CocoStudioGUITest/UIEditBoxTest.cpp diff --git a/tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.cpp b/tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.cpp new file mode 100644 index 000000000000..fbb54a600692 --- /dev/null +++ b/tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.cpp @@ -0,0 +1,1278 @@ +/**************************************************************************** + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.. + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "DrawNodeExTest.h" + +USING_NS_AX; +USING_NS_AX_EXT; + +using namespace std; + +Vec2 vertices1[] = { + {45.750000f, 144.375000f}, {75.500000f, 136.875000f}, {75.500000f, 159.125000f}, {100.250000f, 161.375000f}, + {65.500000f, 181.375000f}, {102.250000f, 179.125000f}, {95.000000f, 215.125000f}, {129.331467f, 189.926208f}, + {131.371460f, 206.366196f}, {139.651474f, 192.446198f}, {161.851471f, 200.606201f}, {151.000000f, 220.375000f}, + {110.500000f, 244.375000f}, {153.750000f, 238.125000f}, {142.500000f, 253.875000f}, {220.750000f, 259.375000f}, + {250.500000f, 244.375000f}, {168.750000f, 241.875000f}, {182.250000f, 154.125000f}, {190.250000f, 227.375000f}, + {196.500000f, 197.375000f}, {208.750000f, 210.625000f}, {220.750000f, 194.375000f}, {208.750000f, 176.375000f}, + {253.250000f, 173.875000f}, {243.750000f, 154.125000f}, {213.750000f, 161.375000f}, {202.250000f, 139.875000f}, + {236.000000f, 131.875000f}, {218.500000f, 120.875000f}, {206.500000f, 125.625000f}, {184.500000f, 110.375000f}, + {157.000000f, 108.625000f}, {147.500000f, 96.625000f}, {153.750000f, 85.125000f}, {147.500000f, 75.375000f}, + {126.500000f, 74.125000f}, {110.500000f, 86.625000f}, {127.750000f, 85.125000f}, {135.250000f, 91.125000f}, + {135.250000f, 97.875000f}, {124.000000f, 93.875000f}, {115.500000f, 100.875000f}, {115.500000f, 111.875000f}, + {135.250000f, 108.625000f}, {151.000000f, 124.125000f}, {90.500000f, 131.875000f}, {113.250000f, 120.875000f}, + {88.000000f, 116.875000f}, {106.000000f, 103.875000f}, {88.000000f, 97.875000f}}; + +Vec2 vertices2[] = { + {290.250000f, 98.1250000f}, {235.000000f, 90.8750000f}, {270.500000f, 109.875000f}, {235.000000f, 119.125000f}, + {275.250000f, 145.875000f}, {249.500000f, 145.875000f}, {249.500000f, 178.125000f}, {275.250000f, 187.375015f}, + {294.750488f, 168.333344f}, {311.250000f, 181.125000f}, {257.000000f, 213.625015f}, {338.500000f, 193.125000f}, + {300.000000f, 211.125015f}, {333.750000f, 211.125015f}, {368.250000f, 206.625000f}, {377.000000f, 178.125000f}, + {421.750000f, 170.125000f}, {416.250000f, 115.375000f}, {391.250000f, 157.875000f}, {338.500000f, 131.625000f}, + {362.750000f, 131.625000f}, {362.750000f, 106.875000f}, {306.500000f, 119.125000f}, {324.250000f, 85.1250000f}, + {227.500000f, 61.8750000}}; + +DrawNodeExTests::DrawNodeExTests() +{ + ADD_TEST_CASE(DrawNodePart1Test); + ADD_TEST_CASE(DrawNodePart2Test); + ADD_TEST_CASE(DrawNode2Test); + ADD_TEST_CASE(IndividualThicknessTest); + ADD_TEST_CASE(DrawPieTest); +// ADD_TEST_CASE(DrawNode2PolygonTest); + ADD_TEST_CASE(DrawNode2FilledPolygonTest); +} + +string DrawNodeExBaseTest::title() const +{ + return "No title"; +} + +// DrawNodeTest +DrawNode2Test::DrawNode2Test() +{ + auto s = Director::getInstance()->getWinSize(); + + auto draw = ax::extension::DrawNodeEx::create(); + addChild(draw, 10); + + draw->drawPoint(Vec2(s.width / 2 - 120, s.height / 2 - 120), 10, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1)); + + draw->drawPoint(Vec2(s.width / 2 + 120, s.height / 2 + 120), 10, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1)); + + // draw 4 small points + Vec2 position[] = {Vec2(60, 60), Vec2(70, 70), Vec2(60, 70), Vec2(70, 60)}; + draw->drawPoints(position, 4, 5, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1)); + + // draw a line + draw->drawLine(Vec2(0, 0), Vec2(s.width, s.height), Color4F(1.0, 0.0, 0.0, 0.5)); + + // draw a rectangle + draw->drawRect(Vec2(23, 23), Vec2(7, 7), Color4F(1, 1, 0, 1)); + + draw->drawRect(Vec2(15, 30), Vec2(30, 15), Vec2(15, 0), Vec2(0, 15), + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1)); + + // draw a circle + draw->drawCircle(VisibleRect::center() + Vec2(140, 0), 100, AX_DEGREES_TO_RADIANS(90), 50, true, 1.0f, 2.0f, + Color4F(1.0f, 0.0f, 0.0f, 0.5f)); + + draw->drawCircle(VisibleRect::center() - Vec2(140, 0), 50, AX_DEGREES_TO_RADIANS(90), 30, false, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + + // Draw some beziers + draw->drawQuadBezier(Vec2(s.width - 150, s.height - 150), Vec2(s.width - 70, s.height - 10), + Vec2(s.width - 10, s.height - 10), 10, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + draw->drawQuadBezier(Vec2(0.0f, s.height), Vec2(s.width / 2, s.height / 2), Vec2(s.width, s.height), 50, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + draw->drawCubicBezier(VisibleRect::center(), Vec2(VisibleRect::center().x + 30, VisibleRect::center().y + 50), + Vec2(VisibleRect::center().x + 60, VisibleRect::center().y - 50), VisibleRect::right(), 100, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + draw->drawCubicBezier(Vec2(s.width - 250, 40.0f), Vec2(s.width - 70, 100.0f), Vec2(s.width - 30, 250.0f), + Vec2(s.width - 10, s.height - 50), 10, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + auto array = ax::PointArray::create(20); + array->addControlPoint(Vec2(0.0f, 0.0f)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array->addControlPoint(Vec2(80.0f, s.height - 80)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width / 2, s.height / 2)); + draw->drawCardinalSpline(array, 0.5f, 50, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + auto array2 = ax::PointArray::create(20); + array2->addControlPoint(Vec2(s.width / 2, 30.0f)); + array2->addControlPoint(Vec2(s.width - 80, 30.0f)); + array2->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, 30.0f)); + draw->drawCatmullRom(array2, 50, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + // open random color poly + Vec2 vertices[] = {Vec2(0.0f, 0.0f), Vec2(50.0f, 50.0f), Vec2(100.0f, 50.0f), Vec2(100.0f, 100.0f), + Vec2(50.0f, 100.0f)}; + draw->drawPoly(vertices, 5, false, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + + // closed random color poly + Vec2 vertices2[] = {Vec2(30.0f, 130.0f), Vec2(30.0f, 230.0f), Vec2(50.0f, 200.0f)}; + draw->drawPoly(vertices2, 3, true, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + + // Draw 10 circles + for (int i = 0; i < 10; i++) + { + draw->drawDot(Vec2(s.width / 2, s.height / 2), 10 * (10 - i), + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + } + + // Draw polygons + Vec2 points[] = {Vec2(s.height / 4, 0.0f), Vec2(s.width, s.height / 5), Vec2(s.width / 3 * 2, s.height)}; + draw->drawPolygon(points, sizeof(points) / sizeof(points[0]), Color4F(1.0f, 0.0f, 0.0f, 0.5f), 4, + Color4F(0.0f, 0.0f, 1.0f, 0.5f)); + + // star poly (triggers buggs) + { + const float o = 80; + const float w = 20; + const float h = 50; + Vec2 star[] = { + Vec2(o + w, o - h), Vec2(o + w * 2, o), // lower spike + Vec2(o + w * 2 + h, o + w), Vec2(o + w * 2, o + w * 2), // right spike + // {o +w, o+w*2+h}, {o,o+w*2}, // top spike + // {o -h, o+w}, {o,o}, // left spike + }; + + draw->drawPolygon(star, sizeof(star) / sizeof(star[0]), Color4F(1.0f, 0.0f, 0.0f, 0.5f), 1, + Color4F(0.0f, 0.0f, 1.0f, 1.0f)); + } + + // star poly (doesn't trigger bug... order is important un tesselation is supported. + { + const float o = 180; + const float w = 20; + const float h = 50; + Vec2 star[] = { + Vec2(o, o), + Vec2(o + w, o - h), + Vec2(o + w * 2, o), // lower spike + Vec2(o + w * 2 + h, o + w), + Vec2(o + w * 2, o + w * 2), // right spike + Vec2(o + w, o + w * 2 + h), + Vec2(o, o + w * 2), // top spike + Vec2(o - h, o + w), // left spike + }; + + draw->drawPolygon(star, sizeof(star) / sizeof(star[0]), Color4F(1.0f, 0.0f, 0.0f, 0.5f), 1, + Color4F(0.0f, 0.0f, 1.0f, 1.0f)); + } + + // draw a solid polygon + Vec2 vertices3[] = {Vec2(60.0f, 160.0f), Vec2(70.0f, 190.0f), Vec2(100.0f, 190.0f), Vec2(90.0f, 160.0f)}; + draw->drawSolidPoly(vertices3, 4, Color4F(1.0f, 1.0f, 0.0f, 1.0f)); + + // draw a solid rectangle + draw->drawSolidRect(Vec2(10.0f, 10.0f), Vec2(20.0f, 20.0f), Color4F(1.0f, 1.0f, 0.0f, 1.0f)); + + // draw a solid circle + draw->drawSolidCircle(VisibleRect::center() + Vec2(140.0f, 0.0f), 40, AX_DEGREES_TO_RADIANS(90), 50, 2.0f, 2.0f, + Color4F(0.0f, 1.0f, 0.0f, 1.0f)); + + // Draw segment + draw->drawSegment(Vec2(20.0f, s.height), Vec2(20.0f, s.height / 2), 10, Color4F(0.0f, 1.0f, 0.0f, 1.0f)); + + draw->drawSegment(Vec2(10.0f, s.height / 2), Vec2(s.width / 2, s.height / 2), 40, Color4F(1.0f, 0.0f, 1.0f, 0.5f)); + + // Draw triangle + draw->drawTriangle(Vec2(10.0f, 10.0f), Vec2(70.0f, 30.0f), Vec2(100.0f, 140.0f), + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + for (int i = 0; i < 100; i++) + { + draw->drawPoint(Vec2(i * 7.0f, 5.0f), (float)i / 5 + 1, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + } + + auto draw1 = ax::extension::DrawNodeEx::create(); + this->addChild(draw1, 10); + draw1->setLineWidth(4); + draw1->drawLine(Vec2(0.0f, s.height), Vec2(s.width, s.height - 20), Color4F::YELLOW); + draw1->drawLine(Vec2(0.0f, 0.0f), Vec2(s.width, s.height - 20), Color4F::YELLOW); + + draw->runAction(RepeatForever::create(Sequence::create(FadeIn::create(1.2), FadeOut::create(1.2), NULL))); + draw1->runAction(RepeatForever::create(Sequence::create(FadeIn::create(1.2), FadeOut::create(1.2), NULL))); +} + +string DrawNode2Test::title() const +{ + return "DrawNode vs DrawNodeEx"; +} + +string DrawNode2Test::subtitle() const +{ + return ""; +} + +// +// +// +IndividualThicknessTest::IndividualThicknessTest() +{ + // Add lines to see the correct "scale of the 'rings'" changing the window size + + auto draw = DrawNodeEx::create(); + draw->setLineWidth(1); + addChild(draw, 10); + + for (float y = 0; y < VisibleRect::top().y; y += 10) + { + draw->drawLine({VisibleRect::left().x, y}, {VisibleRect::right().x, y}, Color4B::GRAY); + } + initSliders(); + + drawNodeEx = DrawNodeEx::create(); + addChild(drawNodeEx, 10); + + auto s = Director::getInstance()->getWinSize(); + // auto draw1 = DrawNodeExt::create(); + // this->addChild(draw1, 10); + //// draw1->setLineWidth(4); + // draw1->drawLine(Vec2(0.0f, s.height), Vec2(s.width, s.height - 20), Color4F::YELLOW); + // draw1->drawLine(Vec2(0.0f, 0.0f), Vec2(s.width, s.height - 20), Color4F::YELLOW); + + scheduleUpdate(); +} + +void IndividualThicknessTest::changeThickness(ax::Ref* pSender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + ax::ui::Slider* sliderthickness = dynamic_cast(pSender); + thickness = static_cast(sliderthickness->getPercent()) / 10.0f; + _thicknessLabel->setString("Thickness " + Value(thickness).asString()); + } +} + +void IndividualThicknessTest::initSliders() +{ + + // Layer => LayerRadialGradientTest ############################################# Peter Eismann + + auto vsize = Director::getInstance()->getVisibleSize(); + ax::ui::Slider* slider = ax::ui::Slider::create(); + slider->setPercent(0); + slider->loadBarTexture("cocosui/sliderTrack.png"); + slider->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + slider->loadProgressBarTexture("cocosui/sliderProgress.png"); + slider->setPosition(Vec2(vsize.width / 2, vsize.height / 6)); + + slider->addEventListener(AX_CALLBACK_2(IndividualThicknessTest::changeThickness, this)); + + auto ttfConfig = TTFConfig("fonts/arial.ttf", 8); + _thicknessLabel = Label::createWithTTF(ttfConfig, "Thickness "); + addChild(_thicknessLabel, 20); + _thicknessLabel->setPosition(Vec2(vsize.width / 2, vsize.height / 6 + 15)); + + addChild(slider, 20); +} + +void IndividualThicknessTest::update(float dt) +{ + auto s = Director::getInstance()->getWinSize(); + + drawNodeEx->clear(); + auto color = Color4F::GREEN; + drawNodeEx->drawCircle(VisibleRect::center() /*- Vec2(120.0f, 0.0f)*/, 60, AX_DEGREES_TO_RADIANS(77), 36, false, + color, thickness); + + // drawNodeEx->drawCircle(VisibleRect::center() /*- Vec2(120.0f, 0.0f)*/, 60, AX_DEGREES_TO_RADIANS(77), 36, false, + // Color4F::BLACK, 1); + + // drawNodeEx->drawLine(Vec2(0.0f, s.height), Vec2(s.width, s.height - 20), Color4F::YELLOW, thickness); + // drawNodeEx->drawLine(Vec2(0.0f, 0.0f), Vec2(s.width, s.height - 20), Color4F::YELLOW, thickness); + + // draw a rectangles + drawNodeEx->drawRect(Vec2(123, 123), Vec2(227, 227), Color4F(1, 1, 0, 1), thickness); + // drawNodeEx->drawRect(Vec2(123, 123), Vec2(227, 227), Color4F::BLACK, 1); + + drawNodeEx->drawRect(Vec2(115, 130), Vec2(130, 115), Vec2(115, 100), Vec2(100, 115), Color4F::MAGENTA, thickness); + // drawNodeEx->drawRect(Vec2(115, 130), Vec2(130, 115), Vec2(115, 100), Vec2(100, 115), Color4F::BLACK, 1); + + drawNodeEx->drawLine(Vec2(200.0f, s.height - 20), Vec2(s.width - 100, s.height - 20), Color4F::YELLOW, thickness); + drawNodeEx->drawLine(Vec2(300.0f, 100.0f), Vec2(s.width - 200, s.height - 120), Color4F::GREEN, thickness); + + Vec2 vertices24[] = { + {45.750000f, 144.375000f}, {75.500000f, 136.875000f}, {75.500000f, 159.125000f}, {100.250000f, 161.375000f}, + {65.500000f, 181.375000f}, {102.250000f, 179.125000f}, {95.000000f, 215.125000f}, {129.331467f, 189.926208f}, + {131.371460f, 206.366196f}, {139.651474f, 192.446198f}, {161.851471f, 200.606201f}, {151.000000f, 220.375000f}, + {110.500000f, 244.375000f}, {153.750000f, 238.125000f}, {142.500000f, 253.875000f}, {220.750000f, 259.375000f}, + {250.500000f, 244.375000f}, {168.750000f, 241.875000f}, {182.250000f, 154.125000f}, {190.250000f, 227.375000f}, + {196.500000f, 197.375000f}, {208.750000f, 210.625000f}, {220.750000f, 194.375000f}, {208.750000f, 176.375000f}, + {253.250000f, 173.875000f}, {243.750000f, 154.125000f}, {213.750000f, 161.375000f}, {202.250000f, 139.875000f}, + {236.000000f, 131.875000f}, {218.500000f, 120.875000f}, {206.500000f, 125.625000f}, {184.500000f, 110.375000f}, + {157.000000f, 108.625000f}, {147.500000f, 96.625000f}, {153.750000f, 85.125000f}, {147.500000f, 75.375000f}, + {126.500000f, 74.125000f}, {110.500000f, 86.625000f}, {127.750000f, 85.125000f}, {135.250000f, 91.125000f}, + {135.250000f, 97.875000f}, {124.000000f, 93.875000f}, {115.500000f, 100.875000f}, {115.500000f, 111.875000f}, + {135.250000f, 108.625000f}, {151.000000f, 124.125000f}, {90.500000f, 131.875000f}, {113.250000f, 120.875000f}, + {88.000000f, 116.875000f}, {106.000000f, 103.875000f}, {88.000000f, 97.875000f}, + }; + drawNodeEx->drawPolygon(vertices24, sizeof(vertices24) / sizeof(vertices24[0]), Color4B::AX_TRANSPARENT, thickness, + Color4F::RED); + // drawNodeEx->drawPolygon(vertices24, sizeof(vertices24) / sizeof(vertices24[0]), Color4B::AX_TRANSPARENT, 0.5f, + // Color4F::BLACK); + + // open random color poly + Vec2 vertices[] = {Vec2(0.0f, 0.0f), Vec2(50.0f, 50.0f), Vec2(100.0f, 50.0f), Vec2(100.0f, 100.0f), + Vec2(50.0f, 100.0f)}; + drawNodeEx->drawPoly(vertices, 5, false, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f), thickness); + + // closed random color poly + Vec2 vertices2[] = {Vec2(30.0f, 130.0f), Vec2(30.0f, 230.0f), Vec2(50.0f, 200.0f)}; + drawNodeEx->drawPoly(vertices2, 3, true, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f), thickness); + + // Draw some beziers + // Draw some beziers + drawNodeEx->drawQuadBezier(Vec2(s.width - 150, s.height - 150), Vec2(s.width - 70, s.height - 10), + Vec2(s.width - 10, s.height - 10), 10, Color4F::BLUE, thickness); + + drawNodeEx->drawQuadBezier(Vec2(0.0f + 100, s.height - 100), Vec2(s.width / 2, s.height / 2), + Vec2(s.width - 100, s.height - 100), 50, Color4F::RED, thickness); + + drawNodeEx->drawCubicBezier(VisibleRect::center(), Vec2(VisibleRect::center().x + 30, VisibleRect::center().y + 50), + Vec2(VisibleRect::center().x + 60, VisibleRect::center().y - 50), VisibleRect::right(), + 100, Color4F::WHITE, thickness); + + drawNodeEx->drawCubicBezier(Vec2(s.width - 250, 40.0f), Vec2(s.width - 70, 100.0f), Vec2(s.width - 30, 250.0f), + Vec2(s.width - 10, s.height - 50), 10, Color4F::GRAY, thickness); + + auto array = ax::PointArray::create(20); + array->addControlPoint(Vec2(0.0f, 0.0f)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array->addControlPoint(Vec2(80.0f, s.height - 80)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width / 2, s.height / 2)); + drawNodeEx->drawCardinalSpline(array, 0.5f, 50, Color4F::MAGENTA, thickness); + + auto array2 = ax::PointArray::create(20); + array2->addControlPoint(Vec2(s.width / 2, 30.0f)); + array2->addControlPoint(Vec2(s.width - 80, 30.0f)); + array2->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, 30.0f)); + drawNodeEx->drawCatmullRom(array2, 50, Color4F::ORANGE, thickness); +} + +string IndividualThicknessTest::title() const +{ + return "Individual line width"; +} + +string IndividualThicknessTest::subtitle() const +{ + return ""; +} + +DrawPieTest::DrawPieTest() +{ + drawNode = DrawNodeEx::create(); + addChild(drawNode, 10); + + initSliders(); + + scheduleUpdate(); +} + +void DrawPieTest::changeEndAngle(ax::Ref* pSender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + ax::ui::Slider* sEndAngle = dynamic_cast(pSender); + endAngle = sEndAngle->getPercent() * 3.6; + _EndAngleLabel->setString("endAngle: (" + Value(endAngle).asString() + ")"); + } +} + +void DrawPieTest::changeStartAngle(ax::Ref* pSender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + ax::ui::Slider* sStartAngle = dynamic_cast(pSender); + startAngle = sStartAngle->getPercent() * 3.6; + _StartAngleLabel->setString("startAngle: (" + Value(startAngle).asString() + ")"); + } +} + +void DrawPieTest::changeRotation(ax::Ref* pSender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + ax::ui::Slider* sStartAngle = dynamic_cast(pSender); + rotation = sStartAngle->getPercent() * 3.6; + _RotationLabel->setString("Rotation: (" + Value(rotation).asString() + ")"); + } +} + +void DrawPieTest::changeThickness(ax::Ref* pSender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + ax::ui::Slider* sStartAngle = dynamic_cast(pSender); + thickness = sStartAngle->getPercent() * 0.1; + _ThicknessLabel->setString("Thickness: (" + Value(thickness).asString() + ")"); + } +} + +void DrawPieTest::initSliders() +{ + rotation = 324; + endAngle = 30; + startAngle = 0; + thickness = 1; + + auto vsize = Director::getInstance()->getVisibleSize(); + ax::ui::Slider* sliderStartAngle = ax::ui::Slider::create(); + sliderStartAngle->setPercent(startAngle); + sliderStartAngle->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + sliderStartAngle->loadBarTexture("cocosui/sliderTrack.png"); + sliderStartAngle->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + sliderStartAngle->loadProgressBarTexture("cocosui/sliderProgress.png"); + sliderStartAngle->setPosition(Vec2(20, vsize.height / 6)); + + sliderStartAngle->addEventListener(AX_CALLBACK_2(DrawPieTest::changeStartAngle, this)); + + auto ttfConfig = TTFConfig("fonts/arial.ttf", 8); + _StartAngleLabel = Label::createWithTTF(ttfConfig, "StartAngle (" + Value(startAngle).asString() + ")"); + _StartAngleLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + addChild(_StartAngleLabel, 20); + _StartAngleLabel->setPosition(sliderStartAngle->getPosition() + Vec2(sliderStartAngle->getContentSize().x + 20, 0)); + + addChild(sliderStartAngle, 20); + + ax::ui::Slider* sliderEndAngle = ax::ui::Slider::create(); + sliderEndAngle->setPercent(endAngle); + sliderEndAngle->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + sliderEndAngle->loadBarTexture("cocosui/sliderTrack.png"); + sliderEndAngle->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + sliderEndAngle->loadProgressBarTexture("cocosui/sliderProgress.png"); + sliderEndAngle->setPosition(Vec2(20, vsize.height / 6 + 25)); + sliderEndAngle->addEventListener(AX_CALLBACK_2(DrawPieTest::changeEndAngle, this)); + + _EndAngleLabel = Label::createWithTTF(ttfConfig, "endAngle (" + Value(endAngle).asString() + ")"); + _EndAngleLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + addChild(_EndAngleLabel, 20); + _EndAngleLabel->setPosition(sliderEndAngle->getPosition() + Vec2(sliderEndAngle->getContentSize().x + 20, 0)); + addChild(sliderEndAngle, 20); + + ax::ui::Slider* sliderRotation = ax::ui::Slider::create(); + sliderRotation->setPercent(rotation); + sliderRotation->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + sliderRotation->loadBarTexture("cocosui/sliderTrack.png"); + sliderRotation->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + sliderRotation->loadProgressBarTexture("cocosui/sliderProgress.png"); + sliderRotation->setPosition(Vec2(20, vsize.height / 6 + 50)); + sliderRotation->addEventListener(AX_CALLBACK_2(DrawPieTest::changeRotation, this)); + + _RotationLabel = Label::createWithTTF(ttfConfig, "Rotation (" + Value(rotation).asString() + ")"); + _RotationLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + addChild(_RotationLabel, 20); + _RotationLabel->setPosition(sliderRotation->getPosition() + Vec2(sliderRotation->getContentSize().x + 20, 0)); + addChild(sliderRotation, 20); + + ax::ui::Slider* sliderThickness = ax::ui::Slider::create(); + sliderThickness->setPercent(thickness); + sliderThickness->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + sliderThickness->loadBarTexture("cocosui/sliderTrack.png"); + sliderThickness->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + sliderThickness->loadProgressBarTexture("cocosui/sliderProgress.png"); + sliderThickness->setPosition(Vec2(20, vsize.height / 6 + 75)); + sliderThickness->addEventListener(AX_CALLBACK_2(DrawPieTest::changeThickness, this)); + + _ThicknessLabel = Label::createWithTTF(ttfConfig, "Thickness (" + Value(thickness).asString() + ")"); + _ThicknessLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + addChild(_ThicknessLabel, 20); + _ThicknessLabel->setPosition(sliderThickness->getPosition() + Vec2(sliderThickness->getContentSize().x + 20, 0)); + addChild(sliderThickness, 20); +} + +void DrawPieTest::update(float dt) +{ + drawNode->clear(); + drawNode->drawPie(VisibleRect::center() - Vec2(170.0f, -35.0f), 50, rotation, startAngle, endAngle, 1.0f, 1.0f, + Color4F::RED, Color4F::BLUE, drawNode->DrawMode::Fill, thickness); + drawNode->drawPie(VisibleRect::center() - Vec2(60.0f, -35.0f), 50, rotation, startAngle, endAngle, 1.0f, 1.0f, + Color4F::AX_TRANSPARENT, Color4F::BLUE, drawNode->DrawMode::Outline, thickness); + drawNode->drawPie(VisibleRect::center() + Vec2(60.0f, 35.0f), 50, rotation, startAngle, endAngle, 1.0f, 1.0f, + Color4F::RED, Color4F::BLUE, drawNode->DrawMode::Line, thickness); + drawNode->drawPie(VisibleRect::center() + Vec2(170.0f, 35.0f), 50, rotation, startAngle, endAngle, 1.0f, 1.0f, + Color4F::RED, Color4F::BLUE, drawNode->DrawMode::Semi, thickness); +} + +string DrawPieTest::title() const +{ + return "drawPie"; +} + +string DrawPieTest::subtitle() const +{ + return "Filled, Outlined, Line, Semi"; +} + +DrawNode2PolygonTest::DrawNode2PolygonTest() +{ + auto director = Director::getInstance(); + // director->setClearColor(Color4F(0, 0, 0, 0)); + auto origin = director->getVisibleOrigin(); + auto size = director->getVisibleSize(); + center = Vec2(origin.x + size.width / 2 + 50, origin.y + size.height / 2); + + float o = 80; + float w = 20; + float h = 50; + drawNodeEx = DrawNodeEx::create(); + addChild(drawNodeEx); + // drawNodeEx->setPosition(center); + + { // star + + Vec2 star[] = { + Vec2(o, o), + Vec2(o + w, o - h), + Vec2(o + w * 2, o), // lower spike + Vec2(o + w * 2 + h, o + w), + Vec2(o + w * 2, o + w * 2), // right spike + Vec2(o + w, o + w * 2 + h), + Vec2(o, o + w * 2), // top spike + Vec2(o - h, o + w), // left spike + }; + + drawNodeEx->setDNPosition(center); + drawNodeEx->setDNCenter(star[0]); + // drawNodeEx->setDNRotation(rot); + drawNodeEx->drawPolygon(star, sizeof(star) / sizeof(star[0]), Color4F(0.0f, 0.0f, 0.7f, 0.5f), 1, + Color4F::BLUE); + } + + scheduleUpdate(); +} + +void DrawNode2PolygonTest::drawDirection(const Vec2* vec, const int size, Vec2 offset) +{ + for (size_t i = 0; i < size; i++) + { + auto label = Label::createWithTTF(std::to_string(i).c_str(), "fonts/Marker Felt.ttf", 10); + this->addChild(label); + label->setPosition(vec[i] + offset); + } +} + +string DrawNode2PolygonTest::title() const +{ + return "DrawNodeVersion and Rotation"; +} + +string DrawNode2PolygonTest::subtitle() const +{ + return "YELLOW=v1 ORANGE=v2"; +} + +void DrawNode2PolygonTest::update(float dt) +{ + float rot = 0.1; + float o = 80; + float w = 20; + float h = 50; + { // star + + Vec2 star[] = { + Vec2(o, o), + Vec2(o + w, o - h), + Vec2(o + w * 2, o), // lower spike + Vec2(o + w * 2 + h, o + w), + Vec2(o + w * 2, o + w * 2), // right spike + Vec2(o + w, o + w * 2 + h), + Vec2(o, o + w * 2), // top spike + Vec2(o - h, o + w), // left spike + }; + +/* drawNodeEx->setDNPosition(center); + drawNodeEx->setDNCenter(star[0]); + drawNodeEx->setDNRotation(rot)*/; + drawNodeEx->drawPolygon(star, sizeof(star) / sizeof(star[0]), Color4F(0.0f, 0.0f, 0.7f, 0.5f), 1, + Color4F::BLUE); + } + { + int x = 0; + int y = 0; + Vec2 vertices[4]; + drawNodeEx->setScale(0.5); + Color4F color; + for (int iy = 0; iy < 5; iy++) + { + x = 0; + for (int ix = 0; ix < 13; ix++) + { + vertices[0] = Vec2(x + o + w, y + o - h); + vertices[1] = Vec2(x + o + w * 2, y + o); + vertices[2] = Vec2(x + o + w * 2 + h, y + o + w); + vertices[3] = Vec2(x + o + w * 2, y + o + w * 2); + + if (AXRANDOM_0_1() > 0.5f) + { + drawNodeEx->setIsConvex(true); + color = Color4F::YELLOW; + } + else + { + drawNodeEx->setIsConvex(false); + color = Color4F::ORANGE; + } + //drawNodeEx->setDNRotation(rot); + //drawNodeEx->setDNCenter(vertices[0]); + //drawNodeEx->setDNPosition(Vec2(-70.f, 60.f)); + drawNodeEx->drawPolygon(vertices, 4, Color4F(0.7f, 0.7f, 0.7f, 0.5f), 1, color); + drawNodeEx->setIsConvex(false); + x += 70; + } + y += 80; + } + } + + rot += 0.1; +} + +DrawNode2FilledPolygonTest::DrawNode2FilledPolygonTest() +{ + + DrawNodeEx* drawNode[3]; + for (int i = 0; i < 3; i++) + { + drawNode[i] = DrawNodeEx::create(); + addChild(drawNode[i]); + } + + // draw a solid circle + drawNode[1]->drawSolidCircle(VisibleRect::center() + Vec2(140.0f, 0.0f), 40, AX_DEGREES_TO_RADIANS(90), 30, 2.0f, + 2.0f, Color4F::BLUE); + + drawNode[1]->drawSolidCircle(VisibleRect::center() + Vec2(-40.0f, 0.0f), 40, AX_DEGREES_TO_RADIANS(90), 30, 2.0f, + 2.0f, Color4F::WHITE); + + drawNode[0]->setPosition(Vec2(-30, -20)); + // drawNodeEx[0]->drawPolygon(vertices24, sizeof(vertices24) / sizeof(vertices24[0]), Color4F::RED, 0.3f, + // Color4F::GREEN); + + drawNode[2]->drawPolygon(vertices2, sizeof(vertices2) / sizeof(vertices2[0]), Color4F::GREEN, 0.3f, + Color4F::YELLOW); + + drawNode[2]->drawPolygon(vertices1, sizeof(vertices1) / sizeof(vertices1[0]), Color4F::AX_TRANSPARENT, 5.3f, + Color4F::RED); +} + +string DrawNode2FilledPolygonTest::title() const +{ + return "Filled Polygon Test #2"; +} + +string DrawNode2FilledPolygonTest::subtitle() const +{ + return ""; +} + +// DrawMethodesThicknessTest +DrawNodePart1Test::DrawNodePart1Test() +{ + _currentSeletedItemIndex = 0; + + auto director = Director::getInstance(); + director->setClearColor(Color4F(0, 0, 0, 0)); + auto origin = director->getVisibleOrigin(); + auto size = director->getVisibleSize(); + Vec2 center(origin.x + size.width / 2 + 50, origin.y + size.height / 2); + + auto listview = createListView(); + listview->setPosition(Vec2(0.0f, 90.0f)); + addChild(listview); + + draw = DrawNodeEx::create(); + draw->setScale(0.5); + draw->setPosition(center); + addChild(draw); + + draw1 = DrawNode::create(); + draw1->setScale(0.5); + draw1->setPosition(size / 4); + addChild(draw1); + + auto thicknessSlider = createSlider(); + thicknessSlider->setPosition(Vec2(center.x, 60.0f)); + addChild(thicknessSlider); + + label = Label::createWithTTF("Value: ", "fonts/Marker Felt.ttf", 10); + label->setPosition(Vec2(Vec2(center.x, 80.0f))); + this->addChild(label, 1); + isDirty = true; + scheduleUpdate(); +} + +std::string DrawNodePart1Test::title() const +{ + return "Scale/Rotation/LineWidth/Position"; +} + +string DrawNodePart1Test::subtitle() const +{ + return ""; +} + +ax::ui::Slider* DrawNodePart1Test::createSlider() +{ + auto slider = ui::Slider::create(); + slider->setTouchEnabled(true); + slider->loadBarTexture("cocosui/sliderTrack.png"); + slider->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + slider->loadProgressBarTexture("cocosui/sliderProgress.png"); + slider->addEventListener(AX_CALLBACK_2(DrawNodePart1Test::sliderCallback, this)); + slider->setTag(101); + slider->setPercent(10); + + return slider; +} + +void DrawNodePart1Test::listviewCallback(ax::Ref* sender, ax::ui::ListView::EventType type) +{ + // clear all text to white + auto listview = static_cast(sender); + for (auto&& item : listview->getItems()) + { + static_cast(item)->setColor(ax::Color3B::WHITE); + } + _currentSeletedItemIndex = (int)listview->getCurSelectedIndex(); + listview->getItem(_currentSeletedItemIndex)->setColor(ax::Color3B::RED); + isDirty = true; +} + +void DrawNodePart1Test::sliderCallback(ax::Ref* sender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + auto slider = dynamic_cast(sender); + thickness = slider->getPercent() * 0.1f; + } + isDirty = true; +} + +ax::ui::ListView* DrawNodePart1Test::createListView() +{ + auto listview = ax::ui::ListView::create(); + + auto drawLine = ax::ui::Text::create(); + drawLine->setString("drawLine"); + drawLine->setTouchEnabled(true); + listview->pushBackCustomItem(drawLine); + + auto drawRect = ax::ui::Text::create(); + drawRect->setString("drawRect"); + drawRect->setTouchEnabled(true); + listview->pushBackCustomItem(drawRect); + + auto drawCircle = ax::ui::Text::create(); + drawCircle->setString("drawCircle"); + drawCircle->setTouchEnabled(true); + listview->pushBackCustomItem(drawCircle); + + auto drawQuadBezier = ax::ui::Text::create(); + drawQuadBezier->setString("drawQuadBezier"); + drawQuadBezier->setTouchEnabled(true); + listview->pushBackCustomItem(drawQuadBezier); + + auto drawCubicBezier = ax::ui::Text::create(); + drawCubicBezier->setString("drawCubicBezier"); + drawCubicBezier->setTouchEnabled(true); + listview->pushBackCustomItem(drawCubicBezier); + + auto drawCardinalSpline = ax::ui::Text::create(); + drawCardinalSpline->setString("drawCardinalSpline"); + drawCardinalSpline->setTouchEnabled(true); + listview->pushBackCustomItem(drawCardinalSpline); + + auto drawCatmullRom = ax::ui::Text::create(); + drawCatmullRom->setString("drawCatmullRom"); + drawCatmullRom->setTouchEnabled(true); + listview->pushBackCustomItem(drawCatmullRom); + + auto drawPoly = ax::ui::Text::create(); + drawPoly->setString("drawPoly"); + drawPoly->setTouchEnabled(true); + listview->pushBackCustomItem(drawPoly); + + auto drawPolygon = ax::ui::Text::create(); + drawPolygon->setString("drawPolygon"); + drawPolygon->setTouchEnabled(true); + listview->pushBackCustomItem(drawPolygon); + + listview->setContentSize(drawLine->getContentSize() * 9); + listview->setCurSelectedIndex(0); + listview->setTouchEnabled(true); + listview->addEventListener( + (ui::ListView::ccListViewCallback)AX_CALLBACK_2(DrawNodePart1Test::listviewCallback, this)); + listview->setTag(100); + + listview->getItem(_currentSeletedItemIndex)->setColor(Color3B::RED); + + return listview; +} + +void DrawNodePart1Test::update(float dt) +{ + // if (isDirty== true) + { + drawAll(); + isDirty = false; + } +} + +void DrawNodePart1Test::drawAll() +{ + isDirty = false; + static float rotation = 0.1; + rotation += 0.1; + auto s = Director::getInstance()->getWinSize(); + + draw->clear(); + label->setString("Thickness: (" + Value(thickness).asString() + ")"); + + switch (_currentSeletedItemIndex) + { + case 0: + { + draw->setRotation(rotation * 3); + draw->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + draw->setScale(0.3); + + // draw->setPosition(0.1); + Vec2 gear1 = {280.f, 320.f}; + Vec2 gear2 = {160.f, 320.f}; + Vec2 gear3 = {200.f, 200.f}; + Vec2 gear4 = {s.width - 200, s.height - 200}; + + draw->drawLine(gear2, gear4, Color4F::RED, thickness); // line + draw->setDNCenter(gear1); + draw->setDNRotation(rotation + 45); + draw->drawStar(Vec2(gear1), 30, 60, 8, Color4F::BLUE, 4.0); + draw->setDNRotation(-rotation); + draw->setDNCenter(gear2); + draw->drawSolidStar(gear2, 30, 60, 8, Color4F::GREEN, Color4F::YELLOW, 4.0); + + draw->resetDNValues(); + draw->drawLine(gear2, gear1, Color4F::RED, thickness); // line + draw->setDNCenter(gear4); + draw->setDNRotation(rotation + 45); + draw->drawStar(gear3, 30, 60, 18, Color4F::RED, 1.0); + draw->drawLine(gear3, gear4, Color4F::YELLOW, thickness); // line + draw->resetDNValues(); + draw->setDNRotation(rotation - 45); + draw->setDNCenter(gear4); + draw->drawStar(gear4, 40, 60, 60, Color4F::GREEN, 1.0); + draw->resetDNValues(); + isDirty = true; + break; + } + case 1: + { + // drawRect + draw->drawRect(Vec2(23, 23), Vec2(7, 7), Color4F(1, 1, 0, 1), thickness); + draw->drawRect(Vec2(15, 30), Vec2(30, 15), Vec2(15, 0), Vec2(0, 15), + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1), thickness); + draw->drawRect(Vec2(123, 123), Vec2(227, 227), Color4F(1, 1, 0, 1), thickness); + draw->drawRect(Vec2(115, 130), Vec2(130, 115), Vec2(115, 100), Vec2(100, 115), Color4F::MAGENTA, thickness); + break; + } + case 2: + { + // drawCircle + draw->drawCircle(VisibleRect::center() + Vec2(140, 0), 100, AX_DEGREES_TO_RADIANS(90), 50, true, 1.0f, 2.0f, + Color4F(1.0f, 0.0f, 0.0f, 0.5f), thickness); + draw->drawCircle(VisibleRect::center() - Vec2(140, 0), 50, AX_DEGREES_TO_RADIANS(90), 30, true, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f), thickness); + break; + } + case 3: + { + // drawCubicBezier + draw->drawQuadBezier(Vec2(s.width - 150, s.height - 150), Vec2(s.width - 70, s.height - 10), + Vec2(s.width - 10, s.height - 10), 10, Color4F::BLUE, thickness); + draw->drawQuadBezier(Vec2(0.0f + 100, s.height - 100), Vec2(s.width / 2, s.height / 2), + Vec2(s.width - 100, s.height - 100), 50, Color4F::RED, thickness); + break; + } + case 4: + { + // drawCubicBezier + draw->drawCubicBezier(VisibleRect::center(), Vec2(VisibleRect::center().x + 30, VisibleRect::center().y + 50), + Vec2(VisibleRect::center().x + 60, VisibleRect::center().y - 50), VisibleRect::right(), + 100, Color4F::WHITE, thickness); + draw->drawCubicBezier(Vec2(s.width - 250, 40.0f), Vec2(s.width - 70, 100.0f), Vec2(s.width - 30, 250.0f), + Vec2(s.width - 10, s.height - 50), 10, Color4F::GRAY, thickness); + break; + } + case 5: + { + // drawCardinalSpline + auto array = ax::PointArray::create(20); + array->addControlPoint(Vec2(0.0f, 0.0f)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array->addControlPoint(Vec2(80.0f, s.height - 80)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width / 2, s.height / 2)); + draw->drawCardinalSpline(array, 0.5f, 50, Color4F::MAGENTA, thickness); + + auto array2 = ax::PointArray::create(20); + array2->addControlPoint(Vec2(s.width / 2, 80.0f)); + array2->addControlPoint(Vec2(s.width - 80, 80.0f)); + array2->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, 80.0f)); + draw->drawCardinalSpline(array2, 5.0f, 50, Color4F::ORANGE, thickness); + break; + } + case 6: + { + // drawCatmullRom + auto array2 = ax::PointArray::create(20); + array2->addControlPoint(Vec2(s.width / 2, 80.0f)); + array2->addControlPoint(Vec2(s.width - 80, 80.0f)); + array2->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, s.height - 80)); + array2->addControlPoint(Vec2(s.width / 2, 80.0f)); + draw->drawCatmullRom(array2, 50, Color4F::ORANGE, thickness); + + auto array = ax::PointArray::create(20); + array->addControlPoint(Vec2(0.0f, 0.0f)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, 80.0f)); + array->addControlPoint(Vec2(s.width - 80, s.height - 80)); + array->addControlPoint(Vec2(80.0f, s.height - 80)); + array->addControlPoint(Vec2(80.0f, 80.0f)); + array->addControlPoint(Vec2(s.width / 2, s.height / 2)); + draw->drawCatmullRom(array, 50, Color4F::MAGENTA, thickness); + break; + } + case 7: + { + // drawPoly + // for (int n = 0; n < 10; n++) + bool isReal = false; + + // draw->drawPoly(verticess, sizeof(verticess) / sizeof(verticess[0]), true, + // Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f), thickness); + + Vec2 vertices[5] = {Vec2(0.0f, 0.0f), Vec2(50.0f, 50.0f), Vec2(100.0f, 50.0f), Vec2(100.0f, 100.0f), + Vec2(50.0f, 100.0f)}; + draw->drawPoly(vertices, 5, false, Color4B::BLUE, thickness); + + Vec2 vertices2[3] = {Vec2(30.0f, 130.0f), Vec2(30.0f, 230.0f), Vec2(50.0f, 200.0f)}; + draw->drawPoly(vertices2, 3, true, Color4B::GREEN, thickness); + + draw->drawPoly(vertices1, sizeof(vertices1) / sizeof(vertices1[0]), true, Color4B::RED, thickness); + + break; + } + case 8: + { + // drawPolygon + + draw->setDNScale(Vec2(thickness, thickness)); + draw->setDNPosition(Vec2(0, 0)); + draw->setDNRotation(0); + draw->drawPolygon(vertices1, sizeof(vertices1) / sizeof(vertices1[0]), Color4F::GREEN, thickness, + Color4F::YELLOW); + draw->setDNPosition(Vec2(0, 0)); + draw->setDNRotation(thickness); + draw->setDNScale(Vec2(thickness, thickness)); + draw->setDNCenter(vertices1[0]); + draw->drawPolygon(vertices1, sizeof(vertices1) / sizeof(vertices1[0]), Color4F::GREEN, thickness, + Color4F::YELLOW); + + draw1->clear(); + draw1->setPosition(Vec2(200, 0)); + draw1->setScale(thickness); + draw1->drawPolygon(vertices1, sizeof(vertices1) / sizeof(vertices1[0]), Color4F::RED, thickness, + Color4F::YELLOW); + + break; + } + default: + break; + } +} + +// DrawFilledPrimitivesTest +DrawNodePart2Test::DrawNodePart2Test() +{ + _currentSeletedItemIndex = 0; + + auto director = Director::getInstance(); + director->setClearColor(Color4F(0, 0, 0, 0)); + auto origin = director->getVisibleOrigin(); + auto size = director->getVisibleSize(); + Vec2 center(origin.x + size.width / 2 + 50, origin.y + size.height / 2); + + auto listview = createListView(); + listview->setPosition(Vec2(0.0f, 90.0f)); + addChild(listview); + + draw = DrawNodeEx::create(); + draw->setScale(0.5); + draw->setPosition(size / 4); + addChild(draw); + + auto thicknessSlider = createSlider(); + thicknessSlider->setPosition(Vec2(center.x, 60.0f)); + addChild(thicknessSlider); + + label = Label::createWithTTF("Count: ", "fonts/Marker Felt.ttf", 10); + label->setPosition(Vec2(Vec2(center.x, 80.0f))); + this->addChild(label, 1); + + scheduleUpdate(); +} + +std::string DrawNodePart2Test::title() const +{ + return "DrawNode #2 Test"; +} + +string DrawNodePart2Test::subtitle() const +{ + return ""; +} + +ax::ui::Slider* DrawNodePart2Test::createSlider() +{ + auto slider = ui::Slider::create(); + slider->setTouchEnabled(true); + slider->loadBarTexture("cocosui/sliderTrack.png"); + slider->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + slider->loadProgressBarTexture("cocosui/sliderProgress.png"); + slider->addEventListener(AX_CALLBACK_2(DrawNodePart2Test::sliderCallback, this)); + // slider->setRotation(90); + slider->setTag(101); + slider->setPercent(10); + + return slider; +} + +void DrawNodePart2Test::listviewCallback(ax::Ref* sender, ax::ui::ListView::EventType type) +{ + // clear all text to white + auto listview = static_cast(sender); + for (auto&& item : listview->getItems()) + { + static_cast(item)->setColor(ax::Color3B::WHITE); + } + _currentSeletedItemIndex = (int)listview->getCurSelectedIndex(); + listview->getItem(_currentSeletedItemIndex)->setColor(ax::Color3B::RED); +} + +void DrawNodePart2Test::sliderCallback(ax::Ref* sender, ax::ui::Slider::EventType type) +{ + if (type == ax::ui::Slider::EventType::ON_PERCENTAGE_CHANGED) + { + auto slider = dynamic_cast(sender); + count = slider->getPercent() * 10; + } +} + +ax::ui::ListView* DrawNodePart2Test::createListView() +{ + auto listview = ax::ui::ListView::create(); + + auto drawLine = ax::ui::Text::create(); + drawLine->setString("drawDot"); + drawLine->setTouchEnabled(true); + listview->pushBackCustomItem(drawLine); + + auto drawSegment = ax::ui::Text::create(); + drawSegment->setString("drawPoint"); + drawSegment->setTouchEnabled(true); + listview->pushBackCustomItem(drawSegment); + + auto drawTriangle = ax::ui::Text::create(); + drawTriangle->setString("drawPoints"); + drawTriangle->setTouchEnabled(true); + listview->pushBackCustomItem(drawTriangle); + + auto drawRect = ax::ui::Text::create(); + drawRect->setString("drawTriangle"); + drawRect->setTouchEnabled(true); + listview->pushBackCustomItem(drawRect); + + auto drawCircle = ax::ui::Text::create(); + drawCircle->setString("drawSegment"); + drawCircle->setTouchEnabled(true); + listview->pushBackCustomItem(drawCircle); + + auto drawQuadBezier = ax::ui::Text::create(); + drawQuadBezier->setString("drawSolidCircle"); + drawQuadBezier->setTouchEnabled(true); + listview->pushBackCustomItem(drawQuadBezier); + + auto drawCubicBezier = ax::ui::Text::create(); + drawCubicBezier->setString("drawSolidPoly"); + drawCubicBezier->setTouchEnabled(true); + listview->pushBackCustomItem(drawCubicBezier); + + auto drawCardinalSpline = ax::ui::Text::create(); + drawCardinalSpline->setString("drawSolidRect"); + drawCardinalSpline->setTouchEnabled(true); + listview->pushBackCustomItem(drawCardinalSpline); + + listview->setContentSize(drawLine->getContentSize() * 8); + listview->setCurSelectedIndex(0); + listview->setTouchEnabled(true); + listview->addEventListener( + (ui::ListView::ccListViewCallback)AX_CALLBACK_2(DrawNodePart2Test::listviewCallback, this)); + listview->setTag(100); + + listview->getItem(_currentSeletedItemIndex)->setColor(Color3B::RED); + + return listview; +} + +void DrawNodePart2Test::update(float dt) +{ + + auto s = Director::getInstance()->getWinSize(); + + draw->clear(); + + label->setString("Count: (" + Value(count).asString() + ")"); + switch (_currentSeletedItemIndex) + { + case 0: + { + // Draw 10 circles/dots + for (int i = 0; i < count / 100; i++) + { + draw->drawDot(Vec2(100.f + AXRANDOM_0_1() * VisibleRect::rightTop().x, + 100.f + AXRANDOM_0_1() * VisibleRect::rightTop().y), + AXRANDOM_0_1() * 20 + 20, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + } + break; + } + case 1: + { + for (int i = 0; i < 100; i++) + { + draw->drawPoint(Vec2(i * 7.0f, 50.0f), (float)i / 5 + 1, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1.0f)); + } + break; + } + case 2: + { + // drawPoints + for (int i = 0; i < count; i++) + { + Vec2 position[] = { + {60 + AXRANDOM_0_1() * VisibleRect::rightTop().x, 60 + AXRANDOM_0_1() * VisibleRect::rightTop().y}, + {70 + AXRANDOM_0_1() * VisibleRect::rightTop().x, 70 + AXRANDOM_0_1() * VisibleRect::rightTop().y}, + {60 + AXRANDOM_0_1() * VisibleRect::rightTop().x, 60 + AXRANDOM_0_1() * VisibleRect::rightTop().y}, + {70 + AXRANDOM_0_1() * VisibleRect::rightTop().x, 70 + AXRANDOM_0_1() * VisibleRect::rightTop().y}}; + draw->drawPoints(position, 4, 5, Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 1)); + } + + break; + } + case 3: + { + // drawTriangle + for (int i = 0; i < count; i++) + { + Vec2 pos = Vec2(AXRANDOM_0_1() * VisibleRect::rightTop().x, AXRANDOM_0_1() * VisibleRect::rightTop().y); + draw->drawTriangle(pos + Vec2(10.0f, 10.0f), pos + Vec2(70.0f, 30.0f), pos + Vec2(100.0f, 140.0f), + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + } + break; + } + case 4: + { + // Draw segment + draw->drawSegment(Vec2(20.0f, s.height), Vec2(20.0f, s.height / 2), 10, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + + draw->drawSegment(Vec2(10.0f, s.height / 2), Vec2(s.width / 2, s.height / 2), 40, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + break; + } + case 5: + { + // draw a solid circle + for (int i = 0; i < count; i++) + { + draw->drawSolidCircle( + Vec2(AXRANDOM_0_1() * VisibleRect::rightTop().x, AXRANDOM_0_1() * VisibleRect::rightTop().y), + AXRANDOM_0_1() * 40.f + 40.f, AX_DEGREES_TO_RADIANS(90), 50, 2.0f, 2.0f, + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + } + break; + } + case 6: + { + // draw a solid poly + draw->resetDNValues(); + draw->setDNPosition(vertices1[0]); + draw->setDNRotation(count); + // draw->setDNScale(Vec2(count, count)); + draw->setDNCenter(vertices1[0]); + draw->drawPoly(vertices1, sizeof(vertices1) / sizeof(vertices1[0]), true, Color4F::GREEN, count); + draw->resetDNValues(); + break; + } + case 7: + { + // draw a solid rectangle + for (int i = 0; i < count; i++) + { + Vec2 pos = Vec2(AXRANDOM_0_1() * VisibleRect::rightTop().x, AXRANDOM_0_1() * VisibleRect::rightTop().y); + draw->drawSolidRect(pos, pos + Vec2(20.0f, 20.0f), + Color4F(AXRANDOM_0_1(), AXRANDOM_0_1(), AXRANDOM_0_1(), 0.5f)); + } + break; + } + default: + break; + } +} diff --git a/tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.h b/tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.h new file mode 100644 index 000000000000..32729f6fcd5e --- /dev/null +++ b/tests/cpp-tests/Source/DrawNodeExTest/DrawNodeExTest.h @@ -0,0 +1,199 @@ +/**************************************************************************** + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). + + https://axmolengine.github.io/ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#pragma once + +#include "axmol.h" +#include "ui/CocosGUI.h" +#include "../BaseTest.h" +#include "extensions/DrawNodeEx/DrawNodeEx.h" + + +DEFINE_TEST_SUITE(DrawNodeExTests); + +class DrawNodeExBaseTest : public TestCase +{ +public: + virtual std::string title() const override; +}; + +class DrawNode2Test : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(DrawNode2Test); + + DrawNode2Test(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; +}; +// +// class Issue11942Test : public DrawPrimitivesBaseTest +//{ +// public: +// CREATE_FUNC(Issue11942Test); +// +// Issue11942Test(); +// +// virtual std::string title() const override; +// virtual std::string subtitle() const override; +//}; + +class IndividualThicknessTest : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(IndividualThicknessTest); + + IndividualThicknessTest(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + void update(float dt); + + void initSliders(); + void changeThickness(ax::Ref* pSender, ax::ui::Slider::EventType type); + // void changeLineWidth(Ref* pSender, ax::ui::Slider::EventType type); + +private: + ax::extension::DrawNodeEx* drawNodeEx; + // ax::Label* _lineWidthLabel; + // float lineWidth = 0; + ax::Label* _thicknessLabel; + float thickness = 1.0f; +}; + +class DrawNode2PolygonTest : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(DrawNode2PolygonTest); + + DrawNode2PolygonTest(); + void drawDirection(const ax::Vec2* vec, const int size, ax::Vec2 offset); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + void update(float dt); + +private: + ax::extension::DrawNodeEx* drawNodeEx; + ax::Vec2 center; +}; + +class DrawNode2FilledPolygonTest : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(DrawNode2FilledPolygonTest); + + DrawNode2FilledPolygonTest(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; +}; + +class DrawPieTest : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(DrawPieTest); + + DrawPieTest(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + void update(float dt); + + void initSliders(); + void changeStartAngle(ax::Ref* pSender, ax::ui::Slider::EventType type); + void changeEndAngle(ax::Ref* pSender, ax::ui::Slider::EventType type); + void changeRotation(ax::Ref* pSender, ax::ui::Slider::EventType type); + void changeThickness(ax::Ref* pSender, ax::ui::Slider::EventType type); + +private: + ax::extension::DrawNodeEx* drawNode; + ax::Label* _StartAngleLabel; + float startAngle = 0; + ax::Label* _EndAngleLabel; + float endAngle = 0; + ax::Label* _RotationLabel; + float rotation = 0; + ax::Label* _ThicknessLabel; + float thickness = 0; +}; + +class DrawNodePart1Test : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(DrawNodePart1Test); + + DrawNodePart1Test(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + void update(float dt); + + void sliderCallback(ax::Ref* sender, ax::ui::Slider::EventType type); + void listviewCallback(ax::Ref* sender, ax::ui::ListView::EventType type); + + void drawAll(); + +private: + ax::ui::Slider* createSlider(); + ax::ui::ListView* createListView(); + ax::extension::DrawNodeEx* draw; + ax::DrawNode* draw1; + ax::Vec2* verticess; + + int _currentSeletedItemIndex = 0; + float thickness = 0.1f; + bool isDirty = false; + + ax::Label* label; +}; + +class DrawNodePart2Test : public DrawNodeExBaseTest +{ +public: + CREATE_FUNC(DrawNodePart2Test); + + DrawNodePart2Test(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + void update(float dt); + + void sliderCallback(ax::Ref* sender, ax::ui::Slider::EventType type); + void listviewCallback(ax::Ref* sender, ax::ui::ListView::EventType type); + + void drawAll(); + +private: + ax::ui::Slider* createSlider(); + ax::ui::ListView* createListView(); + ax::extension::DrawNodeEx* draw; + + int _currentSeletedItemIndex = 0; + int count = 1; + bool isDirty = false; + + ax::Label* label; +}; diff --git a/tests/cpp-tests/Source/controller.cpp b/tests/cpp-tests/Source/controller.cpp index e249f4b55c70..171a4fa137e6 100644 --- a/tests/cpp-tests/Source/controller.cpp +++ b/tests/cpp-tests/Source/controller.cpp @@ -1,5 +1,6 @@ /**************************************************************************** Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). https://axmolengine.github.io/ @@ -47,7 +48,10 @@ class RootTests : public TestList #pragma message("The optional extension Effekseer is enabled.") addTest("Effekseer", []() { return new EffekseerTests(); }); #endif - +#if __has_include("DrawNodeExTest/DrawNodeExTest.h") +# pragma message("The optional extension DrawNodeEx is enabled.") + addTest("DrawNodeEx", []() { return new DrawNodeExTests(); }); +#endif // addTest("Node: Scene3D", [](){return new Scene3DTests(); }); #if defined(AX_PLATFORM_PC) || (AX_TARGET_PLATFORM == AX_PLATFORM_ANDROID) || defined(__EMSCRIPTEN__) addTest("ImGui", []() { return new ImGuiTests(); }); diff --git a/tests/cpp-tests/Source/tests.h b/tests/cpp-tests/Source/tests.h index 3672aa3556fb..20dcb20679da 100644 --- a/tests/cpp-tests/Source/tests.h +++ b/tests/cpp-tests/Source/tests.h @@ -1,5 +1,6 @@ /**************************************************************************** Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md). https://axmolengine.github.io/ @@ -72,6 +73,11 @@ #include "DataVisitorTest/DataVisitorTest.h" #include "NetworkTest/NetworkTest.h" #include "DrawPrimitivesTest/DrawPrimitivesTest.h" + +#if __has_include("DrawNodeExTest/DrawNodeExTest.h") +#include "DrawNodeExTest/DrawNodeExTest.h" +#endif + #include "EffectsAdvancedTest/EffectsAdvancedTest.h" #include "EffectsTest/EffectsTest.h" #include "ExtensionsTest/ExtensionsTest.h"