├── Star-Love ├── screenshot.png ├── img │ ├── heartbeat.png │ ├── ok.svg │ └── todo.svg ├── justpage.php ├── base │ ├── nav.php │ ├── footer.php │ └── head.php ├── loveListPage.php ├── post.php ├── index.php ├── core │ ├── App.php │ └── shortcodes.php ├── functions.php ├── js │ ├── star.js │ └── heart │ │ ├── script.js │ │ ├── MeshSurfaceSampler.js │ │ ├── simplex-noise.js │ │ ├── TrackballControls.js │ │ └── OBJLoader.js ├── commentPage.php ├── Lens.php ├── Multiverse.php ├── css │ ├── style.css │ └── h.css └── homepage.php └── README.md /Star-Love/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crowya/Star-Love/HEAD/Star-Love/screenshot.png -------------------------------------------------------------------------------- /Star-Love/img/heartbeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crowya/Star-Love/HEAD/Star-Love/img/heartbeat.png -------------------------------------------------------------------------------- /Star-Love/justpage.php: -------------------------------------------------------------------------------- 1 | need('post.php'); 9 | ?> -------------------------------------------------------------------------------- /Star-Love/base/nav.php: -------------------------------------------------------------------------------- 1 |
2 | 7 |
-------------------------------------------------------------------------------- /Star-Love/loveListPage.php: -------------------------------------------------------------------------------- 1 | need('base/head.php'); 10 | $this->need('base/nav.php');?> 11 |
12 |
小目标
梦想还是要有的,万一实现了呢
13 | content) ?> 14 |
15 | need('base/footer.php'); ?> 16 | -------------------------------------------------------------------------------- /Star-Love/post.php: -------------------------------------------------------------------------------- 1 | need('base/head.php'); 4 | $this->need('base/nav.php'); 5 | ?> 6 | 7 |
8 |
9 |
title() ?>
10 |
11 | content(); ?> 12 |
13 |
14 |
15 | 16 | need('base/footer.php'); ?> -------------------------------------------------------------------------------- /Star-Love/base/footer.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Star-Love/img/ok.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Star-Love/img/todo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Star-Love/base/head.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <?php $this->archiveTitle(array( 7 | 'category' => _t('分类 %s 下的文章'), 8 | 'search' => _t('包含关键字 %s 的文章'), 9 | 'tag' => _t('标签 %s 下的文章'), 10 | 'author' => _t('%s 发布的文章') 11 | ), '', ' - '); ?><?php $this->options->title(); ?> 12 | header(); ?> 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /Star-Love/index.php: -------------------------------------------------------------------------------- 1 | need('base/head.php'); 12 | $this->need('base/nav.php'); 13 | ?> 14 | 15 |
16 |
17 |
回忆录
相信以后会有更多美好的事情发生
18 | have()) : ?> 19 | next()) : ?> 20 |
21 |

22 | 23 |
24 | 25 | 26 |
27 |

28 |
29 | 30 | pageNav('« 前一页', '后一页 »'); ?> 31 |
32 |
33 | 34 | need('base/footer.php'); ?> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Star-Love 2 | 繁星之恋主题 — A Romantic Theme for Typecho 3 | 4 | 由于可能会鸽很久,先把这个临时版放出来和大家分享一下。 5 | 6 | 演示站点: [BN & SY's Love](https://love.crowya.com/) 7 | 8 | ![image](https://github.com/crowya/Star-Love/assets/61354956/cf386b22-0df5-47f3-9d82-ac8d723a3ea9) 9 | 10 | ![cut_20230809010128](https://github.com/crowya/Star-Love/assets/61354956/69be4fe2-f73a-49a8-89ac-f11a15a6d924) 11 | 12 | 关于主题开发进展,目前已经初步整合了各方代码,增添了后台设置项。 13 | 一些小改进: 14 | 1. 修复祝福墙点不进去问题 15 | 2. 美化板块入口图标 16 | 3. 新增相册模板页以及关于和友链板块 17 | 18 | 仍然存在的问题以及 todo 事项: 19 | 1. 子页面太丑 20 | 2. pjax 框架被我吃了,亟待恢复 21 | 3. 背景音乐以及暂停播放按钮(计划放在右上角) 22 | 23 | 还有一些杂七杂八的问题比如相册是否应对访客可见、导航栏太丑以及连个搜索功能都没有… 24 | 25 | 如果给作者一点金钱上的鼓励,极有可能加速这一进程… 26 | 27 | ![cut_20230809012222](https://github.com/crowya/Star-Love/assets/61354956/3ba4dbdd-d2ab-456d-94a2-bfe51511d6dc) 28 | 29 | ## 安装与使用 30 | 1. 点亮右上角小星星。 31 | 2. 下载最新版[Release](https://github.com/crowya/Star-Love/releases)。 32 | 3. 上传并解压到网站目录`/www/wwwroot/typecho/usr/themes/`文件夹下。 33 | 4. 在后台切换主题并在“设置外观”页面根据提示完成设置。 34 | 5. 其他需要注意的设置项: 35 | - 请在Typecho自带的设置里将首页设置为:直接调用`homepage.php`模板文件。 36 | - 请在Typecho自带的设置里更改站点描述。 37 | - 小目标页面的用法:在页面正文填入以下内容即可。 38 | ``` 39 | [loveList] 40 | [item status="0" img=""]一起看日出[/item] 41 | [item status="1" img=""]一起看日落[/item] 42 | [/loveList] 43 | ``` 44 | 0表示未完成,1表示已完成。图片链接可以为空。 45 | - 照片墙页面的用法:在页面正文填入以下内容即可。 46 | ``` 47 | picture1,2020年01月01日拍摄,https://ww2.sinaimg.cn/large/006uAlqKgy1fzlbjrxju2j31400u04qz.jpg 48 | picture2,2020年01月02日拍摄,https://ww2.sinaimg.cn/large/006uAlqKgy1fzlbjrxju2j31400u04qz.jpg 49 | picture3,2020年01月03日拍摄,https://ww2.sinaimg.cn/large/006uAlqKgy1fzlbjrxju2j31400u04qz.jpg 50 | ``` 51 | 格式为:`标题,简介,图片链接`。其中标题和简介可以为空,即`,,图片链接`。自定义字段的用法请参考致谢4。 52 | 6. 请保留页脚的“Theme Star Love”,祝99。 53 | 54 | ## 致谢 55 | 本主题由以下素材缝合而来。 56 | 1. https://flag.moe/ 57 | 2. https://sc.chinaz.com/jiaoben/210829301800.htm 58 | 3. https://blog.zwying.com/archives/59.html 59 | 4. https://github.com/zzd/photo-page-for-typecho 60 | -------------------------------------------------------------------------------- /Star-Love/core/App.php: -------------------------------------------------------------------------------- 1 | '; 47 | foreach ($matches[3] as $key => $value){ 48 | $out .= '
'; 49 | $out .= '

'; 50 | $out .= '

'; 57 | $out .= '
'; 58 | $out .= '
'; 59 | $out .= '
'; 60 | $out .= '
'; 61 | } 62 | $out .= ''; 63 | return $out; 64 | } 65 | } 66 | add_shortcode('loveList', 'loveListAcc'); -------------------------------------------------------------------------------- /Star-Love/functions.php: -------------------------------------------------------------------------------- 1 | commentsAntiSpam = false; //关闭反垃圾 10 | Helper::options()->commentsCheckReferer = false; //关闭检查评论来源URL与文章链接是否一致判断(否则会无法评论) 11 | Helper::options()->commentsMaxNestingLevels = '999'; //最大嵌套层数 12 | Helper::options()->commentsPageDisplay = 'first'; //强制评论第一页 13 | Helper::options()->commentsOrder = 'DESC'; //将最新的评论展示在前 14 | Helper::options()->commentsHTMLTagAllowed = ' '; 15 | Helper::options()->commentsMarkdown = true; 16 | } 17 | /** 18 | * 主题后台设置 19 | */ 20 | function themeConfig($form) 21 | { 22 | $knowTime = new Typecho_Widget_Helper_Form_Element_Text('knowTime', NULL, NULL, _t('相识时间'), _t('格式为:YYYY/MM/DD HH:mm:ss')); 23 | $loveTime = new Typecho_Widget_Helper_Form_Element_Text('loveTime', NULL, NULL, _t('相恋时间'), _t('格式为:YYYY/MM/DD HH:mm:ss')); 24 | $meetTime = new Typecho_Widget_Helper_Form_Element_Text('meetTime', NULL, NULL, _t('上一次见面时间'), _t('格式为:YYYY/MM/DD HH:mm:ss')); 25 | 26 | $form->addInput($knowTime); 27 | $form->addInput($loveTime); 28 | $form->addInput($meetTime); 29 | 30 | $slogan_list = new Typecho_Widget_Helper_Form_Element_Textarea('slogan_list', NULL, NULL, _t('标题轮换内容'), _t('文本内容用英文双引号包裹,换行用<br>表示,以英文逗号分隔。例如:
31 | "<br>我爱你!",
32 | "我的爱意流过二极管,<br>永不逆转!",
33 | "我的思念流过三极管,<br>被放大无数倍∞",
34 | ')); 35 | $form->addInput($slogan_list); 36 | 37 | $tags_list = new Typecho_Widget_Helper_Form_Element_Textarea('tags_list', NULL, NULL, _t('抽签轮换内容'), _t('文本内容用英文双引号包裹,以英文逗号分隔。例如:"标签1", "标签2", "标签3",')); 38 | $form->addInput($tags_list); 39 | 40 | $page_url_1 = new Text('page_url_1', NULL, NULL, _t('小目标链接'), _t('新建一个页面,选择对应模板,然后将链接填到这里')); 41 | $page_url_2 = new Text('page_url_2', NULL, NULL, _t('回忆录链接'), _t('无需新建页面,一般为:站点链接/blog/,与站点设置有关')); 42 | $page_url_3 = new Text('page_url_3', NULL, NULL, _t('祝福墙链接'), _t('新建一个页面,选择对应模板,然后将链接填到这里')); 43 | $page_url_4 = new Text('page_url_4', NULL, NULL, _t('照片墙链接'), _t('新建一个页面,选择对应模板,然后将链接填到这里')); 44 | $page_url_5 = new Text('page_url_5', NULL, NULL, _t('我们俩链接'), _t('新建一个页面,选择对应模板,然后将链接填到这里')); 45 | $page_url_6 = new Text('page_url_6', NULL, NULL, _t('朋友们链接'), _t('新建一个页面,选择对应模板,然后将链接填到这里')); 46 | 47 | $form->addInput($page_url_1); 48 | $form->addInput($page_url_2); 49 | $form->addInput($page_url_3); 50 | $form->addInput($page_url_4); 51 | $form->addInput($page_url_5); 52 | $form->addInput($page_url_6); 53 | 54 | $beianhao = new Text('beianhao', NULL, NULL, _t('备案号'), _t('可以不填')); 55 | $form->addInput($beianhao); 56 | } 57 | -------------------------------------------------------------------------------- /Star-Love/js/star.js: -------------------------------------------------------------------------------- 1 | // 如果你看到这段文字了,你懂我什么意思吧。 2 | window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)}}(); 3 | 4 | $(function(){ 5 | 6 | var cf = document.createElement("canvas"); 7 | var c = document.getElementById('startrack'); 8 | 9 | let cw, ch; 10 | 11 | c.width = cf.width = cw = c.offsetWidth; 12 | c.height = cf.height = ch = c.offsetHeight; 13 | var longside = Math.max(cw,ch); 14 | cf.width = longside * 2.6 15 | cf.height = longside * 2.6 16 | 17 | var ctx = c.getContext('2d'); 18 | var cftx = cf.getContext('2d'); 19 | 20 | 21 | // ctx.beginPath(); 22 | // ctx.rect(0, 0, cw, ch); 23 | // ctx.fillStyle='rgba(0,255,0,.1)'; 24 | // ctx.closePath(); 25 | // ctx.fill(); 26 | 27 | // cftx.beginPath(); 28 | // cftx.rect(0, 0, cf.width, cf.height); 29 | // cftx.fillStyle='rgba(255,255,255,.1)'; 30 | // cftx.strokeStyle='rgba(255,255,255,.1)'; 31 | // cftx.closePath(); 32 | // cftx.stroke(); 33 | 34 | 35 | var centerX = cw; 36 | var centerY = 0//-ch; 37 | var stars = []; 38 | var drawTimes = 0; 39 | 40 | ctx.fillStyle = "rgba(21,21,21,1)"; 41 | ctx.fillRect(0,0,cw,ch); 42 | 43 | ctx.lineCap = 'round'; 44 | 45 | function rand(Min,Max){ 46 | var Range = Max - Min; 47 | var Rand = Math.random(); 48 | var num = Min + Math.round(Rand * Range); 49 | return num; 50 | } 51 | 52 | function createStar(){ 53 | stars.push({ 54 | x: rand(-cf.width,cf.width), 55 | y: rand(-cf.height, cf.height), 56 | size: 1.2, 57 | color: randomColor(), 58 | }) 59 | } 60 | 61 | function randomColor(){ 62 | var r = rand(120,255); 63 | var g = rand(120,255); 64 | var b = rand(120,255); 65 | var a = rand(30,100)/100; 66 | //var a = 1; 67 | return "rgba("+r+","+g+","+b+","+a+")"; 68 | } 69 | 70 | function drawStar(){ 71 | var count = stars.length; 72 | while(count--){ 73 | var cs = stars[count]; 74 | cftx.beginPath(); 75 | cftx.arc(cs.x, cs.y, cs.size, 0,Math.PI*2,true); 76 | cftx.fillStyle=cs.color; 77 | cftx.closePath(); 78 | cftx.fill(); 79 | } 80 | } 81 | 82 | function drawfromCache(){ 83 | ctx.drawImage(cf, -cf.width/2,-cf.height/2); 84 | } 85 | 86 | function loop(){ 87 | 88 | drawfromCache() 89 | 90 | drawTimes++; 91 | 92 | if(drawTimes > 400 ){ 93 | if(drawTimes % 8==0){ 94 | ctx.fillStyle = 'rgba(0,0,0,.04)'; 95 | ctx.fillRect(-(longside*3),-(longside*3),longside*6,longside*6); 96 | } 97 | } 98 | rotateCanvas(0.025); 99 | 100 | } 101 | 102 | function rotateCanvas(deg){ 103 | ctx.rotate(deg*Math.PI/180); 104 | } 105 | 106 | var count = 20000; 107 | while(count--){ 108 | createStar(); 109 | } 110 | drawStar(); 111 | 112 | var x = centerX; 113 | var y = centerY; 114 | ctx.translate(x,y); 115 | 116 | function fireAnimate() { 117 | requestAnimFrame( fireAnimate ); 118 | loop(); 119 | } 120 | 121 | fireAnimate(); 122 | 123 | function changeStar(){ 124 | loop = function(){ 125 | drawfromCache() 126 | 127 | drawTimes++; 128 | 129 | if(drawTimes > 150 ){ 130 | if(drawTimes % 8==0){ 131 | ctx.fillStyle = 'rgba(0,0,0,.04)'; 132 | ctx.fillRect(-(longside*3),-(longside*3),longside*6,longside*6); 133 | } 134 | } 135 | rotateCanvas(random(1,100)); 136 | } 137 | } 138 | 139 | }) -------------------------------------------------------------------------------- /Star-Love/js/heart/script.js: -------------------------------------------------------------------------------- 1 | const scene = new THREE.Scene(); 2 | const camera = new THREE.PerspectiveCamera( 3 | 75, 4 | 1, 5 | 0.1, 6 | 1000 7 | ); 8 | 9 | const renderer = new THREE.WebGLRenderer({ 10 | antialias: true, 11 | alpha: true 12 | }); 13 | renderer.setClearColor(0x000000, 0); 14 | const shorterDimension = Math.min(window.innerWidth, window.innerHeight); 15 | renderer.setSize(shorterDimension, shorterDimension); 16 | document.body.prepend(renderer.domElement); 17 | document.body.firstElementChild.setAttribute("id","heart"); 18 | if (window.innerWidth > 768){ 19 | camera.fov =90; 20 | camera.updateProjectionMatrix(); 21 | } 22 | 23 | camera.position.z = 1; 24 | 25 | const controls = new THREE.TrackballControls(camera, renderer.domElement); 26 | controls.noPan = true; 27 | controls.maxDistance = 3; 28 | controls.minDistance = 0.7; 29 | 30 | const group = new THREE.Group(); 31 | scene.add(group); 32 | 33 | let heart = null; 34 | let sampler = null; 35 | let originHeart = null; 36 | new THREE.OBJLoader().load('https://assets.codepen.io/127738/heart_2.obj',obj => { 37 | heart = obj.children[0]; 38 | heart.geometry.rotateX(-Math.PI * 0.5); 39 | heart.geometry.scale(0.04, 0.04, 0.04); 40 | heart.geometry.translate(0, -0.4, 0); 41 | group.add(heart); 42 | 43 | heart.material = new THREE.MeshBasicMaterial({ 44 | color: 0x000000 45 | }); 46 | originHeart = Array.from(heart.geometry.attributes.position.array); 47 | sampler = new THREE.MeshSurfaceSampler(heart).build(); 48 | init(); 49 | renderer.setAnimationLoop(render); 50 | }); 51 | 52 | let positions = []; 53 | const geometry = new THREE.BufferGeometry(); 54 | const material = new THREE.LineBasicMaterial({ 55 | color: 0xed93ad 56 | }); 57 | const lines = new THREE.LineSegments(geometry, material); 58 | group.add(lines); 59 | 60 | const simplex = new SimplexNoise(); 61 | const pos = new THREE.Vector3(); 62 | class Grass { 63 | constructor () { 64 | sampler.sample(pos); 65 | this.pos = pos.clone(); 66 | this.scale = Math.random() * 0.01 + 0.001; 67 | this.one = null; 68 | this.two = null; 69 | } 70 | update (a) { 71 | const noise = simplex.noise4D(this.pos.x*1.5, this.pos.y*1.5, this.pos.z*1.5, a * 0.0005) + 1; 72 | this.one = this.pos.clone().multiplyScalar(1.01 + (noise * 0.15 * beat.a)); 73 | this.two = this.one.clone().add(this.one.clone().setLength(this.scale)); 74 | } 75 | } 76 | 77 | let spikes = []; 78 | function init (a) { 79 | positions = []; 80 | for (let i = 0; i < 20000; i++) { 81 | const g = new Grass(); 82 | spikes.push(g); 83 | } 84 | } 85 | 86 | const beat = { a: 0 }; 87 | gsap.timeline({ 88 | repeat: -1, 89 | repeatDelay: 0.3 90 | }).to(beat, { 91 | a: 1.2, 92 | duration: 0.6, 93 | ease: 'power2.in' 94 | }).to(beat, { 95 | a: 0.0, 96 | duration: 0.6, 97 | ease: 'power3.out' 98 | }); 99 | gsap.to(group.rotation, { 100 | y: Math.PI * 2, 101 | duration: 12, 102 | ease: 'none', 103 | repeat: -1 104 | }); 105 | 106 | function render(a) { 107 | positions = []; 108 | spikes.forEach(g => { 109 | g.update(a); 110 | positions.push(g.one.x, g.one.y, g.one.z); 111 | positions.push(g.two.x, g.two.y, g.two.z); 112 | }); 113 | geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3)); 114 | 115 | const vs = heart.geometry.attributes.position.array; 116 | for (let i = 0; i < vs.length; i+=3) { 117 | const v = new THREE.Vector3(originHeart[i], originHeart[i+1], originHeart[i+2]); 118 | const noise = simplex.noise4D(originHeart[i]*1.5, originHeart[i+1]*1.5, originHeart[i+2]*1.5, a * 0.0005) + 1; 119 | v.multiplyScalar(1 + (noise * 0.15 * beat.a)); 120 | vs[i] = v.x; 121 | vs[i+1] = v.y; 122 | vs[i+2] = v.z; 123 | } 124 | heart.geometry.attributes.position.needsUpdate = true; 125 | 126 | controls.update(); 127 | renderer.render(scene, camera); 128 | } 129 | 130 | // window.addEventListener("resize", onWindowResize, false); 131 | // function onWindowResize() { 132 | // camera.aspect = window.innerWidth / window.innerHeight; 133 | // camera.updateProjectionMatrix(); 134 | // renderer.setSize(window.innerWidth, window.innerHeight); 135 | // } -------------------------------------------------------------------------------- /Star-Love/commentPage.php: -------------------------------------------------------------------------------- 1 | need('base/head.php'); 9 | $this->need('base/nav.php'); 10 | $this->comments()->to($comments); 11 | ?> 12 | authorId) { 16 | if ($comments->authorId == $comments->ownerId) { 17 | $commentClass .= ' comment-by-author'; 18 | } else { 19 | $commentClass .= ' comment-by-user'; 20 | } 21 | } 22 | $commentLevelClass = $comments->levels > 0 ? ' comment-child' : ' comment-parent'; 23 | ?> 24 |
33 | 34 |
35 |
36 |
37 |
40 |
41 |
42 | author(); ?> 43 | date('Y-m-d H:i'); ?> 44 |
45 |
46 | content(); ?> 47 |
48 |
49 |
50 |
51 |
52 | 53 | allow('comment')) : ?> 54 |
55 |
56 | have()) : ?> 57 |
commentsNum(_t('暂无祝福'), _t('仅有一条祝福'), _t('累计已经收到 %d 条祝福')); ?>
58 | listComments(); ?> 59 | pageNav('« 前一页', '后一页 »'); ?> 60 | 61 |
63 | user->hasLogin()) : ?> 64 |

user->screenName(); ?>. 66 | » 67 |

68 | 69 |
70 |
71 | 74 |
75 |
76 | options->commentsRequireMail) : ?> required /> 79 |
80 |
81 | options->commentsRequireURL) : ?> required /> 84 |
85 |
86 | 87 |
88 | 91 |
92 |
93 | 94 |
95 |
96 |
97 |
98 | 99 |

100 | 101 | 102 | need('base/footer.php'); ?> -------------------------------------------------------------------------------- /Star-Love/Lens.php: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 15 | 21 | 22 | 23 | 24 | 39 | 40 | 41 | 42 | 43 | 44 | <?php $this->title() ?> - <?php $this->options->title() ?> 45 | 46 | 47 | 48 | 49 | 51 | 52 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 89 | 90 | 91 |
92 |
93 | 94 | 101 |
102 | 106 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /Star-Love/js/heart/MeshSurfaceSampler.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 3 | /** 4 | * Utility class for sampling weighted random points on the surface of a mesh. 5 | * 6 | * Building the sampler is a one-time O(n) operation. Once built, any number of 7 | * random samples may be selected in O(logn) time. Memory usage is O(n). 8 | * 9 | * References: 10 | * - http://www.joesfer.com/?p=84 11 | * - https://stackoverflow.com/a/4322940/1314762 12 | */ 13 | 14 | const _face = new THREE.Triangle(); 15 | 16 | const _color = new THREE.Vector3(); 17 | 18 | class MeshSurfaceSampler { 19 | 20 | constructor( mesh ) { 21 | 22 | let geometry = mesh.geometry; 23 | 24 | if ( ! geometry.isBufferGeometry || geometry.attributes.position.itemSize !== 3 ) { 25 | 26 | throw new Error( 'THREE.MeshSurfaceSampler: Requires BufferGeometry triangle mesh.' ); 27 | 28 | } 29 | 30 | if ( geometry.index ) { 31 | 32 | console.warn( 'THREE.MeshSurfaceSampler: Converting geometry to non-indexed BufferGeometry.' ); 33 | geometry = geometry.toNonIndexed(); 34 | 35 | } 36 | 37 | this.geometry = geometry; 38 | this.randomFunction = Math.random; 39 | this.positionAttribute = this.geometry.getAttribute( 'position' ); 40 | this.colorAttribute = this.geometry.getAttribute( 'color' ); 41 | this.weightAttribute = null; 42 | this.distribution = null; 43 | 44 | } 45 | 46 | setWeightAttribute( name ) { 47 | 48 | this.weightAttribute = name ? this.geometry.getAttribute( name ) : null; 49 | return this; 50 | 51 | } 52 | 53 | build() { 54 | 55 | const positionAttribute = this.positionAttribute; 56 | const weightAttribute = this.weightAttribute; 57 | const faceWeights = new Float32Array( positionAttribute.count / 3 ); // Accumulate weights for each mesh face. 58 | 59 | for ( let i = 0; i < positionAttribute.count; i += 3 ) { 60 | 61 | let faceWeight = 1; 62 | 63 | if ( weightAttribute ) { 64 | 65 | faceWeight = weightAttribute.getX( i ) + weightAttribute.getX( i + 1 ) + weightAttribute.getX( i + 2 ); 66 | 67 | } 68 | 69 | _face.a.fromBufferAttribute( positionAttribute, i ); 70 | 71 | _face.b.fromBufferAttribute( positionAttribute, i + 1 ); 72 | 73 | _face.c.fromBufferAttribute( positionAttribute, i + 2 ); 74 | 75 | faceWeight *= _face.getArea(); 76 | faceWeights[ i / 3 ] = faceWeight; 77 | 78 | } // Store cumulative total face weights in an array, where weight index 79 | // corresponds to face index. 80 | 81 | 82 | this.distribution = new Float32Array( positionAttribute.count / 3 ); 83 | let cumulativeTotal = 0; 84 | 85 | for ( let i = 0; i < faceWeights.length; i ++ ) { 86 | 87 | cumulativeTotal += faceWeights[ i ]; 88 | this.distribution[ i ] = cumulativeTotal; 89 | 90 | } 91 | 92 | return this; 93 | 94 | } 95 | 96 | setRandomGenerator( randomFunction ) { 97 | 98 | this.randomFunction = randomFunction; 99 | return this; 100 | 101 | } 102 | 103 | sample( targetPosition, targetNormal, targetColor ) { 104 | 105 | const cumulativeTotal = this.distribution[ this.distribution.length - 1 ]; 106 | const faceIndex = this.binarySearch( this.randomFunction() * cumulativeTotal ); 107 | return this.sampleFace( faceIndex, targetPosition, targetNormal, targetColor ); 108 | 109 | } 110 | 111 | binarySearch( x ) { 112 | 113 | const dist = this.distribution; 114 | let start = 0; 115 | let end = dist.length - 1; 116 | let index = - 1; 117 | 118 | while ( start <= end ) { 119 | 120 | const mid = Math.ceil( ( start + end ) / 2 ); 121 | 122 | if ( mid === 0 || dist[ mid - 1 ] <= x && dist[ mid ] > x ) { 123 | 124 | index = mid; 125 | break; 126 | 127 | } else if ( x < dist[ mid ] ) { 128 | 129 | end = mid - 1; 130 | 131 | } else { 132 | 133 | start = mid + 1; 134 | 135 | } 136 | 137 | } 138 | 139 | return index; 140 | 141 | } 142 | 143 | sampleFace( faceIndex, targetPosition, targetNormal, targetColor ) { 144 | 145 | let u = this.randomFunction(); 146 | let v = this.randomFunction(); 147 | 148 | if ( u + v > 1 ) { 149 | 150 | u = 1 - u; 151 | v = 1 - v; 152 | 153 | } 154 | 155 | _face.a.fromBufferAttribute( this.positionAttribute, faceIndex * 3 ); 156 | 157 | _face.b.fromBufferAttribute( this.positionAttribute, faceIndex * 3 + 1 ); 158 | 159 | _face.c.fromBufferAttribute( this.positionAttribute, faceIndex * 3 + 2 ); 160 | 161 | targetPosition.set( 0, 0, 0 ).addScaledVector( _face.a, u ).addScaledVector( _face.b, v ).addScaledVector( _face.c, 1 - ( u + v ) ); 162 | 163 | if ( targetNormal !== undefined ) { 164 | 165 | _face.getNormal( targetNormal ); 166 | 167 | } 168 | 169 | if ( targetColor !== undefined && this.colorAttribute !== undefined ) { 170 | 171 | _face.a.fromBufferAttribute( this.colorAttribute, faceIndex * 3 ); 172 | 173 | _face.b.fromBufferAttribute( this.colorAttribute, faceIndex * 3 + 1 ); 174 | 175 | _face.c.fromBufferAttribute( this.colorAttribute, faceIndex * 3 + 2 ); 176 | 177 | _color.set( 0, 0, 0 ).addScaledVector( _face.a, u ).addScaledVector( _face.b, v ).addScaledVector( _face.c, 1 - ( u + v ) ); 178 | 179 | targetColor.r = _color.x; 180 | targetColor.g = _color.y; 181 | targetColor.b = _color.z; 182 | 183 | } 184 | 185 | return this; 186 | 187 | } 188 | 189 | } 190 | 191 | THREE.MeshSurfaceSampler = MeshSurfaceSampler; 192 | 193 | } )(); 194 | -------------------------------------------------------------------------------- /Star-Love/Multiverse.php: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | 15 | 21 | 22 | 23 | 38 | 39 | 40 | 41 | 42 | 43 | <?php $this->title() ?> - <?php $this->options->title() ?> 44 | 45 | 46 | 47 | 48 | 50 | 51 | 60 | 61 | 62 | 63 | 64 |
65 | 66 | 74 | 75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |

控制台

83 |

本系统共有张图片,前端样式Multiverse由HTML5UP设计。

84 |

Console

85 |

The system has a total of pictures, style Multiverse is designed by HTML5UP.

86 |
87 |
88 |
    89 | fields->Twitter) : ?> 90 |
  • Twitter
  • 91 | 92 | fields->Facebook) : ?> 93 |
  • Facebook
  • 94 | 95 | fields->Instagram) : ?> 96 |
  • Instagram
  • 97 | 98 | fields->GitHub) : ?> 99 |
  • GitHub
  • 100 | 101 |
102 |
103 | 107 |
108 |
109 |
110 |

关于title() ?>

111 | fields->about) : ?> 112 |

fields->about; ?>

113 | 114 |

在自定义字段内添加about字段,即可编辑此内容,现有内容将自动替换。

115 | 116 |
117 |
118 |
119 |
120 |
121 | 125 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /Star-Love/css/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | font-family: Inter,'Noto Sans SC','Microsoft YaHei', sans-serif !important; 3 | } 4 | .page-navigator{ 5 | display: flex; 6 | } 7 | .page-navigator li{ 8 | margin: 0 10px; 9 | } 10 | ol,p { 11 | margin: 0; 12 | } 13 | ol{ 14 | list-style: none; 15 | padding: 0; 16 | } 17 | 18 | ::-webkit-scrollbar { 19 | width: 6px; 20 | } 21 | ::-webkit-scrollbar-corner { 22 | background: unset; 23 | } 24 | ::-webkit-scrollbar-thumb { 25 | background: hsla(0,0%,52.9%,.4); 26 | border-radius: 6px; 27 | } 28 | 29 | ::-webkit-scrollbar-track { 30 | background: hsla(0,0%,52.9%,.1); 31 | } 32 | ::-webkit-scrollbar-track { 33 | background-color: #fff; 34 | } 35 | 36 | .avatar-img { 37 | height: 120px; 38 | width: 120px; 39 | object-fit: cover; 40 | border: rgba(255, 255, 255, .4) 4px solid; 41 | } 42 | 43 | .heart { 44 | background-color: #ff5162; 45 | display: inline-block; 46 | height: 30px; 47 | position: relative; 48 | top: 0; 49 | transform: rotate(-45deg); 50 | width: 30px; 51 | } 52 | 53 | .lover:hover .heart { 54 | animation: heartbeat 1s infinite; 55 | } 56 | 57 | .heart:before, .heart:after { 58 | content: ""; 59 | background-color: #ff5162; 60 | border-radius: 50%; 61 | height: 30px; 62 | position: absolute; 63 | width: 30px; 64 | } 65 | 66 | .heart:before { 67 | top: -15px; 68 | left: 0; 69 | } 70 | 71 | .heart:after { 72 | left: 15px; 73 | top: 0; 74 | } 75 | 76 | @keyframes heartbeat { 77 | 0% { 78 | transform: scale( 1) rotate(-45deg); 79 | } 80 | 20% { 81 | transform: scale( 1.25) rotate(-45deg); 82 | } 83 | 40% { 84 | transform: scale( 1.5) rotate(-45deg); 85 | } 86 | } 87 | 88 | .lover-container { 89 | max-width: 500px !important; 90 | width: 500px; 91 | height: 50vh; 92 | } 93 | 94 | .lover-background { 95 | position: absolute; 96 | width: 100%; 97 | height: 100%; 98 | left: 0; 99 | top: 0; 100 | z-index: -1; 101 | object-fit: cover; 102 | background-position-x: center; 103 | background-position-y: center; 104 | background-size: cover; 105 | } 106 | 107 | .lover-background:before { 108 | content: ""; 109 | position: absolute; 110 | top: 0; 111 | left: 0; 112 | width: 100%; 113 | height: 100%; 114 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAKUlEQVQImU3IMREAIAgAwJfNkQCEsH8cijjpMf6vnXlQaIiJFx+omEBfmqIEZLe2jzcAAAAASUVORK5CYII=); 115 | } 116 | 117 | .main-hero-header, .main-hero-waves-area { 118 | width: 100%; 119 | position: absolute; 120 | left: 0; 121 | z-index: 0; 122 | } 123 | 124 | .main-hero-waves-area { 125 | bottom: -5px; 126 | } 127 | 128 | .waves-area .waves-svg { 129 | width: 100%; 130 | height: 5rem 131 | } 132 | 133 | .waves-area .parallax>use { 134 | -webkit-animation: move-forever 25s cubic-bezier(.55, .5, .45, .5) infinite; 135 | animation: move-forever 25s cubic-bezier(.55, .5, .45, .5) infinite 136 | } 137 | 138 | .waves-area .parallax>use:first-child { 139 | -webkit-animation-delay: -2s; 140 | animation-delay: -2s; 141 | -webkit-animation-duration: 7s; 142 | animation-duration: 7s; 143 | fill: hsla(0, 0%, 100%, .7) 144 | } 145 | 146 | .waves-area .parallax>use:nth-child(2) { 147 | -webkit-animation-delay: -3s; 148 | animation-delay: -3s; 149 | -webkit-animation-duration: 10s; 150 | animation-duration: 10s; 151 | fill: hsla(0, 0%, 100%, .5) 152 | } 153 | 154 | .waves-area .parallax>use:nth-child(3) { 155 | -webkit-animation-delay: -4s; 156 | animation-delay: -4s; 157 | -webkit-animation-duration: 13s; 158 | animation-duration: 13s; 159 | fill: hsla(0, 0%, 100%, .3) 160 | } 161 | 162 | .waves-area .parallax>use:nth-child(4) { 163 | -webkit-animation-delay: -5s; 164 | animation-delay: -5s; 165 | -webkit-animation-duration: 20s; 166 | animation-duration: 20s; 167 | fill: #fff 168 | } 169 | 170 | @-webkit-keyframes move-forever { 171 | 0% { 172 | -webkit-transform: translate3d(-90px, 0, 0); 173 | transform: translate3d(-90px, 0, 0) 174 | } 175 | to { 176 | -webkit-transform: translate3d(85px, 0, 0); 177 | transform: translate3d(85px, 0, 0) 178 | } 179 | } 180 | 181 | @keyframes move-forever { 182 | 0% { 183 | -webkit-transform: translate3d(-90px, 0, 0); 184 | transform: translate3d(-90px, 0, 0) 185 | } 186 | to { 187 | -webkit-transform: translate3d(85px, 0, 0); 188 | transform: translate3d(85px, 0, 0) 189 | } 190 | } 191 | 192 | .lover-card-title { 193 | background: -webkit-linear-gradient(left, red, #00f); 194 | background: -o-linear-gradient(right, red, #00f); 195 | background: -moz-linear-gradient(right, red, #00f); 196 | background: linear-gradient(to right, red, #00f); 197 | -webkit-background-clip: text; 198 | background-clip: text; 199 | -webkit-text-fill-color: transparent; 200 | } 201 | 202 | .avatar-md img{ 203 | width: 65px; 204 | height: 65px; 205 | } 206 | 207 | #loveList,.list-content{ 208 | max-width: 650px; 209 | width: 100%; 210 | } 211 | #loveList section{ 212 | display: block; 213 | padding-top: 50%; 214 | background-position: 50% 50%; 215 | background-color: #eee; 216 | background-repeat: no-repeat; 217 | -webkit-background-size: cover; 218 | background-size: cover; 219 | } 220 | 221 | .statusIcon{ 222 | width: 18px; 223 | height: 18px; 224 | margin-right: .8rem; 225 | } 226 | .indexPlate a:hover{ 227 | color: initial; 228 | text-decoration: none; 229 | } 230 | .indexPlate a{ 231 | color: inherit; 232 | } 233 | .commentlist { 234 | clear: both; 235 | } 236 | 237 | .commentlist .comment { 238 | clear: both; 239 | margin: 15px 0; 240 | margin-left: 65px; 241 | position: relative; 242 | margin-bottom: 20px; 243 | } 244 | 245 | .commentlist .comment .comment-avatar { 246 | position: absolute; 247 | left: -65px; 248 | } 249 | 250 | .commentlist .comment .comment-avatar .avatar { 251 | border-radius: 3px; 252 | -moz-border-radius: 3px; 253 | -webkit-border-radius: 3px; 254 | width: 50px; 255 | height: 50px; 256 | } 257 | 258 | .commentlist .comment .comment_author { 259 | position: relative; 260 | } 261 | 262 | .commentlist .comment .comment-text { 263 | padding: 10px 0; 264 | color: #282828; 265 | } 266 | 267 | .commentlist .comment .comment_reply { 268 | display: block; 269 | text-align: right; 270 | margin: 0; 271 | font-size: 12px; 272 | color: #757e91; 273 | } 274 | .commentlist em { 275 | padding-left: 6px; 276 | color: #A8A8A8; 277 | font-size: 12px; 278 | font-style: normal; 279 | } 280 | .commentlist p { 281 | color: #fff; 282 | font-size: 14px; 283 | line-height: 1.6; 284 | margin-bottom: 0; 285 | } 286 | .list-text{ 287 | line-height: 2.2; 288 | text-align: center; 289 | } 290 | .bigfontNum{ 291 | font-size: 3.5rem; 292 | } 293 | .indexPlate .card{ 294 | margin-bottom: 1rem; 295 | } 296 | @media screen and (max-width: 600px){ 297 | .avatar-img { 298 | height: 64px; 299 | width: 64px; 300 | object-fit: cover; 301 | border: rgba(255, 255, 255, .4) 2px solid; 302 | } 303 | .lover-container { 304 | max-width: 500px !important; 305 | width: 500px; 306 | height: 35vh; 307 | } 308 | .waves-area .waves-svg { 309 | width: 100%; 310 | height: 3rem; 311 | } 312 | .bigfontNum{ 313 | font-size: 1.5rem; 314 | } 315 | .list-content { 316 | max-width: 650px; 317 | width: 90%; 318 | } 319 | } 320 | #article img{ 321 | max-width: 100%; 322 | } 323 | 324 | /* Make clicks pass-through */ 325 | #nprogress { 326 | pointer-events: none; 327 | } 328 | 329 | #nprogress .bar { 330 | background: #29d; 331 | 332 | position: fixed; 333 | z-index: 1031; 334 | top: 0; 335 | left: 0; 336 | 337 | width: 100%; 338 | height: 2px; 339 | } 340 | 341 | /* Fancy blur effect */ 342 | #nprogress .peg { 343 | display: block; 344 | position: absolute; 345 | right: 0px; 346 | width: 100px; 347 | height: 100%; 348 | box-shadow: 0 0 10px #29d, 0 0 5px #29d; 349 | opacity: 1.0; 350 | 351 | -webkit-transform: rotate(3deg) translate(0px, -4px); 352 | -ms-transform: rotate(3deg) translate(0px, -4px); 353 | transform: rotate(3deg) translate(0px, -4px); 354 | } 355 | 356 | /* Remove these to get rid of the spinner */ 357 | #nprogress .spinner { 358 | display: block; 359 | position: fixed; 360 | z-index: 1031; 361 | top: 15px; 362 | right: 15px; 363 | } 364 | 365 | #nprogress .spinner-icon { 366 | width: 18px; 367 | height: 18px; 368 | box-sizing: border-box; 369 | 370 | border: solid 2px transparent; 371 | border-top-color: #29d; 372 | border-left-color: #29d; 373 | border-radius: 50%; 374 | 375 | -webkit-animation: nprogress-spinner 400ms linear infinite; 376 | animation: nprogress-spinner 400ms linear infinite; 377 | } 378 | 379 | .nprogress-custom-parent { 380 | overflow: hidden; 381 | position: relative; 382 | } 383 | 384 | .nprogress-custom-parent #nprogress .spinner, 385 | .nprogress-custom-parent #nprogress .bar { 386 | position: absolute; 387 | } 388 | 389 | @-webkit-keyframes nprogress-spinner { 390 | 0% { -webkit-transform: rotate(0deg); } 391 | 100% { -webkit-transform: rotate(360deg); } 392 | } 393 | @keyframes nprogress-spinner { 394 | 0% { transform: rotate(0deg); } 395 | 100% { transform: rotate(360deg); } 396 | } 397 | 398 | 399 | /******************************************************/ 400 | 401 | .mx-auto{ 402 | margin-left: auto!important; 403 | margin-right: auto!important; 404 | } 405 | 406 | .text-white{ 407 | color: #fff!important; 408 | } 409 | 410 | .navbar-brand { 411 | color: #fff; 412 | display: inline-block; 413 | padding-top: .3125rem; 414 | padding-bottom: .3125rem; 415 | margin-right: 1rem; 416 | font-size: 1.25rem; 417 | line-height: inherit; 418 | white-space: nowrap; 419 | } 420 | 421 | a { 422 | color: #007bff; 423 | text-decoration: none; 424 | } 425 | 426 | .btn:not(:disabled):not(.disabled) { 427 | cursor: pointer; 428 | } 429 | 430 | .btn-outline-danger:hover { 431 | color: #fff; 432 | background-color: #dc3545; 433 | border-color: #dc3545; 434 | } 435 | 436 | .float-right { 437 | float: right!important; 438 | } 439 | 440 | .btn-outline-danger { 441 | color: #dc3545; 442 | border-color: #dc3545 !important; 443 | } 444 | 445 | .btn { 446 | -moz-user-select: none; 447 | -ms-user-select: none; 448 | user-select: none; 449 | background-color: transparent; 450 | border: 1px solid transparent; 451 | padding: .375rem .75rem; 452 | border-radius: .25rem; 453 | transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; 454 | } 455 | 456 | .form-control { 457 | font-family: "PingFang SC"; 458 | font-size: 1rem; 459 | width: 100%; 460 | padding: .375rem .75rem; 461 | color: #ffffff; 462 | background-color: transparent; 463 | border-radius: .25rem; 464 | transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; 465 | } 466 | 467 | .form-group { 468 | margin-bottom: 1rem; 469 | } 470 | 471 | * { 472 | box-sizing: border-box; 473 | } 474 | 475 | p { 476 | margin-bottom: 1rem; 477 | } 478 | 479 | .text-center { 480 | text-align: center!important; 481 | } 482 | 483 | .h5, h5 { 484 | font-size: 1.25rem; 485 | } 486 | 487 | .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { 488 | font-weight: 500; 489 | } 490 | 491 | .comment-list{ 492 | line-height: 1; 493 | } -------------------------------------------------------------------------------- /Star-Love/css/h.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | transition-timing-function: cubic-bezier(.19, 1, .22, 1); 5 | } 6 | 7 | body { 8 | font-family: "PingFang SC"; 9 | -webkit-font-smoothing: antialiased; 10 | color: #fff; 11 | line-height: 2; 12 | padding: 0 5%; 13 | background-color: #000 !important; 14 | font-size: 17px; 15 | overflow-x: hidden; 16 | } 17 | 18 | ::selection { 19 | background: rgba(255, 255, 255, .2); 20 | } 21 | 22 | ::-webkit-scrollbar-thumb { 23 | background-color: rgba(255, 255, 255, 0.25); 24 | border: none; 25 | } 26 | ::-webkit-scrollbar-track { 27 | background-color: #282828; 28 | } 29 | ::-webkit-scrollbar { 30 | width: 8px; 31 | } 32 | 33 | .intro { 34 | position: relative; 35 | } 36 | 37 | .clear{ 38 | position: relative; 39 | z-index: 2; 40 | padding-bottom: 20px !important; 41 | } 42 | 43 | .clear:after { 44 | content: ""; 45 | display: block; 46 | height: 0; 47 | visibility: hidden; 48 | clear: both; 49 | } 50 | 51 | .chatbox>.line { 52 | display: none; 53 | } 54 | 55 | #startrack { 56 | position: absolute; 57 | top: 0; 58 | left: 0; 59 | height: 100%; 60 | width: 100%; 61 | opacity: 0.6; 62 | background-color: #000; 63 | object-fit: cover; 64 | } 65 | 66 | #heart{ 67 | position:absolute; 68 | right:0; 69 | z-index:1; 70 | } 71 | @media (max-width: 768px) { 72 | #heart { 73 | position: relative; 74 | right: 6%; 75 | } 76 | .readme { 77 | letter-spacing: .1em !important; 78 | } 79 | .hello h1 { 80 | letter-spacing: .1em !important; 81 | } 82 | } 83 | 84 | .background { 85 | position: absolute; 86 | top: 0; 87 | left: 0; 88 | width: 100vw; 89 | height: 100vh; 90 | z-index: -1; 91 | } 92 | 93 | .background .cover { 94 | position: absolute; 95 | bottom: 00%; 96 | left: 0; 97 | height: 100%; 98 | width: 100%; 99 | background: linear-gradient(to top, rgb(0 0 0) 15%, rgba(32, 32, 32, 0) 100%); 100 | } 101 | 102 | @keyframes bg { 103 | 0% { 104 | transform: rotate(0deg); 105 | border-radius: 0; 106 | } 107 | 50% { 108 | transform: rotate(180deg); 109 | border-radius: 0; 110 | } 111 | 100% { 112 | transform: rotate(360deg); 113 | border-radius: 0; 114 | } 115 | } 116 | 117 | @-webkit-keyframes bg { 118 | 0% { 119 | transform: rotate(0deg); 120 | border-radius: 0; 121 | } 122 | 50% { 123 | transform: rotate(180deg); 124 | border-radius: 0; 125 | } 126 | 100% { 127 | transform: rotate(360deg); 128 | border-radius: 0; 129 | } 130 | } 131 | 132 | @-ms-keyframes bg { 133 | 0% { 134 | transform: rotate(0deg); 135 | border-radius: 0; 136 | } 137 | 50% { 138 | transform: rotate(180deg); 139 | border-radius: 0; 140 | } 141 | 100% { 142 | transform: rotate(360deg); 143 | border-radius: 0; 144 | } 145 | } 146 | 147 | @-moz-keyframes bg { 148 | 0% { 149 | transform: rotate(0deg); 150 | border-radius: 0; 151 | } 152 | 50% { 153 | transform: rotate(180deg); 154 | border-radius: 0; 155 | } 156 | 100% { 157 | transform: rotate(360deg); 158 | border-radius: 0; 159 | } 160 | } 161 | 162 | .ch { 163 | width: 100%; 164 | padding-bottom: 60px; 165 | animation: fadedown 1s cubic-bezier(.19, 1, .22, 1); 166 | -webkit-animation: fadedown 1s cubic-bezier(.19, 1, .22, 1); 167 | -ms-animation: fadedown 1s cubic-bezier(.19, 1, .22, 1); 168 | -moz-animation: fadedown 1s cubic-bezier(.19, 1, .22, 1); 169 | } 170 | 171 | .ch h2.chtitle { 172 | padding-bottom: 30px; 173 | font-size: 26px; 174 | letter-spacing: .2em; 175 | color: rgba(255, 255, 255, .5); 176 | } 177 | 178 | .ch h2.chtitle span { 179 | color: #fff; 180 | } 181 | 182 | .ch h2.chtitle:after { 183 | content: ''; 184 | display: block; 185 | width: 10%; 186 | height: 5px; 187 | background-color: rgba(255, 255, 255, .5); 188 | margin-top: 30px; 189 | } 190 | 191 | @keyframes fadedown { 192 | 0% { 193 | opacity: 0; 194 | transform: translateY(-50px); 195 | } 196 | 100% { 197 | opacity: 1; 198 | transform: translateY(0); 199 | } 200 | } 201 | 202 | @-webkit-keyframes fadedown { 203 | 0% { 204 | opacity: 0; 205 | transform: translateY(-50px); 206 | } 207 | 100% { 208 | opacity: 1; 209 | transform: translateY(0); 210 | } 211 | } 212 | 213 | @-ms-keyframes fadedown { 214 | 0% { 215 | opacity: 0; 216 | transform: translateY(-50px); 217 | } 218 | 100% { 219 | opacity: 1; 220 | transform: translateY(0); 221 | } 222 | } 223 | 224 | @-moz-keyframes fadedown { 225 | 0% { 226 | opacity: 0; 227 | transform: translateY(-50px); 228 | } 229 | 100% { 230 | opacity: 1; 231 | transform: translateY(0); 232 | } 233 | } 234 | 235 | .container { 236 | position: relative; 237 | margin: 0 auto; 238 | height: 100%; 239 | max-width: 1800px; 240 | } 241 | 242 | .intro { 243 | color: #fff; 244 | } 245 | 246 | .intro .container { 247 | animation: fadedown 3.5s cubic-bezier(.19, 1, .22, 1); 248 | -webkit-animation: fadedown 3.5s cubic-bezier(.19, 1, .22, 1); 249 | -ms-animation: fadedown 3.5s cubic-bezier(.19, 1, .22, 1); 250 | -moz-animation: fadedown 3.5s cubic-bezier(.19, 1, .22, 1); 251 | } 252 | 253 | .hello { 254 | padding: 5% 0; 255 | } 256 | 257 | .hello h1 { 258 | font-size: 78px; 259 | letter-spacing: .2em; 260 | font-weight: 1000; 261 | line-height: 1.35em; 262 | } 263 | 264 | .hello .avatar { 265 | height: 150px; 266 | width: 150px; 267 | border-radius: 100%; 268 | float: left; 269 | margin-right: 50px; 270 | } 271 | 272 | .readme { 273 | font-size: 18px; 274 | letter-spacing: .2em; 275 | } 276 | 277 | .readme sup { 278 | font-size: .76em; 279 | } 280 | 281 | .readme p { 282 | margin-bottom: 1.8em; 283 | } 284 | 285 | .readme a { 286 | position: relative; 287 | color: #fff; 288 | margin: 0; 289 | text-decoration: none; 290 | transition: .3s all; 291 | } 292 | 293 | .readme a::after { 294 | content: ""; 295 | position: absolute; 296 | bottom: -5px; 297 | left: 0; 298 | width: 98%; 299 | height: 3px; 300 | background-color: rgba(255, 255, 255, .6); 301 | transition: .1s all; 302 | } 303 | 304 | .readme a:hover::after { 305 | background-color: rgba(255, 255, 255, 1); 306 | height: 5px; 307 | } 308 | 309 | .readme .b { 310 | font-weight: bold; 311 | } 312 | 313 | ul.skill li .progress div { 314 | animation: progressin 7s; 315 | -webkit-animation: progressin 7s; 316 | -ms-animation: progressin 7s; 317 | -moz-animation: progressin 7s; 318 | } 319 | 320 | @keyframes progressin { 321 | from { 322 | width: 0; 323 | } 324 | } 325 | 326 | @-webkit-keyframes progressin { 327 | from { 328 | width: 0; 329 | } 330 | } 331 | 332 | @-ms-keyframes progressin { 333 | from { 334 | width: 0; 335 | } 336 | } 337 | 338 | @-moz-keyframes progressin { 339 | from { 340 | width: 0; 341 | } 342 | } 343 | 344 | .links a { 345 | color: #fff; 346 | text-decoration: none; 347 | } 348 | 349 | .gate-friends { 350 | display: none; 351 | } 352 | 353 | .gate .container { 354 | background-color: #333; 355 | border-radius: 10px; 356 | } 357 | 358 | .ch-content { 359 | padding: 0 2%; 360 | } 361 | 362 | .gate .links .item { 363 | margin: 5px 0; 364 | padding: 15px 1.5%; 365 | float: left; 366 | width: 22%; 367 | height: 60px; 368 | transition: .2s all; 369 | opacity: .85; 370 | } 371 | 372 | .gate .links .item.akarin { 373 | opacity: .58; 374 | } 375 | 376 | .gate .links .item:hover { 377 | opacity: 1; 378 | border-radius: 5px; 379 | background-color: rgba(255, 255, 255, .25); 380 | transform: translateY(-5px); 381 | box-shadow: 0 3px 20px rgba(0, 0, 0, .28); 382 | animation: index-link-active 1s cubic-bezier(0.315, 0.605, 0.375, 0.925) forwards; 383 | } 384 | 385 | .gate .links .item .avatar { 386 | float: left; 387 | height: 60px; 388 | line-height: 60px; 389 | width: 60px; 390 | border-radius: 100%; 391 | text-align: center; 392 | margin-right: 15px; 393 | background-color: #353535; 394 | overflow: hidden; 395 | } 396 | 397 | .gate .links .item .avatar i { 398 | font-size: 24px; 399 | } 400 | 401 | .gate .links .item .avatar img { 402 | height: 60px; 403 | max-width: 60px; 404 | border-radius: 100%; 405 | } 406 | 407 | .gate .links .item .inner h5 { 408 | font-weight: normal; 409 | font-size: 17px; 410 | } 411 | 412 | .gate .links .item .inner p { 413 | font-size: 12px; 414 | color: rgba(255, 255, 255, .6); 415 | } 416 | 417 | .gate .links .item .inner h5, 418 | .gate .links .item .inner p { 419 | white-space: nowrap; 420 | overflow: hidden; 421 | text-overflow: ellipsis; 422 | } 423 | 424 | .footer { 425 | text-align: center; 426 | letter-spacing: .1em; 427 | padding-bottom: 10px; 428 | } 429 | 430 | .footer a { 431 | color: inherit; 432 | text-decoration: none; 433 | } 434 | 435 | .footer a:hover { 436 | text-decoration: underline; 437 | } 438 | 439 | .footer h3 { 440 | font-weight: normal; 441 | font-size: 20px; 442 | margin: 6px 0; 443 | } 444 | 445 | .footer p { 446 | font-size: 12px; 447 | opacity: .3; 448 | } 449 | 450 | .footer p.c { 451 | margin-top: 20px; 452 | letter-spacing: .1em; 453 | } 454 | 455 | .find-me a { 456 | text-decoration: none; 457 | color: #fff; 458 | } 459 | 460 | .find-me .item { 461 | display: inline-block; 462 | width: 80px; 463 | height: 80px; 464 | line-height: 80px; 465 | position: relative; 466 | text-align: center; 467 | transition: .2s all; 468 | position: relative; 469 | margin: 10px 20px 10px 0; 470 | } 471 | 472 | .find-me .item i { 473 | position: relative; 474 | display: inline-block; 475 | font-size: 26px; 476 | z-index: 2; 477 | transition: .3s all; 478 | } 479 | 480 | .find-me .item span { 481 | font-size: 12px; 482 | display: block; 483 | position: absolute; 484 | bottom: 0px; 485 | left: 0; 486 | width: 80px; 487 | height: auto; 488 | line-height: 1; 489 | z-index: 2; 490 | opacity: 0; 491 | transition: .3s all; 492 | } 493 | 494 | .find-me .item:hover span { 495 | opacity: .6; 496 | bottom: 16px; 497 | } 498 | 499 | .find-me .item:hover i { 500 | transform: translateY(-10px); 501 | } 502 | 503 | .find-me .item::after { 504 | content: ''; 505 | display: block; 506 | position: absolute; 507 | bottom: 0; 508 | left: 0; 509 | height: 4px; 510 | width: 100%; 511 | background-color: #333; 512 | transition: .2s all; 513 | border-radius: 2px; 514 | z-index: 0; 515 | } 516 | 517 | .find-me .item:nth-child(1)::after { 518 | background-color: #66ccff; 519 | } 520 | 521 | .find-me .item:nth-child(2)::after { 522 | background-color: #0088cc; 523 | } 524 | 525 | .find-me .item:nth-child(3)::after { 526 | background-color: #F58930; 527 | } 528 | 529 | .find-me .item:nth-child(4)::after { 530 | background-color: #28a9e0; 531 | } 532 | 533 | .find-me .item:nth-child(5)::after { 534 | background-color: #f09199; 535 | } 536 | 537 | .find-me .item:nth-child(6)::after { 538 | background-color: #f12d35; 539 | } 540 | 541 | .find-me .item:nth-child(7)::after { 542 | background-color: #555; 543 | } 544 | 545 | .find-me .item:nth-child(8)::after { 546 | background-color: #b600ff; 547 | } 548 | 549 | .find-me .item:hover { 550 | transform: translateY(-3px); 551 | } 552 | 553 | .find-me .item:hover::after { 554 | height: 100%; 555 | border-radius: 10px; 556 | } 557 | 558 | .roll-tag { 559 | display: none; 560 | transition: .1s all; 561 | width: 100%; 562 | position: relative; 563 | height: 80px; 564 | margin-bottom: 10px; 565 | } 566 | 567 | .roll-tag.active { 568 | display: inline-block; 569 | } 570 | 571 | .roll-tag span { 572 | position: absolute; 573 | animation: tag-entering 0.1s ease-in-out; 574 | box-shadow: 0 0 20px rgba(0, 0, 0, .28); 575 | background-color: #333; 576 | border-radius: 10px; 577 | padding: 10px 20px; 578 | display: inline-block; 579 | white-space: nowrap; 580 | transform-origin: center left; 581 | } 582 | 583 | .roll-tag span::before { 584 | content: '#'; 585 | margin-right: 5px; 586 | display: inline; 587 | } 588 | 589 | .roll-tag span.removing { 590 | animation: tag-removing 0.1s ease-in-out; 591 | } 592 | 593 | .enter-list { 594 | margin-left: -2%; 595 | margin-right: -2%; 596 | } 597 | 598 | .enter-list .item { 599 | position: relative; 600 | float: left; 601 | margin: 0 2% 6% 2%; 602 | width: 29.33%; 603 | display: block; 604 | color: #fff; 605 | text-decoration: none; 606 | height: 160px; 607 | background-color: #333; 608 | border-radius: 10px; 609 | transition: .2s all; 610 | } 611 | 612 | .enter-list .item:hover { 613 | background-color: #383838; 614 | transform: translateY(-5px); 615 | animation: index-link-active 1s cubic-bezier(0.315, 0.605, 0.375, 0.925) forwards; 616 | } 617 | 618 | .enter-list .item .text { 619 | font-size:2rem; 620 | position: absolute; 621 | bottom: 10%; 622 | left: 8%; 623 | } 624 | 625 | .enter-list .item .bg { 626 | position: absolute; 627 | height: 100%; 628 | width: 100%; 629 | overflow: hidden; 630 | } 631 | 632 | .enter-list .item .bg div { 633 | height: 100%; 634 | width: 100%; 635 | } 636 | 637 | .enter-list .item .bg svg { 638 | position: absolute; 639 | right: -20px; 640 | top: -20px; 641 | height: 160px; 642 | width: 160px; 643 | opacity: .3; 644 | } 645 | 646 | .enter-list .item .bg .triangle svg { 647 | height: 180px; 648 | width: 180px; 649 | } 650 | 651 | .enter-list .item .bg .square svg { 652 | animation: spin-icon 15s linear infinite; 653 | } 654 | 655 | .enter-list .item .bg .triangle svg { 656 | animation: spin-icon 30s linear infinite; 657 | } 658 | 659 | .enter-list .item .bg .rounded svg { 660 | animation: spin-icon 20s linear infinite; 661 | } 662 | 663 | @keyframes spin-icon { 664 | 0% { 665 | transform: rotate(0); 666 | } 667 | 100% { 668 | transform: rotate(360deg); 669 | } 670 | } 671 | 672 | @keyframes tag-entering { 673 | 0% { 674 | transform: translateY(-10px); 675 | opacity: 0; 676 | } 677 | 100% { 678 | opacity: 1; 679 | transform: translateY(0px); 680 | } 681 | } 682 | 683 | @keyframes tag-removing { 684 | 0% { 685 | transform: translateY(0px); 686 | opacity: 1; 687 | } 688 | 100% { 689 | opacity: 0; 690 | transform: translateY(10px); 691 | } 692 | } 693 | 694 | @keyframes loading-point { 695 | 0% { 696 | opacity: .8; 697 | } 698 | 50% { 699 | opacity: .25; 700 | } 701 | 100% { 702 | opacity: 8; 703 | } 704 | } 705 | 706 | @keyframes error { 707 | 0% { 708 | transform: translateX(0) 709 | } 710 | 25% { 711 | transform: translateX(-2px) 712 | } 713 | 50% { 714 | transform: translateX(0) 715 | } 716 | 75% { 717 | transform: translateX(2px) 718 | } 719 | 100% { 720 | transform: translateX(0) 721 | } 722 | } 723 | 724 | @keyframes index-link-active { 725 | 0% { 726 | transform: perspective(1600px) rotateX(0) rotateY(0) translateZ(0); 727 | } 728 | 16% { 729 | transform: perspective(1600px) rotateX(10deg) rotateY(5deg) translateZ(32px); 730 | } 731 | 100% { 732 | transform: perspective(1600px) rotateX(0) rotateY(0) translateZ(65px); 733 | } 734 | } 735 | 736 | .gate .links .item { 737 | width: 30.333%; 738 | } 739 | 740 | @media screen and (min-width: 1400px) { 741 | .container { 742 | width: 80%; 743 | } 744 | .gate .links .item { 745 | width: 22%; 746 | } 747 | } 748 | 749 | @media screen and (max-width: 700px) { 750 | body, 751 | html { 752 | min-width: 0; 753 | font-size: 15px; 754 | } 755 | .container { 756 | width: auto; 757 | margin: 0; 758 | } 759 | div.el span { 760 | display: block; 761 | width: 60%; 762 | left: 0; 763 | top: 75px; 764 | margin-left: 0; 765 | margin: 0 auto; 766 | margin-top: -40%; 767 | } 768 | .ch { 769 | padding: 20px 0; 770 | } 771 | .hello h1 { 772 | font-size: 40px; 773 | } 774 | .readme { 775 | font-size: 15px; 776 | } 777 | .roll-tag { 778 | height: 60px; 779 | } 780 | .roll-tag span { 781 | white-space: normal; 782 | display: block; 783 | } 784 | .enter-list .item { 785 | float: none; 786 | width: auto; 787 | margin-bottom: 20px; 788 | height: 100px; 789 | } 790 | .gate .links .item { 791 | width: 47%; 792 | margin: 0; 793 | padding: 15px 1.5%; 794 | height: auto; 795 | } 796 | .gate .links .item .avatar { 797 | height: 40px; 798 | line-height: 40px; 799 | width: 40px; 800 | margin-right: 10px; 801 | } 802 | .gate .links .item .avatar img { 803 | height: 40px; 804 | max-width: 40px; 805 | } 806 | .gate .links .item .inner { 807 | line-height: 1.5; 808 | padding: 0; 809 | } 810 | .gate .links .item .inner h5 { 811 | font-size: 15px; 812 | } 813 | .footer { 814 | /* padding-bottom: 100px; */ 815 | } 816 | /* .footer h3 { 817 | letter-spacing: .1em; 818 | } 819 | .footer p { 820 | letter-spacing: .2em; 821 | } 822 | } */ -------------------------------------------------------------------------------- /Star-Love/js/heart/simplex-noise.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A fast javascript implementation of simplex noise by Jonas Wagner 3 | 4 | Based on a speed-improved simplex noise algorithm for 2D, 3D and 4D in Java. 5 | Which is based on example code by Stefan Gustavson (stegu@itn.liu.se). 6 | With Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). 7 | Better rank ordering method by Stefan Gustavson in 2012. 8 | 9 | Copyright (c) 2018 Jonas Wagner 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | */ 29 | (function() { 30 | 'use strict'; 31 | 32 | var F2 = 0.5 * (Math.sqrt(3.0) - 1.0); 33 | var G2 = (3.0 - Math.sqrt(3.0)) / 6.0; 34 | var F3 = 1.0 / 3.0; 35 | var G3 = 1.0 / 6.0; 36 | var F4 = (Math.sqrt(5.0) - 1.0) / 4.0; 37 | var G4 = (5.0 - Math.sqrt(5.0)) / 20.0; 38 | 39 | function SimplexNoise(randomOrSeed) { 40 | var random; 41 | if (typeof randomOrSeed == 'function') { 42 | random = randomOrSeed; 43 | } 44 | else if (randomOrSeed) { 45 | random = alea(randomOrSeed); 46 | } else { 47 | random = Math.random; 48 | } 49 | this.p = buildPermutationTable(random); 50 | this.perm = new Uint8Array(512); 51 | this.permMod12 = new Uint8Array(512); 52 | for (var i = 0; i < 512; i++) { 53 | this.perm[i] = this.p[i & 255]; 54 | this.permMod12[i] = this.perm[i] % 12; 55 | } 56 | 57 | } 58 | SimplexNoise.prototype = { 59 | grad3: new Float32Array([1, 1, 0, 60 | -1, 1, 0, 61 | 1, -1, 0, 62 | 63 | -1, -1, 0, 64 | 1, 0, 1, 65 | -1, 0, 1, 66 | 67 | 1, 0, -1, 68 | -1, 0, -1, 69 | 0, 1, 1, 70 | 71 | 0, -1, 1, 72 | 0, 1, -1, 73 | 0, -1, -1]), 74 | grad4: new Float32Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 75 | 0, -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 76 | 1, 0, 1, 1, 1, 0, 1, -1, 1, 0, -1, 1, 1, 0, -1, -1, 77 | -1, 0, 1, 1, -1, 0, 1, -1, -1, 0, -1, 1, -1, 0, -1, -1, 78 | 1, 1, 0, 1, 1, 1, 0, -1, 1, -1, 0, 1, 1, -1, 0, -1, 79 | -1, 1, 0, 1, -1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, -1, 80 | 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 0, 81 | -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 0]), 82 | noise2D: function(xin, yin) { 83 | var permMod12 = this.permMod12; 84 | var perm = this.perm; 85 | var grad3 = this.grad3; 86 | var n0 = 0; // Noise contributions from the three corners 87 | var n1 = 0; 88 | var n2 = 0; 89 | // Skew the input space to determine which simplex cell we're in 90 | var s = (xin + yin) * F2; // Hairy factor for 2D 91 | var i = Math.floor(xin + s); 92 | var j = Math.floor(yin + s); 93 | var t = (i + j) * G2; 94 | var X0 = i - t; // Unskew the cell origin back to (x,y) space 95 | var Y0 = j - t; 96 | var x0 = xin - X0; // The x,y distances from the cell origin 97 | var y0 = yin - Y0; 98 | // For the 2D case, the simplex shape is an equilateral triangle. 99 | // Determine which simplex we are in. 100 | var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 101 | if (x0 > y0) { 102 | i1 = 1; 103 | j1 = 0; 104 | } // lower triangle, XY order: (0,0)->(1,0)->(1,1) 105 | else { 106 | i1 = 0; 107 | j1 = 1; 108 | } // upper triangle, YX order: (0,0)->(0,1)->(1,1) 109 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 110 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 111 | // c = (3-sqrt(3))/6 112 | var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 113 | var y1 = y0 - j1 + G2; 114 | var x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords 115 | var y2 = y0 - 1.0 + 2.0 * G2; 116 | // Work out the hashed gradient indices of the three simplex corners 117 | var ii = i & 255; 118 | var jj = j & 255; 119 | // Calculate the contribution from the three corners 120 | var t0 = 0.5 - x0 * x0 - y0 * y0; 121 | if (t0 >= 0) { 122 | var gi0 = permMod12[ii + perm[jj]] * 3; 123 | t0 *= t0; 124 | n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0); // (x,y) of grad3 used for 2D gradient 125 | } 126 | var t1 = 0.5 - x1 * x1 - y1 * y1; 127 | if (t1 >= 0) { 128 | var gi1 = permMod12[ii + i1 + perm[jj + j1]] * 3; 129 | t1 *= t1; 130 | n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1); 131 | } 132 | var t2 = 0.5 - x2 * x2 - y2 * y2; 133 | if (t2 >= 0) { 134 | var gi2 = permMod12[ii + 1 + perm[jj + 1]] * 3; 135 | t2 *= t2; 136 | n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2); 137 | } 138 | // Add contributions from each corner to get the final noise value. 139 | // The result is scaled to return values in the interval [-1,1]. 140 | return 70.0 * (n0 + n1 + n2); 141 | }, 142 | // 3D simplex noise 143 | noise3D: function(xin, yin, zin) { 144 | var permMod12 = this.permMod12; 145 | var perm = this.perm; 146 | var grad3 = this.grad3; 147 | var n0, n1, n2, n3; // Noise contributions from the four corners 148 | // Skew the input space to determine which simplex cell we're in 149 | var s = (xin + yin + zin) * F3; // Very nice and simple skew factor for 3D 150 | var i = Math.floor(xin + s); 151 | var j = Math.floor(yin + s); 152 | var k = Math.floor(zin + s); 153 | var t = (i + j + k) * G3; 154 | var X0 = i - t; // Unskew the cell origin back to (x,y,z) space 155 | var Y0 = j - t; 156 | var Z0 = k - t; 157 | var x0 = xin - X0; // The x,y,z distances from the cell origin 158 | var y0 = yin - Y0; 159 | var z0 = zin - Z0; 160 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 161 | // Determine which simplex we are in. 162 | var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 163 | var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 164 | if (x0 >= y0) { 165 | if (y0 >= z0) { 166 | i1 = 1; 167 | j1 = 0; 168 | k1 = 0; 169 | i2 = 1; 170 | j2 = 1; 171 | k2 = 0; 172 | } // X Y Z order 173 | else if (x0 >= z0) { 174 | i1 = 1; 175 | j1 = 0; 176 | k1 = 0; 177 | i2 = 1; 178 | j2 = 0; 179 | k2 = 1; 180 | } // X Z Y order 181 | else { 182 | i1 = 0; 183 | j1 = 0; 184 | k1 = 1; 185 | i2 = 1; 186 | j2 = 0; 187 | k2 = 1; 188 | } // Z X Y order 189 | } 190 | else { // x0 y0) rankx++; 297 | else ranky++; 298 | if (x0 > z0) rankx++; 299 | else rankz++; 300 | if (x0 > w0) rankx++; 301 | else rankw++; 302 | if (y0 > z0) ranky++; 303 | else rankz++; 304 | if (y0 > w0) ranky++; 305 | else rankw++; 306 | if (z0 > w0) rankz++; 307 | else rankw++; 308 | var i1, j1, k1, l1; // The integer offsets for the second simplex corner 309 | var i2, j2, k2, l2; // The integer offsets for the third simplex corner 310 | var i3, j3, k3, l3; // The integer offsets for the fourth simplex corner 311 | // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. 312 | // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0; 317 | j1 = ranky >= 3 ? 1 : 0; 318 | k1 = rankz >= 3 ? 1 : 0; 319 | l1 = rankw >= 3 ? 1 : 0; 320 | // Rank 2 denotes the second largest coordinate. 321 | i2 = rankx >= 2 ? 1 : 0; 322 | j2 = ranky >= 2 ? 1 : 0; 323 | k2 = rankz >= 2 ? 1 : 0; 324 | l2 = rankw >= 2 ? 1 : 0; 325 | // Rank 1 denotes the second smallest coordinate. 326 | i3 = rankx >= 1 ? 1 : 0; 327 | j3 = ranky >= 1 ? 1 : 0; 328 | k3 = rankz >= 1 ? 1 : 0; 329 | l3 = rankw >= 1 ? 1 : 0; 330 | // The fifth corner has all coordinate offsets = 1, so no need to compute that. 331 | var x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords 332 | var y1 = y0 - j1 + G4; 333 | var z1 = z0 - k1 + G4; 334 | var w1 = w0 - l1 + G4; 335 | var x2 = x0 - i2 + 2.0 * G4; // Offsets for third corner in (x,y,z,w) coords 336 | var y2 = y0 - j2 + 2.0 * G4; 337 | var z2 = z0 - k2 + 2.0 * G4; 338 | var w2 = w0 - l2 + 2.0 * G4; 339 | var x3 = x0 - i3 + 3.0 * G4; // Offsets for fourth corner in (x,y,z,w) coords 340 | var y3 = y0 - j3 + 3.0 * G4; 341 | var z3 = z0 - k3 + 3.0 * G4; 342 | var w3 = w0 - l3 + 3.0 * G4; 343 | var x4 = x0 - 1.0 + 4.0 * G4; // Offsets for last corner in (x,y,z,w) coords 344 | var y4 = y0 - 1.0 + 4.0 * G4; 345 | var z4 = z0 - 1.0 + 4.0 * G4; 346 | var w4 = w0 - 1.0 + 4.0 * G4; 347 | // Work out the hashed gradient indices of the five simplex corners 348 | var ii = i & 255; 349 | var jj = j & 255; 350 | var kk = k & 255; 351 | var ll = l & 255; 352 | // Calculate the contribution from the five corners 353 | var t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; 354 | if (t0 < 0) n0 = 0.0; 355 | else { 356 | var gi0 = (perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32) * 4; 357 | t0 *= t0; 358 | n0 = t0 * t0 * (grad4[gi0] * x0 + grad4[gi0 + 1] * y0 + grad4[gi0 + 2] * z0 + grad4[gi0 + 3] * w0); 359 | } 360 | var t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; 361 | if (t1 < 0) n1 = 0.0; 362 | else { 363 | var gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32) * 4; 364 | t1 *= t1; 365 | n1 = t1 * t1 * (grad4[gi1] * x1 + grad4[gi1 + 1] * y1 + grad4[gi1 + 2] * z1 + grad4[gi1 + 3] * w1); 366 | } 367 | var t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; 368 | if (t2 < 0) n2 = 0.0; 369 | else { 370 | var gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32) * 4; 371 | t2 *= t2; 372 | n2 = t2 * t2 * (grad4[gi2] * x2 + grad4[gi2 + 1] * y2 + grad4[gi2 + 2] * z2 + grad4[gi2 + 3] * w2); 373 | } 374 | var t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; 375 | if (t3 < 0) n3 = 0.0; 376 | else { 377 | var gi3 = (perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32) * 4; 378 | t3 *= t3; 379 | n3 = t3 * t3 * (grad4[gi3] * x3 + grad4[gi3 + 1] * y3 + grad4[gi3 + 2] * z3 + grad4[gi3 + 3] * w3); 380 | } 381 | var t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; 382 | if (t4 < 0) n4 = 0.0; 383 | else { 384 | var gi4 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32) * 4; 385 | t4 *= t4; 386 | n4 = t4 * t4 * (grad4[gi4] * x4 + grad4[gi4 + 1] * y4 + grad4[gi4 + 2] * z4 + grad4[gi4 + 3] * w4); 387 | } 388 | // Sum up and scale the result to cover the range [-1,1] 389 | return 27.0 * (n0 + n1 + n2 + n3 + n4); 390 | } 391 | }; 392 | 393 | function buildPermutationTable(random) { 394 | var i; 395 | var p = new Uint8Array(256); 396 | for (i = 0; i < 256; i++) { 397 | p[i] = i; 398 | } 399 | for (i = 0; i < 255; i++) { 400 | var r = i + ~~(random() * (256 - i)); 401 | var aux = p[i]; 402 | p[i] = p[r]; 403 | p[r] = aux; 404 | } 405 | return p; 406 | } 407 | SimplexNoise._buildPermutationTable = buildPermutationTable; 408 | 409 | /* 410 | The ALEA PRNG and masher code used by simplex-noise.js 411 | is based on code by Johannes Baagøe, modified by Jonas Wagner. 412 | See alea.md for the full license. 413 | */ 414 | function alea() { 415 | var s0 = 0; 416 | var s1 = 0; 417 | var s2 = 0; 418 | var c = 1; 419 | 420 | var mash = masher(); 421 | s0 = mash(' '); 422 | s1 = mash(' '); 423 | s2 = mash(' '); 424 | 425 | for (var i = 0; i < arguments.length; i++) { 426 | s0 -= mash(arguments[i]); 427 | if (s0 < 0) { 428 | s0 += 1; 429 | } 430 | s1 -= mash(arguments[i]); 431 | if (s1 < 0) { 432 | s1 += 1; 433 | } 434 | s2 -= mash(arguments[i]); 435 | if (s2 < 0) { 436 | s2 += 1; 437 | } 438 | } 439 | mash = null; 440 | return function() { 441 | var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 442 | s0 = s1; 443 | s1 = s2; 444 | return s2 = t - (c = t | 0); 445 | }; 446 | } 447 | function masher() { 448 | var n = 0xefc8249d; 449 | return function(data) { 450 | data = data.toString(); 451 | for (var i = 0; i < data.length; i++) { 452 | n += data.charCodeAt(i); 453 | var h = 0.02519603282416938 * n; 454 | n = h >>> 0; 455 | h -= n; 456 | h *= n; 457 | n = h >>> 0; 458 | h -= n; 459 | n += h * 0x100000000; // 2^32 460 | } 461 | return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 462 | }; 463 | } 464 | 465 | // amd 466 | if (typeof define !== 'undefined' && define.amd) define(function() {return SimplexNoise;}); 467 | // common js 468 | if (typeof exports !== 'undefined') exports.SimplexNoise = SimplexNoise; 469 | // browser 470 | else if (typeof window !== 'undefined') window.SimplexNoise = SimplexNoise; 471 | // nodejs 472 | if (typeof module !== 'undefined') { 473 | module.exports = SimplexNoise; 474 | } 475 | 476 | })(); 477 | -------------------------------------------------------------------------------- /Star-Love/js/heart/TrackballControls.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 3 | const _changeEvent = { 4 | type: 'change' 5 | }; 6 | const _startEvent = { 7 | type: 'start' 8 | }; 9 | const _endEvent = { 10 | type: 'end' 11 | }; 12 | 13 | class TrackballControls extends THREE.EventDispatcher { 14 | 15 | constructor( object, domElement ) { 16 | 17 | super(); 18 | if ( domElement === undefined ) console.warn( 'THREE.TrackballControls: The second parameter "domElement" is now mandatory.' ); 19 | if ( domElement === document ) console.error( 'THREE.TrackballControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' ); 20 | const scope = this; 21 | const STATE = { 22 | NONE: - 1, 23 | ROTATE: 0, 24 | ZOOM: 1, 25 | PAN: 2, 26 | TOUCH_ROTATE: 3, 27 | TOUCH_ZOOM_PAN: 4 28 | }; 29 | this.object = object; 30 | this.domElement = domElement; 31 | this.domElement.style.touchAction = 'none'; // disable touch scroll 32 | // API 33 | 34 | this.enabled = true; 35 | this.screen = { 36 | left: 0, 37 | top: 0, 38 | width: 0, 39 | height: 0 40 | }; 41 | this.rotateSpeed = 1.0; 42 | this.zoomSpeed = 1.2; 43 | this.panSpeed = 0.3; 44 | this.noRotate = false; 45 | this.noZoom = false; 46 | this.noPan = false; 47 | this.staticMoving = false; 48 | this.dynamicDampingFactor = 0.2; 49 | this.minDistance = 0; 50 | this.maxDistance = Infinity; 51 | this.keys = [ 'KeyA', 52 | /*A*/ 53 | 'KeyS', 54 | /*S*/ 55 | 'KeyD' 56 | /*D*/ 57 | ]; 58 | this.mouseButtons = { 59 | LEFT: THREE.MOUSE.ROTATE, 60 | MIDDLE: THREE.MOUSE.DOLLY, 61 | RIGHT: THREE.MOUSE.PAN 62 | }; // internals 63 | 64 | this.target = new THREE.Vector3(); 65 | const EPS = 0.000001; 66 | const lastPosition = new THREE.Vector3(); 67 | let lastZoom = 1; 68 | let _state = STATE.NONE, 69 | _keyState = STATE.NONE, 70 | _touchZoomDistanceStart = 0, 71 | _touchZoomDistanceEnd = 0, 72 | _lastAngle = 0; 73 | 74 | const _eye = new THREE.Vector3(), 75 | _movePrev = new THREE.Vector2(), 76 | _moveCurr = new THREE.Vector2(), 77 | _lastAxis = new THREE.Vector3(), 78 | _zoomStart = new THREE.Vector2(), 79 | _zoomEnd = new THREE.Vector2(), 80 | _panStart = new THREE.Vector2(), 81 | _panEnd = new THREE.Vector2(), 82 | _pointers = [], 83 | _pointerPositions = {}; // for reset 84 | 85 | 86 | this.target0 = this.target.clone(); 87 | this.position0 = this.object.position.clone(); 88 | this.up0 = this.object.up.clone(); 89 | this.zoom0 = this.object.zoom; // methods 90 | 91 | this.handleResize = function () { 92 | 93 | const box = scope.domElement.getBoundingClientRect(); // adjustments come from similar code in the jquery offset() function 94 | 95 | const d = scope.domElement.ownerDocument.documentElement; 96 | scope.screen.left = box.left + window.pageXOffset - d.clientLeft; 97 | scope.screen.top = box.top + window.pageYOffset - d.clientTop; 98 | scope.screen.width = box.width; 99 | scope.screen.height = box.height; 100 | 101 | }; 102 | 103 | const getMouseOnScreen = function () { 104 | 105 | const vector = new THREE.Vector2(); 106 | return function getMouseOnScreen( pageX, pageY ) { 107 | 108 | vector.set( ( pageX - scope.screen.left ) / scope.screen.width, ( pageY - scope.screen.top ) / scope.screen.height ); 109 | return vector; 110 | 111 | }; 112 | 113 | }(); 114 | 115 | const getMouseOnCircle = function () { 116 | 117 | const vector = new THREE.Vector2(); 118 | return function getMouseOnCircle( pageX, pageY ) { 119 | 120 | vector.set( ( pageX - scope.screen.width * 0.5 - scope.screen.left ) / ( scope.screen.width * 0.5 ), ( scope.screen.height + 2 * ( scope.screen.top - pageY ) ) / scope.screen.width // screen.width intentional 121 | ); 122 | return vector; 123 | 124 | }; 125 | 126 | }(); 127 | 128 | this.rotateCamera = function () { 129 | 130 | const axis = new THREE.Vector3(), 131 | quaternion = new THREE.Quaternion(), 132 | eyeDirection = new THREE.Vector3(), 133 | objectUpDirection = new THREE.Vector3(), 134 | objectSidewaysDirection = new THREE.Vector3(), 135 | moveDirection = new THREE.Vector3(); 136 | return function rotateCamera() { 137 | 138 | moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); 139 | let angle = moveDirection.length(); 140 | 141 | if ( angle ) { 142 | 143 | _eye.copy( scope.object.position ).sub( scope.target ); 144 | 145 | eyeDirection.copy( _eye ).normalize(); 146 | objectUpDirection.copy( scope.object.up ).normalize(); 147 | objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); 148 | objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); 149 | objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); 150 | moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); 151 | axis.crossVectors( moveDirection, _eye ).normalize(); 152 | angle *= scope.rotateSpeed; 153 | quaternion.setFromAxisAngle( axis, angle ); 154 | 155 | _eye.applyQuaternion( quaternion ); 156 | 157 | scope.object.up.applyQuaternion( quaternion ); 158 | 159 | _lastAxis.copy( axis ); 160 | 161 | _lastAngle = angle; 162 | 163 | } else if ( ! scope.staticMoving && _lastAngle ) { 164 | 165 | _lastAngle *= Math.sqrt( 1.0 - scope.dynamicDampingFactor ); 166 | 167 | _eye.copy( scope.object.position ).sub( scope.target ); 168 | 169 | quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); 170 | 171 | _eye.applyQuaternion( quaternion ); 172 | 173 | scope.object.up.applyQuaternion( quaternion ); 174 | 175 | } 176 | 177 | _movePrev.copy( _moveCurr ); 178 | 179 | }; 180 | 181 | }(); 182 | 183 | this.zoomCamera = function () { 184 | 185 | let factor; 186 | 187 | if ( _state === STATE.TOUCH_ZOOM_PAN ) { 188 | 189 | factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; 190 | _touchZoomDistanceStart = _touchZoomDistanceEnd; 191 | 192 | if ( scope.object.isPerspectiveCamera ) { 193 | 194 | _eye.multiplyScalar( factor ); 195 | 196 | } else if ( scope.object.isOrthographicCamera ) { 197 | 198 | scope.object.zoom *= factor; 199 | scope.object.updateProjectionMatrix(); 200 | 201 | } else { 202 | 203 | console.warn( 'THREE.TrackballControls: Unsupported camera type' ); 204 | 205 | } 206 | 207 | } else { 208 | 209 | factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * scope.zoomSpeed; 210 | 211 | if ( factor !== 1.0 && factor > 0.0 ) { 212 | 213 | if ( scope.object.isPerspectiveCamera ) { 214 | 215 | _eye.multiplyScalar( factor ); 216 | 217 | } else if ( scope.object.isOrthographicCamera ) { 218 | 219 | scope.object.zoom /= factor; 220 | scope.object.updateProjectionMatrix(); 221 | 222 | } else { 223 | 224 | console.warn( 'THREE.TrackballControls: Unsupported camera type' ); 225 | 226 | } 227 | 228 | } 229 | 230 | if ( scope.staticMoving ) { 231 | 232 | _zoomStart.copy( _zoomEnd ); 233 | 234 | } else { 235 | 236 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 237 | 238 | } 239 | 240 | } 241 | 242 | }; 243 | 244 | this.panCamera = function () { 245 | 246 | const mouseChange = new THREE.Vector2(), 247 | objectUp = new THREE.Vector3(), 248 | pan = new THREE.Vector3(); 249 | return function panCamera() { 250 | 251 | mouseChange.copy( _panEnd ).sub( _panStart ); 252 | 253 | if ( mouseChange.lengthSq() ) { 254 | 255 | if ( scope.object.isOrthographicCamera ) { 256 | 257 | const scale_x = ( scope.object.right - scope.object.left ) / scope.object.zoom / scope.domElement.clientWidth; 258 | const scale_y = ( scope.object.top - scope.object.bottom ) / scope.object.zoom / scope.domElement.clientWidth; 259 | mouseChange.x *= scale_x; 260 | mouseChange.y *= scale_y; 261 | 262 | } 263 | 264 | mouseChange.multiplyScalar( _eye.length() * scope.panSpeed ); 265 | pan.copy( _eye ).cross( scope.object.up ).setLength( mouseChange.x ); 266 | pan.add( objectUp.copy( scope.object.up ).setLength( mouseChange.y ) ); 267 | scope.object.position.add( pan ); 268 | scope.target.add( pan ); 269 | 270 | if ( scope.staticMoving ) { 271 | 272 | _panStart.copy( _panEnd ); 273 | 274 | } else { 275 | 276 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( scope.dynamicDampingFactor ) ); 277 | 278 | } 279 | 280 | } 281 | 282 | }; 283 | 284 | }(); 285 | 286 | this.checkDistances = function () { 287 | 288 | if ( ! scope.noZoom || ! scope.noPan ) { 289 | 290 | if ( _eye.lengthSq() > scope.maxDistance * scope.maxDistance ) { 291 | 292 | scope.object.position.addVectors( scope.target, _eye.setLength( scope.maxDistance ) ); 293 | 294 | _zoomStart.copy( _zoomEnd ); 295 | 296 | } 297 | 298 | if ( _eye.lengthSq() < scope.minDistance * scope.minDistance ) { 299 | 300 | scope.object.position.addVectors( scope.target, _eye.setLength( scope.minDistance ) ); 301 | 302 | _zoomStart.copy( _zoomEnd ); 303 | 304 | } 305 | 306 | } 307 | 308 | }; 309 | 310 | this.update = function () { 311 | 312 | _eye.subVectors( scope.object.position, scope.target ); 313 | 314 | if ( ! scope.noRotate ) { 315 | 316 | scope.rotateCamera(); 317 | 318 | } 319 | 320 | if ( ! scope.noZoom ) { 321 | 322 | scope.zoomCamera(); 323 | 324 | } 325 | 326 | if ( ! scope.noPan ) { 327 | 328 | scope.panCamera(); 329 | 330 | } 331 | 332 | scope.object.position.addVectors( scope.target, _eye ); 333 | 334 | if ( scope.object.isPerspectiveCamera ) { 335 | 336 | scope.checkDistances(); 337 | scope.object.lookAt( scope.target ); 338 | 339 | if ( lastPosition.distanceToSquared( scope.object.position ) > EPS ) { 340 | 341 | scope.dispatchEvent( _changeEvent ); 342 | lastPosition.copy( scope.object.position ); 343 | 344 | } 345 | 346 | } else if ( scope.object.isOrthographicCamera ) { 347 | 348 | scope.object.lookAt( scope.target ); 349 | 350 | if ( lastPosition.distanceToSquared( scope.object.position ) > EPS || lastZoom !== scope.object.zoom ) { 351 | 352 | scope.dispatchEvent( _changeEvent ); 353 | lastPosition.copy( scope.object.position ); 354 | lastZoom = scope.object.zoom; 355 | 356 | } 357 | 358 | } else { 359 | 360 | console.warn( 'THREE.TrackballControls: Unsupported camera type' ); 361 | 362 | } 363 | 364 | }; 365 | 366 | this.reset = function () { 367 | 368 | _state = STATE.NONE; 369 | _keyState = STATE.NONE; 370 | scope.target.copy( scope.target0 ); 371 | scope.object.position.copy( scope.position0 ); 372 | scope.object.up.copy( scope.up0 ); 373 | scope.object.zoom = scope.zoom0; 374 | scope.object.updateProjectionMatrix(); 375 | 376 | _eye.subVectors( scope.object.position, scope.target ); 377 | 378 | scope.object.lookAt( scope.target ); 379 | scope.dispatchEvent( _changeEvent ); 380 | lastPosition.copy( scope.object.position ); 381 | lastZoom = scope.object.zoom; 382 | 383 | }; // listeners 384 | 385 | 386 | function onPointerDown( event ) { 387 | 388 | if ( scope.enabled === false ) return; 389 | 390 | if ( _pointers.length === 0 ) { 391 | 392 | scope.domElement.setPointerCapture( event.pointerId ); 393 | scope.domElement.addEventListener( 'pointermove', onPointerMove ); 394 | scope.domElement.addEventListener( 'pointerup', onPointerUp ); 395 | 396 | } // 397 | 398 | 399 | addPointer( event ); 400 | 401 | if ( event.pointerType === 'touch' ) { 402 | 403 | onTouchStart( event ); 404 | 405 | } else { 406 | 407 | onMouseDown( event ); 408 | 409 | } 410 | 411 | } 412 | 413 | function onPointerMove( event ) { 414 | 415 | if ( scope.enabled === false ) return; 416 | 417 | if ( event.pointerType === 'touch' ) { 418 | 419 | onTouchMove( event ); 420 | 421 | } else { 422 | 423 | onMouseMove( event ); 424 | 425 | } 426 | 427 | } 428 | 429 | function onPointerUp( event ) { 430 | 431 | if ( scope.enabled === false ) return; 432 | 433 | if ( event.pointerType === 'touch' ) { 434 | 435 | onTouchEnd( event ); 436 | 437 | } else { 438 | 439 | onMouseUp(); 440 | 441 | } // 442 | 443 | 444 | removePointer( event ); 445 | 446 | if ( _pointers.length === 0 ) { 447 | 448 | scope.domElement.releasePointerCapture( event.pointerId ); 449 | scope.domElement.removeEventListener( 'pointermove', onPointerMove ); 450 | scope.domElement.removeEventListener( 'pointerup', onPointerUp ); 451 | 452 | } 453 | 454 | } 455 | 456 | function onPointerCancel( event ) { 457 | 458 | removePointer( event ); 459 | 460 | } 461 | 462 | function keydown( event ) { 463 | 464 | if ( scope.enabled === false ) return; 465 | window.removeEventListener( 'keydown', keydown ); 466 | 467 | if ( _keyState !== STATE.NONE ) { 468 | 469 | return; 470 | 471 | } else if ( event.code === scope.keys[ STATE.ROTATE ] && ! scope.noRotate ) { 472 | 473 | _keyState = STATE.ROTATE; 474 | 475 | } else if ( event.code === scope.keys[ STATE.ZOOM ] && ! scope.noZoom ) { 476 | 477 | _keyState = STATE.ZOOM; 478 | 479 | } else if ( event.code === scope.keys[ STATE.PAN ] && ! scope.noPan ) { 480 | 481 | _keyState = STATE.PAN; 482 | 483 | } 484 | 485 | } 486 | 487 | function keyup() { 488 | 489 | if ( scope.enabled === false ) return; 490 | _keyState = STATE.NONE; 491 | window.addEventListener( 'keydown', keydown ); 492 | 493 | } 494 | 495 | function onMouseDown( event ) { 496 | 497 | if ( _state === STATE.NONE ) { 498 | 499 | switch ( event.button ) { 500 | 501 | case scope.mouseButtons.LEFT: 502 | _state = STATE.ROTATE; 503 | break; 504 | 505 | case scope.mouseButtons.MIDDLE: 506 | _state = STATE.ZOOM; 507 | break; 508 | 509 | case scope.mouseButtons.RIGHT: 510 | _state = STATE.PAN; 511 | break; 512 | 513 | default: 514 | _state = STATE.NONE; 515 | 516 | } 517 | 518 | } 519 | 520 | const state = _keyState !== STATE.NONE ? _keyState : _state; 521 | 522 | if ( state === STATE.ROTATE && ! scope.noRotate ) { 523 | 524 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 525 | 526 | _movePrev.copy( _moveCurr ); 527 | 528 | } else if ( state === STATE.ZOOM && ! scope.noZoom ) { 529 | 530 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 531 | 532 | _zoomEnd.copy( _zoomStart ); 533 | 534 | } else if ( state === STATE.PAN && ! scope.noPan ) { 535 | 536 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 537 | 538 | _panEnd.copy( _panStart ); 539 | 540 | } 541 | 542 | scope.dispatchEvent( _startEvent ); 543 | 544 | } 545 | 546 | function onMouseMove( event ) { 547 | 548 | const state = _keyState !== STATE.NONE ? _keyState : _state; 549 | 550 | if ( state === STATE.ROTATE && ! scope.noRotate ) { 551 | 552 | _movePrev.copy( _moveCurr ); 553 | 554 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 555 | 556 | } else if ( state === STATE.ZOOM && ! scope.noZoom ) { 557 | 558 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 559 | 560 | } else if ( state === STATE.PAN && ! scope.noPan ) { 561 | 562 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 563 | 564 | } 565 | 566 | } 567 | 568 | function onMouseUp() { 569 | 570 | _state = STATE.NONE; 571 | scope.dispatchEvent( _endEvent ); 572 | 573 | } 574 | 575 | function onMouseWheel( event ) { 576 | 577 | if ( scope.enabled === false ) return; 578 | if ( scope.noZoom === true ) return; 579 | event.preventDefault(); 580 | 581 | switch ( event.deltaMode ) { 582 | 583 | case 2: 584 | // Zoom in pages 585 | _zoomStart.y -= event.deltaY * 0.025; 586 | break; 587 | 588 | case 1: 589 | // Zoom in lines 590 | _zoomStart.y -= event.deltaY * 0.01; 591 | break; 592 | 593 | default: 594 | // undefined, 0, assume pixels 595 | _zoomStart.y -= event.deltaY * 0.00025; 596 | break; 597 | 598 | } 599 | 600 | scope.dispatchEvent( _startEvent ); 601 | scope.dispatchEvent( _endEvent ); 602 | 603 | } 604 | 605 | function onTouchStart( event ) { 606 | 607 | trackPointer( event ); 608 | 609 | switch ( _pointers.length ) { 610 | 611 | case 1: 612 | _state = STATE.TOUCH_ROTATE; 613 | 614 | _moveCurr.copy( getMouseOnCircle( _pointers[ 0 ].pageX, _pointers[ 0 ].pageY ) ); 615 | 616 | _movePrev.copy( _moveCurr ); 617 | 618 | break; 619 | 620 | default: 621 | // 2 or more 622 | _state = STATE.TOUCH_ZOOM_PAN; 623 | const dx = _pointers[ 0 ].pageX - _pointers[ 1 ].pageX; 624 | const dy = _pointers[ 0 ].pageY - _pointers[ 1 ].pageY; 625 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 626 | const x = ( _pointers[ 0 ].pageX + _pointers[ 1 ].pageX ) / 2; 627 | const y = ( _pointers[ 0 ].pageY + _pointers[ 1 ].pageY ) / 2; 628 | 629 | _panStart.copy( getMouseOnScreen( x, y ) ); 630 | 631 | _panEnd.copy( _panStart ); 632 | 633 | break; 634 | 635 | } 636 | 637 | scope.dispatchEvent( _startEvent ); 638 | 639 | } 640 | 641 | function onTouchMove( event ) { 642 | 643 | trackPointer( event ); 644 | 645 | switch ( _pointers.length ) { 646 | 647 | case 1: 648 | _movePrev.copy( _moveCurr ); 649 | 650 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 651 | 652 | break; 653 | 654 | default: 655 | // 2 or more 656 | const position = getSecondPointerPosition( event ); 657 | const dx = event.pageX - position.x; 658 | const dy = event.pageY - position.y; 659 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); 660 | const x = ( event.pageX + position.x ) / 2; 661 | const y = ( event.pageY + position.y ) / 2; 662 | 663 | _panEnd.copy( getMouseOnScreen( x, y ) ); 664 | 665 | break; 666 | 667 | } 668 | 669 | } 670 | 671 | function onTouchEnd( event ) { 672 | 673 | switch ( _pointers.length ) { 674 | 675 | case 0: 676 | _state = STATE.NONE; 677 | break; 678 | 679 | case 1: 680 | _state = STATE.TOUCH_ROTATE; 681 | 682 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 683 | 684 | _movePrev.copy( _moveCurr ); 685 | 686 | break; 687 | 688 | case 2: 689 | _state = STATE.TOUCH_ZOOM_PAN; 690 | 691 | _moveCurr.copy( getMouseOnCircle( event.pageX - _movePrev.pageX, event.pageY - _movePrev.pageY ) ); 692 | 693 | _movePrev.copy( _moveCurr ); 694 | 695 | break; 696 | 697 | } 698 | 699 | scope.dispatchEvent( _endEvent ); 700 | 701 | } 702 | 703 | function contextmenu( event ) { 704 | 705 | if ( scope.enabled === false ) return; 706 | event.preventDefault(); 707 | 708 | } 709 | 710 | function addPointer( event ) { 711 | 712 | _pointers.push( event ); 713 | 714 | } 715 | 716 | function removePointer( event ) { 717 | 718 | delete _pointerPositions[ event.pointerId ]; 719 | 720 | for ( let i = 0; i < _pointers.length; i ++ ) { 721 | 722 | if ( _pointers[ i ].pointerId == event.pointerId ) { 723 | 724 | _pointers.splice( i, 1 ); 725 | 726 | return; 727 | 728 | } 729 | 730 | } 731 | 732 | } 733 | 734 | function trackPointer( event ) { 735 | 736 | let position = _pointerPositions[ event.pointerId ]; 737 | 738 | if ( position === undefined ) { 739 | 740 | position = new THREE.Vector2(); 741 | _pointerPositions[ event.pointerId ] = position; 742 | 743 | } 744 | 745 | position.set( event.pageX, event.pageY ); 746 | 747 | } 748 | 749 | function getSecondPointerPosition( event ) { 750 | 751 | const pointer = event.pointerId === _pointers[ 0 ].pointerId ? _pointers[ 1 ] : _pointers[ 0 ]; 752 | return _pointerPositions[ pointer.pointerId ]; 753 | 754 | } 755 | 756 | this.dispose = function () { 757 | 758 | scope.domElement.removeEventListener( 'contextmenu', contextmenu ); 759 | scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); 760 | scope.domElement.removeEventListener( 'pointercancel', onPointerCancel ); 761 | scope.domElement.removeEventListener( 'wheel', onMouseWheel ); 762 | scope.domElement.removeEventListener( 'pointermove', onPointerMove ); 763 | scope.domElement.removeEventListener( 'pointerup', onPointerUp ); 764 | window.removeEventListener( 'keydown', keydown ); 765 | window.removeEventListener( 'keyup', keyup ); 766 | 767 | }; 768 | 769 | this.domElement.addEventListener( 'contextmenu', contextmenu ); 770 | this.domElement.addEventListener( 'pointerdown', onPointerDown ); 771 | this.domElement.addEventListener( 'pointercancel', onPointerCancel ); 772 | this.domElement.addEventListener( 'wheel', onMouseWheel, { 773 | passive: false 774 | } ); 775 | window.addEventListener( 'keydown', keydown ); 776 | window.addEventListener( 'keyup', keyup ); 777 | this.handleResize(); // force an update at start 778 | 779 | this.update(); 780 | 781 | } 782 | 783 | } 784 | 785 | THREE.TrackballControls = TrackballControls; 786 | 787 | } )(); 788 | -------------------------------------------------------------------------------- /Star-Love/js/heart/OBJLoader.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 3 | const _object_pattern = /^[og]\s*(.+)?/; // mtllib file_reference 4 | 5 | const _material_library_pattern = /^mtllib /; // usemtl material_name 6 | 7 | const _material_use_pattern = /^usemtl /; // usemap map_name 8 | 9 | const _map_use_pattern = /^usemap /; 10 | 11 | const _vA = new THREE.Vector3(); 12 | 13 | const _vB = new THREE.Vector3(); 14 | 15 | const _vC = new THREE.Vector3(); 16 | 17 | const _ab = new THREE.Vector3(); 18 | 19 | const _cb = new THREE.Vector3(); 20 | 21 | function ParserState() { 22 | 23 | const state = { 24 | objects: [], 25 | object: {}, 26 | vertices: [], 27 | normals: [], 28 | colors: [], 29 | uvs: [], 30 | materials: {}, 31 | materialLibraries: [], 32 | startObject: function ( name, fromDeclaration ) { 33 | 34 | // If the current object (initial from reset) is not from a g/o declaration in the parsed 35 | // file. We need to use it for the first parsed g/o to keep things in sync. 36 | if ( this.object && this.object.fromDeclaration === false ) { 37 | 38 | this.object.name = name; 39 | this.object.fromDeclaration = fromDeclaration !== false; 40 | return; 41 | 42 | } 43 | 44 | const previousMaterial = this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined; 45 | 46 | if ( this.object && typeof this.object._finalize === 'function' ) { 47 | 48 | this.object._finalize( true ); 49 | 50 | } 51 | 52 | this.object = { 53 | name: name || '', 54 | fromDeclaration: fromDeclaration !== false, 55 | geometry: { 56 | vertices: [], 57 | normals: [], 58 | colors: [], 59 | uvs: [], 60 | hasUVIndices: false 61 | }, 62 | materials: [], 63 | smooth: true, 64 | startMaterial: function ( name, libraries ) { 65 | 66 | const previous = this._finalize( false ); // New usemtl declaration overwrites an inherited material, except if faces were declared 67 | // after the material, then it must be preserved for proper MultiMaterial continuation. 68 | 69 | 70 | if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) { 71 | 72 | this.materials.splice( previous.index, 1 ); 73 | 74 | } 75 | 76 | const material = { 77 | index: this.materials.length, 78 | name: name || '', 79 | mtllib: Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '', 80 | smooth: previous !== undefined ? previous.smooth : this.smooth, 81 | groupStart: previous !== undefined ? previous.groupEnd : 0, 82 | groupEnd: - 1, 83 | groupCount: - 1, 84 | inherited: false, 85 | clone: function ( index ) { 86 | 87 | const cloned = { 88 | index: typeof index === 'number' ? index : this.index, 89 | name: this.name, 90 | mtllib: this.mtllib, 91 | smooth: this.smooth, 92 | groupStart: 0, 93 | groupEnd: - 1, 94 | groupCount: - 1, 95 | inherited: false 96 | }; 97 | cloned.clone = this.clone.bind( cloned ); 98 | return cloned; 99 | 100 | } 101 | }; 102 | this.materials.push( material ); 103 | return material; 104 | 105 | }, 106 | currentMaterial: function () { 107 | 108 | if ( this.materials.length > 0 ) { 109 | 110 | return this.materials[ this.materials.length - 1 ]; 111 | 112 | } 113 | 114 | return undefined; 115 | 116 | }, 117 | _finalize: function ( end ) { 118 | 119 | const lastMultiMaterial = this.currentMaterial(); 120 | 121 | if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) { 122 | 123 | lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3; 124 | lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart; 125 | lastMultiMaterial.inherited = false; 126 | 127 | } // Ignore objects tail materials if no face declarations followed them before a new o/g started. 128 | 129 | 130 | if ( end && this.materials.length > 1 ) { 131 | 132 | for ( let mi = this.materials.length - 1; mi >= 0; mi -- ) { 133 | 134 | if ( this.materials[ mi ].groupCount <= 0 ) { 135 | 136 | this.materials.splice( mi, 1 ); 137 | 138 | } 139 | 140 | } 141 | 142 | } // Guarantee at least one empty material, this makes the creation later more straight forward. 143 | 144 | 145 | if ( end && this.materials.length === 0 ) { 146 | 147 | this.materials.push( { 148 | name: '', 149 | smooth: this.smooth 150 | } ); 151 | 152 | } 153 | 154 | return lastMultiMaterial; 155 | 156 | } 157 | }; // Inherit previous objects material. 158 | // Spec tells us that a declared material must be set to all objects until a new material is declared. 159 | // If a usemtl declaration is encountered while this new object is being parsed, it will 160 | // overwrite the inherited material. Exception being that there was already face declarations 161 | // to the inherited material, then it will be preserved for proper MultiMaterial continuation. 162 | 163 | if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) { 164 | 165 | const declared = previousMaterial.clone( 0 ); 166 | declared.inherited = true; 167 | this.object.materials.push( declared ); 168 | 169 | } 170 | 171 | this.objects.push( this.object ); 172 | 173 | }, 174 | finalize: function () { 175 | 176 | if ( this.object && typeof this.object._finalize === 'function' ) { 177 | 178 | this.object._finalize( true ); 179 | 180 | } 181 | 182 | }, 183 | parseVertexIndex: function ( value, len ) { 184 | 185 | const index = parseInt( value, 10 ); 186 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; 187 | 188 | }, 189 | parseNormalIndex: function ( value, len ) { 190 | 191 | const index = parseInt( value, 10 ); 192 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; 193 | 194 | }, 195 | parseUVIndex: function ( value, len ) { 196 | 197 | const index = parseInt( value, 10 ); 198 | return ( index >= 0 ? index - 1 : index + len / 2 ) * 2; 199 | 200 | }, 201 | addVertex: function ( a, b, c ) { 202 | 203 | const src = this.vertices; 204 | const dst = this.object.geometry.vertices; 205 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 206 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 207 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 208 | 209 | }, 210 | addVertexPoint: function ( a ) { 211 | 212 | const src = this.vertices; 213 | const dst = this.object.geometry.vertices; 214 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 215 | 216 | }, 217 | addVertexLine: function ( a ) { 218 | 219 | const src = this.vertices; 220 | const dst = this.object.geometry.vertices; 221 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 222 | 223 | }, 224 | addNormal: function ( a, b, c ) { 225 | 226 | const src = this.normals; 227 | const dst = this.object.geometry.normals; 228 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 229 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 230 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 231 | 232 | }, 233 | addFaceNormal: function ( a, b, c ) { 234 | 235 | const src = this.vertices; 236 | const dst = this.object.geometry.normals; 237 | 238 | _vA.fromArray( src, a ); 239 | 240 | _vB.fromArray( src, b ); 241 | 242 | _vC.fromArray( src, c ); 243 | 244 | _cb.subVectors( _vC, _vB ); 245 | 246 | _ab.subVectors( _vA, _vB ); 247 | 248 | _cb.cross( _ab ); 249 | 250 | _cb.normalize(); 251 | 252 | dst.push( _cb.x, _cb.y, _cb.z ); 253 | dst.push( _cb.x, _cb.y, _cb.z ); 254 | dst.push( _cb.x, _cb.y, _cb.z ); 255 | 256 | }, 257 | addColor: function ( a, b, c ) { 258 | 259 | const src = this.colors; 260 | const dst = this.object.geometry.colors; 261 | if ( src[ a ] !== undefined ) dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 262 | if ( src[ b ] !== undefined ) dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 263 | if ( src[ c ] !== undefined ) dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 264 | 265 | }, 266 | addUV: function ( a, b, c ) { 267 | 268 | const src = this.uvs; 269 | const dst = this.object.geometry.uvs; 270 | dst.push( src[ a + 0 ], src[ a + 1 ] ); 271 | dst.push( src[ b + 0 ], src[ b + 1 ] ); 272 | dst.push( src[ c + 0 ], src[ c + 1 ] ); 273 | 274 | }, 275 | addDefaultUV: function () { 276 | 277 | const dst = this.object.geometry.uvs; 278 | dst.push( 0, 0 ); 279 | dst.push( 0, 0 ); 280 | dst.push( 0, 0 ); 281 | 282 | }, 283 | addUVLine: function ( a ) { 284 | 285 | const src = this.uvs; 286 | const dst = this.object.geometry.uvs; 287 | dst.push( src[ a + 0 ], src[ a + 1 ] ); 288 | 289 | }, 290 | addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) { 291 | 292 | const vLen = this.vertices.length; 293 | let ia = this.parseVertexIndex( a, vLen ); 294 | let ib = this.parseVertexIndex( b, vLen ); 295 | let ic = this.parseVertexIndex( c, vLen ); 296 | this.addVertex( ia, ib, ic ); 297 | this.addColor( ia, ib, ic ); // normals 298 | 299 | if ( na !== undefined && na !== '' ) { 300 | 301 | const nLen = this.normals.length; 302 | ia = this.parseNormalIndex( na, nLen ); 303 | ib = this.parseNormalIndex( nb, nLen ); 304 | ic = this.parseNormalIndex( nc, nLen ); 305 | this.addNormal( ia, ib, ic ); 306 | 307 | } else { 308 | 309 | this.addFaceNormal( ia, ib, ic ); 310 | 311 | } // uvs 312 | 313 | 314 | if ( ua !== undefined && ua !== '' ) { 315 | 316 | const uvLen = this.uvs.length; 317 | ia = this.parseUVIndex( ua, uvLen ); 318 | ib = this.parseUVIndex( ub, uvLen ); 319 | ic = this.parseUVIndex( uc, uvLen ); 320 | this.addUV( ia, ib, ic ); 321 | this.object.geometry.hasUVIndices = true; 322 | 323 | } else { 324 | 325 | // add placeholder values (for inconsistent face definitions) 326 | this.addDefaultUV(); 327 | 328 | } 329 | 330 | }, 331 | addPointGeometry: function ( vertices ) { 332 | 333 | this.object.geometry.type = 'Points'; 334 | const vLen = this.vertices.length; 335 | 336 | for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) { 337 | 338 | const index = this.parseVertexIndex( vertices[ vi ], vLen ); 339 | this.addVertexPoint( index ); 340 | this.addColor( index ); 341 | 342 | } 343 | 344 | }, 345 | addLineGeometry: function ( vertices, uvs ) { 346 | 347 | this.object.geometry.type = 'Line'; 348 | const vLen = this.vertices.length; 349 | const uvLen = this.uvs.length; 350 | 351 | for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) { 352 | 353 | this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) ); 354 | 355 | } 356 | 357 | for ( let uvi = 0, l = uvs.length; uvi < l; uvi ++ ) { 358 | 359 | this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) ); 360 | 361 | } 362 | 363 | } 364 | }; 365 | state.startObject( '', false ); 366 | return state; 367 | 368 | } // 369 | 370 | 371 | class OBJLoader extends THREE.Loader { 372 | 373 | constructor( manager ) { 374 | 375 | super( manager ); 376 | this.materials = null; 377 | 378 | } 379 | 380 | load( url, onLoad, onProgress, onError ) { 381 | 382 | const scope = this; 383 | const loader = new THREE.FileLoader( this.manager ); 384 | loader.setPath( this.path ); 385 | loader.setRequestHeader( this.requestHeader ); 386 | loader.setWithCredentials( this.withCredentials ); 387 | loader.load( url, function ( text ) { 388 | 389 | try { 390 | 391 | onLoad( scope.parse( text ) ); 392 | 393 | } catch ( e ) { 394 | 395 | if ( onError ) { 396 | 397 | onError( e ); 398 | 399 | } else { 400 | 401 | console.error( e ); 402 | 403 | } 404 | 405 | scope.manager.itemError( url ); 406 | 407 | } 408 | 409 | }, onProgress, onError ); 410 | 411 | } 412 | 413 | setMaterials( materials ) { 414 | 415 | this.materials = materials; 416 | return this; 417 | 418 | } 419 | 420 | parse( text ) { 421 | 422 | const state = new ParserState(); 423 | 424 | if ( text.indexOf( '\r\n' ) !== - 1 ) { 425 | 426 | // This is faster than String.split with regex that splits on both 427 | text = text.replace( /\r\n/g, '\n' ); 428 | 429 | } 430 | 431 | if ( text.indexOf( '\\\n' ) !== - 1 ) { 432 | 433 | // join lines separated by a line continuation character (\) 434 | text = text.replace( /\\\n/g, '' ); 435 | 436 | } 437 | 438 | const lines = text.split( '\n' ); 439 | let line = '', 440 | lineFirstChar = ''; 441 | let lineLength = 0; 442 | let result = []; // Faster to just trim left side of the line. Use if available. 443 | 444 | const trimLeft = typeof ''.trimLeft === 'function'; 445 | 446 | for ( let i = 0, l = lines.length; i < l; i ++ ) { 447 | 448 | line = lines[ i ]; 449 | line = trimLeft ? line.trimLeft() : line.trim(); 450 | lineLength = line.length; 451 | if ( lineLength === 0 ) continue; 452 | lineFirstChar = line.charAt( 0 ); // @todo invoke passed in handler if any 453 | 454 | if ( lineFirstChar === '#' ) continue; 455 | 456 | if ( lineFirstChar === 'v' ) { 457 | 458 | const data = line.split( /\s+/ ); 459 | 460 | switch ( data[ 0 ] ) { 461 | 462 | case 'v': 463 | state.vertices.push( parseFloat( data[ 1 ] ), parseFloat( data[ 2 ] ), parseFloat( data[ 3 ] ) ); 464 | 465 | if ( data.length >= 7 ) { 466 | 467 | state.colors.push( parseFloat( data[ 4 ] ), parseFloat( data[ 5 ] ), parseFloat( data[ 6 ] ) ); 468 | 469 | } else { 470 | 471 | // if no colors are defined, add placeholders so color and vertex indices match 472 | state.colors.push( undefined, undefined, undefined ); 473 | 474 | } 475 | 476 | break; 477 | 478 | case 'vn': 479 | state.normals.push( parseFloat( data[ 1 ] ), parseFloat( data[ 2 ] ), parseFloat( data[ 3 ] ) ); 480 | break; 481 | 482 | case 'vt': 483 | state.uvs.push( parseFloat( data[ 1 ] ), parseFloat( data[ 2 ] ) ); 484 | break; 485 | 486 | } 487 | 488 | } else if ( lineFirstChar === 'f' ) { 489 | 490 | const lineData = line.substr( 1 ).trim(); 491 | const vertexData = lineData.split( /\s+/ ); 492 | const faceVertices = []; // Parse the face vertex data into an easy to work with format 493 | 494 | for ( let j = 0, jl = vertexData.length; j < jl; j ++ ) { 495 | 496 | const vertex = vertexData[ j ]; 497 | 498 | if ( vertex.length > 0 ) { 499 | 500 | const vertexParts = vertex.split( '/' ); 501 | faceVertices.push( vertexParts ); 502 | 503 | } 504 | 505 | } // Draw an edge between the first vertex and all subsequent vertices to form an n-gon 506 | 507 | 508 | const v1 = faceVertices[ 0 ]; 509 | 510 | for ( let j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) { 511 | 512 | const v2 = faceVertices[ j ]; 513 | const v3 = faceVertices[ j + 1 ]; 514 | state.addFace( v1[ 0 ], v2[ 0 ], v3[ 0 ], v1[ 1 ], v2[ 1 ], v3[ 1 ], v1[ 2 ], v2[ 2 ], v3[ 2 ] ); 515 | 516 | } 517 | 518 | } else if ( lineFirstChar === 'l' ) { 519 | 520 | const lineParts = line.substring( 1 ).trim().split( ' ' ); 521 | let lineVertices = []; 522 | const lineUVs = []; 523 | 524 | if ( line.indexOf( '/' ) === - 1 ) { 525 | 526 | lineVertices = lineParts; 527 | 528 | } else { 529 | 530 | for ( let li = 0, llen = lineParts.length; li < llen; li ++ ) { 531 | 532 | const parts = lineParts[ li ].split( '/' ); 533 | if ( parts[ 0 ] !== '' ) lineVertices.push( parts[ 0 ] ); 534 | if ( parts[ 1 ] !== '' ) lineUVs.push( parts[ 1 ] ); 535 | 536 | } 537 | 538 | } 539 | 540 | state.addLineGeometry( lineVertices, lineUVs ); 541 | 542 | } else if ( lineFirstChar === 'p' ) { 543 | 544 | const lineData = line.substr( 1 ).trim(); 545 | const pointData = lineData.split( ' ' ); 546 | state.addPointGeometry( pointData ); 547 | 548 | } else if ( ( result = _object_pattern.exec( line ) ) !== null ) { 549 | 550 | // o object_name 551 | // or 552 | // g group_name 553 | // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869 554 | // let name = result[ 0 ].substr( 1 ).trim(); 555 | const name = ( ' ' + result[ 0 ].substr( 1 ).trim() ).substr( 1 ); 556 | state.startObject( name ); 557 | 558 | } else if ( _material_use_pattern.test( line ) ) { 559 | 560 | // material 561 | state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries ); 562 | 563 | } else if ( _material_library_pattern.test( line ) ) { 564 | 565 | // mtl file 566 | state.materialLibraries.push( line.substring( 7 ).trim() ); 567 | 568 | } else if ( _map_use_pattern.test( line ) ) { 569 | 570 | // the line is parsed but ignored since the loader assumes textures are defined MTL files 571 | // (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method) 572 | console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' ); 573 | 574 | } else if ( lineFirstChar === 's' ) { 575 | 576 | result = line.split( ' ' ); // smooth shading 577 | // @todo Handle files that have varying smooth values for a set of faces inside one geometry, 578 | // but does not define a usemtl for each face set. 579 | // This should be detected and a dummy material created (later MultiMaterial and geometry groups). 580 | // This requires some care to not create extra material on each smooth value for "normal" obj files. 581 | // where explicit usemtl defines geometry groups. 582 | // Example asset: examples/models/obj/cerberus/Cerberus.obj 583 | 584 | /* 585 | * http://paulbourke.net/dataformats/obj/ 586 | * or 587 | * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf 588 | * 589 | * From chapter "Grouping" Syntax explanation "s group_number": 590 | * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off. 591 | * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form 592 | * surfaces, smoothing groups are either turned on or off; there is no difference between values greater 593 | * than 0." 594 | */ 595 | 596 | if ( result.length > 1 ) { 597 | 598 | const value = result[ 1 ].trim().toLowerCase(); 599 | state.object.smooth = value !== '0' && value !== 'off'; 600 | 601 | } else { 602 | 603 | // ZBrush can produce "s" lines #11707 604 | state.object.smooth = true; 605 | 606 | } 607 | 608 | const material = state.object.currentMaterial(); 609 | if ( material ) material.smooth = state.object.smooth; 610 | 611 | } else { 612 | 613 | // Handle null terminated files without exception 614 | if ( line === '\0' ) continue; 615 | console.warn( 'THREE.OBJLoader: Unexpected line: "' + line + '"' ); 616 | 617 | } 618 | 619 | } 620 | 621 | state.finalize(); 622 | const container = new THREE.Group(); 623 | container.materialLibraries = [].concat( state.materialLibraries ); 624 | const hasPrimitives = ! ( state.objects.length === 1 && state.objects[ 0 ].geometry.vertices.length === 0 ); 625 | 626 | if ( hasPrimitives === true ) { 627 | 628 | for ( let i = 0, l = state.objects.length; i < l; i ++ ) { 629 | 630 | const object = state.objects[ i ]; 631 | const geometry = object.geometry; 632 | const materials = object.materials; 633 | const isLine = geometry.type === 'Line'; 634 | const isPoints = geometry.type === 'Points'; 635 | let hasVertexColors = false; // Skip o/g line declarations that did not follow with any faces 636 | 637 | if ( geometry.vertices.length === 0 ) continue; 638 | const buffergeometry = new THREE.BufferGeometry(); 639 | buffergeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) ); 640 | 641 | if ( geometry.normals.length > 0 ) { 642 | 643 | buffergeometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) ); 644 | 645 | } 646 | 647 | if ( geometry.colors.length > 0 ) { 648 | 649 | hasVertexColors = true; 650 | buffergeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) ); 651 | 652 | } 653 | 654 | if ( geometry.hasUVIndices === true ) { 655 | 656 | buffergeometry.setAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) ); 657 | 658 | } // Create materials 659 | 660 | 661 | const createdMaterials = []; 662 | 663 | for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { 664 | 665 | const sourceMaterial = materials[ mi ]; 666 | const materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_' + hasVertexColors; 667 | let material = state.materials[ materialHash ]; 668 | 669 | if ( this.materials !== null ) { 670 | 671 | material = this.materials.create( sourceMaterial.name ); // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material. 672 | 673 | if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) { 674 | 675 | const materialLine = new THREE.LineBasicMaterial(); 676 | THREE.Material.prototype.copy.call( materialLine, material ); 677 | materialLine.color.copy( material.color ); 678 | material = materialLine; 679 | 680 | } else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) { 681 | 682 | const materialPoints = new THREE.PointsMaterial( { 683 | size: 10, 684 | sizeAttenuation: false 685 | } ); 686 | THREE.Material.prototype.copy.call( materialPoints, material ); 687 | materialPoints.color.copy( material.color ); 688 | materialPoints.map = material.map; 689 | material = materialPoints; 690 | 691 | } 692 | 693 | } 694 | 695 | if ( material === undefined ) { 696 | 697 | if ( isLine ) { 698 | 699 | material = new THREE.LineBasicMaterial(); 700 | 701 | } else if ( isPoints ) { 702 | 703 | material = new THREE.PointsMaterial( { 704 | size: 1, 705 | sizeAttenuation: false 706 | } ); 707 | 708 | } else { 709 | 710 | material = new THREE.MeshPhongMaterial(); 711 | 712 | } 713 | 714 | material.name = sourceMaterial.name; 715 | material.flatShading = sourceMaterial.smooth ? false : true; 716 | material.vertexColors = hasVertexColors; 717 | state.materials[ materialHash ] = material; 718 | 719 | } 720 | 721 | createdMaterials.push( material ); 722 | 723 | } // Create mesh 724 | 725 | 726 | let mesh; 727 | 728 | if ( createdMaterials.length > 1 ) { 729 | 730 | for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { 731 | 732 | const sourceMaterial = materials[ mi ]; 733 | buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi ); 734 | 735 | } 736 | 737 | if ( isLine ) { 738 | 739 | mesh = new THREE.LineSegments( buffergeometry, createdMaterials ); 740 | 741 | } else if ( isPoints ) { 742 | 743 | mesh = new THREE.Points( buffergeometry, createdMaterials ); 744 | 745 | } else { 746 | 747 | mesh = new THREE.Mesh( buffergeometry, createdMaterials ); 748 | 749 | } 750 | 751 | } else { 752 | 753 | if ( isLine ) { 754 | 755 | mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ); 756 | 757 | } else if ( isPoints ) { 758 | 759 | mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] ); 760 | 761 | } else { 762 | 763 | mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ); 764 | 765 | } 766 | 767 | } 768 | 769 | mesh.name = object.name; 770 | container.add( mesh ); 771 | 772 | } 773 | 774 | } else { 775 | 776 | // if there is only the default parser state object with no geometry data, interpret data as point cloud 777 | if ( state.vertices.length > 0 ) { 778 | 779 | const material = new THREE.PointsMaterial( { 780 | size: 1, 781 | sizeAttenuation: false 782 | } ); 783 | const buffergeometry = new THREE.BufferGeometry(); 784 | buffergeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( state.vertices, 3 ) ); 785 | 786 | if ( state.colors.length > 0 && state.colors[ 0 ] !== undefined ) { 787 | 788 | buffergeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( state.colors, 3 ) ); 789 | material.vertexColors = true; 790 | 791 | } 792 | 793 | const points = new THREE.Points( buffergeometry, material ); 794 | container.add( points ); 795 | 796 | } 797 | 798 | } 799 | 800 | return container; 801 | 802 | } 803 | 804 | } 805 | 806 | THREE.OBJLoader = OBJLoader; 807 | 808 | } )(); 809 | -------------------------------------------------------------------------------- /Star-Love/homepage.php: -------------------------------------------------------------------------------- 1 | need('base/head.php'); 9 | ?> 10 |
11 |
12 |
13 |
14 |

...

15 |
16 |
17 |

options->description(); ?>

18 |

我们已相识

19 |

我们已相恋

20 |

距离上一次见面已过去

21 |

👉🏻点击抽签

22 |
23 |
24 |
25 |
26 | 87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 206 | need('base/footer.php'); ?> -------------------------------------------------------------------------------- /Star-Love/core/shortcodes.php: -------------------------------------------------------------------------------- 1 | &/\[\]\x00-\x20=]@', $tag ) ) { 73 | /* translators: 1: Shortcode name, 2: Space-separated list of reserved characters. */ 74 | $message = sprintf( __( 'Invalid shortcode name: %1$s. Do not use spaces or reserved characters: %2$s' ), $tag, '& / < > [ ] =' ); 75 | _doing_it_wrong( __FUNCTION__, $message, '4.4.0' ); 76 | return; 77 | } 78 | 79 | $shortcode_tags[ $tag ] = $callback; 80 | } 81 | 82 | /** 83 | * Removes hook for shortcode. 84 | * 85 | * @since 2.5.0 86 | * 87 | * @global array $shortcode_tags 88 | * 89 | * @param string $tag Shortcode tag to remove hook for. 90 | */ 91 | function remove_shortcode( $tag ) { 92 | global $shortcode_tags; 93 | 94 | unset( $shortcode_tags[ $tag ] ); 95 | } 96 | 97 | /** 98 | * Clear all shortcodes. 99 | * 100 | * This function is simple, it clears all of the shortcode tags by replacing the 101 | * shortcodes global by a empty array. This is actually a very efficient method 102 | * for removing all shortcodes. 103 | * 104 | * @since 2.5.0 105 | * 106 | * @global array $shortcode_tags 107 | */ 108 | function remove_all_shortcodes() { 109 | global $shortcode_tags; 110 | 111 | $shortcode_tags = array(); 112 | } 113 | 114 | /** 115 | * Whether a registered shortcode exists named $tag 116 | * 117 | * @since 3.6.0 118 | * 119 | * @global array $shortcode_tags List of shortcode tags and their callback hooks. 120 | * 121 | * @param string $tag Shortcode tag to check. 122 | * @return bool Whether the given shortcode exists. 123 | */ 124 | function shortcode_exists( $tag ) { 125 | global $shortcode_tags; 126 | return array_key_exists( $tag, $shortcode_tags ); 127 | } 128 | 129 | /** 130 | * Whether the passed content contains the specified shortcode 131 | * 132 | * @since 3.6.0 133 | * 134 | * @global array $shortcode_tags 135 | * 136 | * @param string $content Content to search for shortcodes. 137 | * @param string $tag Shortcode tag to check. 138 | * @return bool Whether the passed content contains the given shortcode. 139 | */ 140 | function has_shortcode( $content, $tag ) { 141 | if ( false === strpos( $content, '[' ) ) { 142 | return false; 143 | } 144 | 145 | if ( shortcode_exists( $tag ) ) { 146 | preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); 147 | if ( empty( $matches ) ) { 148 | return false; 149 | } 150 | 151 | foreach ( $matches as $shortcode ) { 152 | if ( $tag === $shortcode[2] ) { 153 | return true; 154 | } elseif ( ! empty( $shortcode[5] ) && has_shortcode( $shortcode[5], $tag ) ) { 155 | return true; 156 | } 157 | } 158 | } 159 | return false; 160 | } 161 | 162 | /** 163 | * Search content for shortcodes and filter shortcodes through their hooks. 164 | * 165 | * This function is an alias for do_shortcode(). 166 | * 167 | * @since 5.4.0 168 | * 169 | * @see do_shortcode() 170 | * 171 | * @param string $content Content to search for shortcodes. 172 | * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. 173 | * Default false. 174 | * @return string Content with shortcodes filtered out. 175 | */ 176 | function apply_shortcodes( $content, $ignore_html = false ) { 177 | return do_shortcode( $content, $ignore_html ); 178 | } 179 | 180 | /** 181 | * Search content for shortcodes and filter shortcodes through their hooks. 182 | * 183 | * If there are no shortcode tags defined, then the content will be returned 184 | * without any filtering. This might cause issues when plugins are disabled but 185 | * the shortcode will still show up in the post or content. 186 | * 187 | * @since 2.5.0 188 | * 189 | * @global array $shortcode_tags List of shortcode tags and their callback hooks. 190 | * 191 | * @param string $content Content to search for shortcodes. 192 | * @param bool $ignore_html When true, shortcodes inside HTML elements will be skipped. 193 | * Default false. 194 | * @return string Content with shortcodes filtered out. 195 | */ 196 | function do_shortcode( $content, $ignore_html = false ) { 197 | global $shortcode_tags; 198 | 199 | if ( false === strpos( $content, '[' ) ) { 200 | return $content; 201 | } 202 | 203 | if ( empty( $shortcode_tags ) || ! is_array( $shortcode_tags ) ) { 204 | return $content; 205 | } 206 | 207 | // Find all registered tag names in $content. 208 | preg_match_all( '@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches ); 209 | $tagnames = array_intersect( array_keys( $shortcode_tags ), $matches[1] ); 210 | 211 | if ( empty( $tagnames ) ) { 212 | return $content; 213 | } 214 | 215 | $content = do_shortcodes_in_html_tags( $content, $ignore_html, $tagnames ); 216 | 217 | $pattern = get_shortcode_regex( $tagnames ); 218 | $content = preg_replace_callback( "/$pattern/", 'do_shortcode_tag', $content ); 219 | 220 | // Always restore square braces so we don't break things like is found. 680 | . '-(?!->)' // Dash not followed by end of comment. 681 | . '[^\-]*+' // Consume non-dashes. 682 | . ')*+' // Loop possessively. 683 | . '(?:-->)?'; // End of comment. If not found, match all input. 684 | 685 | $cdata = 686 | '!\[CDATA\[' // Start of comment, after the <. 687 | . '[^\]]*+' // Consume non-]. 688 | . '(?:' // Unroll the loop: Consume everything until ]]> is found. 689 | . '](?!]>)' // One ] not followed by end of comment. 690 | . '[^\]]*+' // Consume non-]. 691 | . ')*+' // Loop possessively. 692 | . '(?:]]>)?'; // End of comment. If not found, match all input. 693 | 694 | $escaped = 695 | '(?=' // Is the element escaped? 696 | . '!--' 697 | . '|' 698 | . '!\[CDATA\[' 699 | . ')' 700 | . '(?(?=!-)' // If yes, which type? 701 | . $comments 702 | . '|' 703 | . $cdata 704 | . ')'; 705 | 706 | $regex = 707 | '/(' // Capture the entire match. 708 | . '<' // Find start of element. 709 | . '(?' // Conditional expression follows. 710 | . $escaped // Find end of escaped element. 711 | . '|' // ...else... 712 | . '[^>]*>?' // Find end of normal element. 713 | . ')' 714 | . ')/'; 715 | // phpcs:enable 716 | } 717 | 718 | return $regex; 719 | } 720 | function apply_filters( $tag, $value ) { 721 | global $wp_filter, $wp_current_filter; 722 | 723 | $args = func_get_args(); 724 | 725 | // Do 'all' actions first. 726 | // if ( isset( $wp_filter['all'] ) ) { 727 | // $wp_current_filter[] = $tag; 728 | // _wp_call_all_hook( $args ); 729 | // } 730 | 731 | if ( ! isset( $wp_filter[ $tag ] ) ) { 732 | if ( isset( $wp_filter['all'] ) ) { 733 | array_pop( $wp_current_filter ); 734 | } 735 | return $value; 736 | } 737 | 738 | if ( ! isset( $wp_filter['all'] ) ) { 739 | $wp_current_filter[] = $tag; 740 | } 741 | 742 | // Don't pass the tag name to WP_Hook. 743 | array_shift( $args ); 744 | 745 | $filtered = $wp_filter[ $tag ]->apply_filters( $value, $args ); 746 | 747 | array_pop( $wp_current_filter ); 748 | 749 | return $filtered; 750 | } --------------------------------------------------------------------------------