From fee39cb531e876720aea8fa1c22c3980c6460ac1 Mon Sep 17 00:00:00 2001 From: jpgonzalezra Date: Wed, 24 Jan 2024 16:36:26 -0300 Subject: [PATCH] fix: body improvements (#5) --- packages/contracts/src/LucidOrigins.sol | 20 ++- packages/contracts/src/layers/Background.sol | 3 +- packages/contracts/src/layers/Blob.sol | 136 +++++++++++++++++++ packages/contracts/src/layers/Body.sol | 51 ++++--- packages/contracts/src/layers/Face.sol | 71 ++++++++-- packages/contracts/src/layers/Head.sol | 121 +---------------- 6 files changed, 248 insertions(+), 154 deletions(-) create mode 100644 packages/contracts/src/layers/Blob.sol diff --git a/packages/contracts/src/LucidOrigins.sol b/packages/contracts/src/LucidOrigins.sol index d9c441c..378af5c 100644 --- a/packages/contracts/src/LucidOrigins.sol +++ b/packages/contracts/src/LucidOrigins.sol @@ -38,13 +38,16 @@ contract LucidOrigins is Owned, ERC721A, Background, Face, Body, Head, Blush { string memory linesColor = isColorDark(r, g, b) ? "#FFF" : "#000"; string memory face = face( - normalizeToRange(dna[Constants.EYE_RADIUS_INDEX], 4, 7), + normalizeToRange(dna[Constants.EYE_RADIUS_INDEX], 7, 7), normalizeToRange(dna[Constants.EYE_BROW_LENGHT_INDEX], 2, 4), - normalizeToRange(dna[Constants.EYE_SEPARATION_INDEX], 20, 30), + normalizeToRange(dna[Constants.EYE_SEPARATION_INDEX], 20, 25), normalizeToRange(dna[Constants.EYE_BROW_ROTATION_INDEX], 0, 20), normalizeToRange(dna[Constants.MOUNTH_ROTATION], 0, 6), normalizeToRange(dna[Constants.EYE_BROW_SIZE_INDEX], 1, 5), - linesColor + linesColor, + r2, + g2, + b2 ); (string memory colorDefs, string memory fillColor) = @@ -59,9 +62,18 @@ contract LucidOrigins is Owned, ERC721A, Background, Face, Body, Head, Blush { fillColor ); + string memory body = body( + normalizeToRange(dna[Constants.HEAD_SIZE_INDEX], 95, 125), + normalizeToRange(dna[Constants.HEAD_SIZE_INDEX], 1, 3), + normalizeToRange(dna[Constants.HEAD_MIN_GROWTH_INDEX], 9, 12), + normalizeToRange(dna[Constants.HEAD_EDGES_NUM_INDEX], 10, 55), + colorDefs, + fillColor + ); + string memory footer = ""; - string memory svgContent = string(abi.encodePacked(body(colorDefs, fillColor), head, face, blush())); + string memory svgContent = string(abi.encodePacked(body, head, face, blush())); uint256 rotation = normalizeToRange(dna[Constants.HEAD_SIZE_INDEX], 0, 3); string memory svg = string(abi.encodePacked(header, background, rotationWrapper(rotation, svgContent), footer)); diff --git a/packages/contracts/src/layers/Background.sol b/packages/contracts/src/layers/Background.sol index 65da4fb..5d6acd6 100644 --- a/packages/contracts/src/layers/Background.sol +++ b/packages/contracts/src/layers/Background.sol @@ -29,6 +29,7 @@ contract Background { function background(uint256 dnaBgLayer) internal view returns (string memory) { return - string(abi.encodePacked('')); + + string(abi.encodePacked('','')); } } diff --git a/packages/contracts/src/layers/Blob.sol b/packages/contracts/src/layers/Blob.sol new file mode 100644 index 0000000..f5dad90 --- /dev/null +++ b/packages/contracts/src/layers/Blob.sol @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +// import { console2 } from "forge-std/console2.sol"; +import { LibString } from "solmate/utils/LibString.sol"; +import { Trigonometry } from "solidity-trigonometry/Trigonometry.sol"; + +contract Blob { + struct Point { + int256 x; + int256 y; + } + + using LibString for int256; + using Trigonometry for uint256; + + function createPoints( + uint256 size, + uint256 x, + uint256 y, + uint256 minGrowth, + uint256 edgesNum + ) + internal + view + returns (Point[] memory) + { + Point[] memory points = new Point[](edgesNum); + + uint256 outerRad = size / 2; + uint256 innerRad = minGrowth * (outerRad / 10); + uint256 deg = 360 / edgesNum; + + for (uint256 i = 0; i < edgesNum; i++) { + uint256 degree = i * deg; + uint256 radius = randPoint(i, innerRad, outerRad); + Point memory point = calculatePoint(x, y, radius, degree); + points[i] = point; + } + + return points; + } + + function calculatePoint( + uint256 _x, + uint256 _y, + uint256 radius, + uint256 degree + ) + internal + pure + returns (Point memory) + { + uint256 scaledDegree = degree * 1e18; + uint256 scaledPI = Trigonometry.PI; + + int256 cosValue = uint256(scaledDegree * scaledPI / 180 / 1e18).cos(); + int256 sinValue = (scaledDegree * scaledPI / 180 / 1e18).sin(); + + int256 x = int256(_x) + int256(radius) * cosValue / 1e18; + int256 y = int256(_y) + int256(radius) * sinValue / 1e18; + + return Point(x, y); + } + + function randPoint(uint256 i, uint256 minv, uint256 maxv) internal view returns (uint256) { + uint256 random = uint256(keccak256(abi.encodePacked(block.number, block.timestamp, i, minv, maxv))) % maxv; + return (random >= minv) ? random : minv + (random % (maxv - minv)); + } + + function createSvgPath(Point[] memory points) internal pure returns (string memory) { + string memory svgPath; + Point memory mid = Point({ x: (points[0].x + points[1].x) / 2, y: (points[0].y + points[1].y) / 2 }); + + svgPath = string(abi.encodePacked("M", mid.x.toString(), ",", mid.y.toString())); + + for (uint256 i = 0; i < points.length; i++) { + Point memory p1 = points[(i + 1) % points.length]; + Point memory p2 = points[(i + 2) % points.length]; + Point memory midPoint = Point({ x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 }); + + svgPath = string( + abi.encodePacked( + svgPath, + "Q", + p1.x.toString(), + ",", + p1.y.toString(), + ",", + midPoint.x.toString(), + ",", + midPoint.y.toString() + ) + ); + } + + return string(abi.encodePacked(svgPath, "Z")); + } + + function build( + string memory id, + string memory colorDefs, + string memory fillColor, + string memory h1, + string memory h2 + ) + internal + pure + returns (string memory) + { + return string( + abi.encodePacked( + colorDefs, + '', + '', + '', + "" + ) + ); + } +} diff --git a/packages/contracts/src/layers/Body.sol b/packages/contracts/src/layers/Body.sol index b51a22e..e61b967 100644 --- a/packages/contracts/src/layers/Body.sol +++ b/packages/contracts/src/layers/Body.sol @@ -1,34 +1,33 @@ // SPDX-License-Identifier: GNU GPLv3 pragma solidity 0.8.21; -contract Body { - function body(string memory colorDefs, string memory fillColor) internal pure returns (string memory) { +import { Blob } from "./Blob.sol"; + +contract Body is Blob { + function body( + uint256 size, + uint256 animation, + uint256 minGrowth, + uint256 edgesNum, + string memory colorDefs, + string memory fillColor + ) + internal + view + returns (string memory) + { + uint256 x = 50; + uint256 y = 0; + string memory b1 = createSvgPath(createPoints(size, x, y, minGrowth, edgesNum)); + string memory b2 = createSvgPath(createPoints(size + animation, x, y, minGrowth, edgesNum)); + + uint256 resize = size - 30; + string memory bi1 = createSvgPath(createPoints(resize, x, y, minGrowth - 2, edgesNum / 2)); + string memory bi2 = createSvgPath(createPoints(resize + animation, x, y, minGrowth - 2, edgesNum / 2)); + return string( abi.encodePacked( - colorDefs, - '"' + build("body", colorDefs, fillColor, b1, b2), build("inner-body", colorDefs, fillColor, bi1, bi2) ) ); } diff --git a/packages/contracts/src/layers/Face.sol b/packages/contracts/src/layers/Face.sol index 095f007..3ce0165 100644 --- a/packages/contracts/src/layers/Face.sol +++ b/packages/contracts/src/layers/Face.sol @@ -14,22 +14,75 @@ contract Face { uint256 eyebrowRotation, uint256 mouthRotation, uint256 eyebrowSize, - string memory linesColor + string memory linesColor, + uint256 r, + uint256 g, + uint256 b ) internal pure returns (string memory) { - string memory eyes = getEyes(eyeRadius, eyeSeparation, eyebrowRotation, linesColor); - string memory eyebrows = getEyebrows(eyebrowLength, eyebrowRotation, eyebrowSize, mouthRotation, linesColor); - string memory mouth = getMouth(eyeSeparation, eyebrowRotation, eyebrowSize, mouthRotation, linesColor); + string memory eyes = getEyes(eyeRadius, eyeSeparation, mouthRotation, eyebrowRotation, r, g, b); + //string memory eyebrows = getEyebrows(eyebrowLength, eyebrowRotation, eyebrowSize, mouthRotation, linesColor); + //string memory mouth = getMouth(eyeSeparation, eyebrowRotation, eyebrowSize, mouthRotation, linesColor); return string( - abi.encodePacked('', eyes, eyebrows, mouth, "") + // abi.encodePacked('', eyes, eyebrows, mouth, "") + abi.encodePacked('', eyes, /*eyebrows, mouth,*/ "") ); } function getEyes( + uint256 eyeRadius, + uint256 eyeSeparation, + uint256 pupilRadius, + uint256 pupilColor, + uint256 r, + uint256 g, + uint256 b + ) + internal + pure + returns (string memory) + { + // string memory pupilAlternativeColor = string(abi.encodePacked("rgb(", r.toString(), ",", g.toString(), ",", + // b.toString(), ")")); + return string( + abi.encodePacked( + '', + '', + '' '', + '' "" + ) + ); + } + + function _getEyes( uint256 eyeRadius, uint256 eyeSeparation, uint256 eyebrowRotation, @@ -41,7 +94,7 @@ contract Face { { return string( abi.encodePacked( - '', + '', '= minv) ? random : minv + (random % (maxv - minv)); - } - - function createSvgPath(Point[] memory points) internal pure returns (string memory) { - string memory svgPath; - Point memory mid = Point({ x: (points[0].x + points[1].x) / 2, y: (points[0].y + points[1].y) / 2 }); - - svgPath = string(abi.encodePacked("M", mid.x.toString(), ",", mid.y.toString())); - - for (uint256 i = 0; i < points.length; i++) { - Point memory p1 = points[(i + 1) % points.length]; - Point memory p2 = points[(i + 2) % points.length]; - Point memory midPoint = Point({ x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 }); - - svgPath = string( - abi.encodePacked( - svgPath, - "Q", - p1.x.toString(), - ",", - p1.y.toString(), - ",", - midPoint.x.toString(), - ",", - midPoint.y.toString() - ) - ); - } + uint256 y = 0; - return string(abi.encodePacked(svgPath, "Z")); - } - - function buildHead( - string memory colorDefs, - string memory fillColor, - string memory h1, - string memory h2 - ) - private - pure - returns (string memory) - { - return string( - abi.encodePacked( - colorDefs, - '', - '', - '', - "" - ) - ); + Point[] memory points = createPoints(size, x, y, minGrowth, edgesNum); + string memory h1 = createSvgPath(points); + string memory h2 = createSvgPath(createPoints(size + animation, x, y, minGrowth, edgesNum)); + return build("head", colorDefs, fillColor, h1, h2); } }