Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テクスチャ</title>
</head>
<body>
  <div class="conf">
<table color="white">
<tr>
<td>degrees</td><td><input type="range" value="0" min="0" max="360" id="degrees" ui="Slider" onchange="showValue(this,this.value)"/></td><td><span id="degreesDisp">0</span></td>
</tr>
</table>
</div>
<canvas id="mycanvas" width="600" height="400"></canvas>
</body>
</html>

              
            
!

CSS

              
                
              
            
!

JS

              
                var frame = 0;
var marks = [];
var dragFlag = false;
var markNo;
var move = new Point();
var vertexs = [];
var ct = new Point();
var offset = {x: 100, y:100};

function Point(x, y) {
    this.x = x;
    this.y = y;
}

//テクスチャオブジェクト定義
var texture = [/*{
	x : 0,
	y : 0,
	width : 0,
	height : 0,
	image : undefined,
}, ...*/];

//マークオブジェクト定義
var mark = function(x, y,size,color){
	this.x = x;
	this.y = y;
	this.size = size;
	this.color = color;
}

//マーク描画処理
mark.prototype.draw = function() {
	var ctx = cvs.ctx;

	ctx.beginPath();
	ctx.fillStyle = this.color;
	ctx.arc(this.x, this.y, this.size, 0, Math.PI*2, false);
	ctx.fill();

	ctx.beginPath();
	ctx.moveTo(this.x - this.size, this.y);
	ctx.lineTo(this.x + this.size, this.y);
	ctx.moveTo(this.x, this.y - this.size);
	ctx.lineTo(this.x, this.y + this.size);
	ctx.strokeStyle = "black";
	ctx.stroke();
}

//衝突判定
//円 : 中心点C(xc, yc)、半径r
//点 : P(xp, yp)
//(xp-xc)^2 + (yp-yc)^2 ≦ r^2ならば衝突している
mark.prototype.isHit = function(xp,yp) {
	var a, b, d,r;

	r = this.size;
	a = xp - this.x;
	b = yp - this.y;
	d = a * a + b * b;

	return (d <= r*r);
}

var cvs = {
	// canvas element
	'elem' : undefined,
	// canvas width(window max)
	'width' : 0,
	// canvas width(window height)
	'height' : 0,
	// 2d context
	'ctx' : undefined,
	// element offset(left)
	'left' : 0,
	// element offset(top)
	'top' : 0,
	// explode point(x)
	'pos_x' : 0,
	// explode point(y)
	'pos_y' : 0
}

//キャンバス初期化
function init () {
	cvs.elem = document.getElementById('mycanvas');
	if (!cvs.elem || !cvs.elem.getContext) {
		return alert('require canvas support');
	}
	(function () {
		var b = document.body;
		var d = document.documentElement;
		cvs.width = Math.max(b.clientWidth , b.scrollWidth, d.scrollWidth, d.clientWidth);
		cvs.height = Math.max(b.clientHeight , b.scrollHeight, d.scrollHeight, d.clientHeight);
	})();
	cvs.elem.height = cvs.height;
	cvs.elem.width = cvs.width;
	cvs.ctx = cvs.elem.getContext('2d');
	cvs.left = cvs.elem.getBoundingClientRect
		? cvs.elem.getBoundingClientRect().left
		: 0
		;
	cvs.top = cvs.elem.getBoundingClientRect
		? cvs.elem.getBoundingClientRect().top
		: 0
		;
}

//ロード時
onload = function () {
	init();

	var canvas = cvs.elem;

	//イベント:マウスダウン
	canvas.onmousedown = mouseDownListner;
	function mouseDownListner(e) {
		var x;
		var y;
		
		getMouseXY(e);
		dragFlag = true;
		markNo = -1;
		for(var i=0; i<marks.length; i++){
			if(marks[i].isHit(mouseX,mouseY)){
				markNo = i;
				//マウスダウンした位置を差分として退避
				move.x = marks[i].x - mouseX;
				move.y = marks[i].y - mouseY;
				break;
			}
		}
		
		//return falseは、canvas上でmousedownした後カーソルが「cursor:text」の形状に
		//なるのを回避するためです。
		return false;
	}

	//イベント:マウス移動
	canvas.onmousemove = mouseMoveListner;
	function mouseMoveListner(e) {

		getMouseXY(e);
		if(dragFlag != false) {
			if(markNo != -1) {
				//マーク移動
				marks[markNo].x = mouseX + move.x;
				marks[markNo].y = mouseY + move.y;
				marks[markNo].draw();
			}
		}
		else{
			//マーク範囲内かチェック
			for(var i=0; i<marks.length; i++){
				if(marks[i].isHit(mouseX,mouseY)){
					break;
				}
			}
		}
	}

	//イベント:マウスアップ
	canvas.onmouseup = mouseUpListner;
	function mouseUpListner(e) {
		dragFlag = false;
		markNo = -1;
	}

	//イベント:マウスアウト
	canvas.onmouseout = mouseOutListner;
	function mouseOutListner(e) {
		dragFlag = false;
		markNo = -1;
	}

	//マウス座標
	function getMouseXY(e) {
		var rect = e.target.getBoundingClientRect();
		mouseX = e.clientX- rect.left;
		mouseY = e.clientY- rect.top;
	}

	//テクスチャ初期化
	texture.image = new Image();
	texture.image.src = "https://drive.google.com/uc?export=view&id=1TKuNlr51kMHnCNboO4VAyuW4LAHD7QCS";
	texture.image.onload = function() {
		texture.width = texture.image.width;
		texture.height = texture.image.height;
		cvs.ctx.drawImage(texture.image, texture.x, texture.y);
		var w = texture.width;
		var h = texture.height;

		//マーク初期化
		initMark();
		
		setInterval(loop,50);
	}
}

//マーク初期化
function initMark(){

	var obj;
	var sx = offset.x;
	var sy = offset.y;
	var r = 10;

	// 1  2
	// 4  3

	//制御点1
	obj = new mark(sx , sy, r,'red');
	marks.push(obj);
	//制御点2
	obj = new mark(texture.width + sx, sy, r,'red');
	marks.push(obj);
	//制御点3
	obj = new mark(texture.width + sx, texture.height + sy, r,'red');
	marks.push(obj);
	//制御点4
	obj = new mark(sx, texture.height + sy ,r ,'red');
	marks.push(obj);

	//中心点
	ct = new Point(texture.width / 2, texture.height / 2);
	//回転用に各制御点の中心点との差をセット
	obj = new Point(-ct.x, -ct.y);
	vertexs.push(obj);
	obj = new Point( ct.x ,-ct.y);
	vertexs.push(obj);
	obj = new Point( ct.x,  ct.y);
	vertexs.push(obj);
	obj = new Point(-ct.x,  ct.y);
	vertexs.push(obj);
}

function rotate2d(x, y, rad) {
    var p = new Point;
    p.x =  Math.cos(rad) * x - Math.sin(rad) * y;
    p.y =  Math.sin(rad) * x + Math.cos(rad) * y;

    return p;
}

//マーク描画
function drawMark(){

	for(var i=0; i<marks.length; i++){
		marks[i].draw();
	}
}

//座標情報描画
function drawInfo(){

	var ctx = cvs.ctx;
	ctx.fillStyle = "black";
	for(var i=0; i<marks.length; i++){
		ctx.fillText('制御点' + (i+1) + ' (' + marks[i].x + ',' + marks[i].y + ')' , 10, (i+2)*10);
	}
}

//単位行列
// |a,b| |_11,_12|
// |c,d| |_21,_22|
function M22()
{
	this._11 = 1;
	this._12 = 0;
	this._21 = 0;
	this._22 = 1;
}

//逆行列取得
M22.prototype.getInvert = function()
{
	var out = new M22();
	//逆行列の公式 ad - bc の部分
	var det = this._11 * this._22 - this._12 * this._21;
	if (det > -0.0001 && det < 0.0001)
		return null;

	//逆行列の公式 det=(ad - bc) で各値(a,b,c,d)を割る
	out._11 = this._22 / det;
	out._22 = this._11 / det;

	out._12 = -this._12 / det;
	out._21 = -this._21 / det;

	return out;
}

//三角形テクスチャ描画
function drawTriangle(g, img, vertex_list, uv_list)
{
	var _Ax = vertex_list[2] - vertex_list[0];
	var _Ay = vertex_list[3] - vertex_list[1];
	var _Bx = vertex_list[4] - vertex_list[0];
	var _By = vertex_list[5] - vertex_list[1];

	var Ax = (uv_list[2] - uv_list[0]) * img.width;
	var Ay = (uv_list[3] - uv_list[1]) * img.height;
	var Bx = (uv_list[4] - uv_list[0]) * img.width;
	var By = (uv_list[5] - uv_list[1]) * img.height;

	//逆行列を求める
	var m = new M22();
	m._11 = Ax;
	m._12 = Ay;
	m._21 = Bx;
	m._22 = By;
	var mi = m.getInvert();
	if (!mi) return;

	//マトリックス変換値を求める
	var a, b, c, d;
	a = mi._11 * _Ax + mi._12 * _Bx;
	c = mi._21 * _Ax + mi._22 * _Bx;

	b = mi._11 * _Ay + mi._12 * _By;
	d = mi._21 * _Ay + mi._22 * _By;

	g.save();
	g.beginPath();
	g.moveTo(vertex_list[0], vertex_list[1]);
	g.lineTo(vertex_list[2], vertex_list[3]);
	g.lineTo(vertex_list[4], vertex_list[5]);
	g.clip();	//三角形に切り取る

	g.transform(a, b, c, d,
		vertex_list[0] - (a * uv_list[0] * img.width + c * uv_list[1] * img.height),
		vertex_list[1] - (b * uv_list[0] * img.width + d * uv_list[1] * img.height));
	g.drawImage(img, 0, 0);
	g.restore();
}

//テクスチャ描画
function drawTexture(){

	var ctx = cvs.ctx;
	drawTriangle(ctx, texture.image, 
		[
		 marks[0].x, marks[0].y,
		 marks[1].x, marks[1].y,
		 marks[3].x, marks[3].y
		],
		[
		 0, 0,
		 1, 0,
		 0, 1
		]
	);

	drawTriangle(ctx, texture.image,
		[
		 marks[3].x, marks[3].y,
		 marks[2].x, marks[2].y,
		 marks[1].x, marks[1].y,
		],
		[
		 0, 1,
		 1, 1,
		 1, 0
		]
	);
}

//フレーム処理
function render(){

	cvs.ctx.clearRect(0, 0, cvs.width, cvs.height);

	drawTexture();
	drawMark();
	drawInfo();
}

//フレーム処理
function loop(){
	render();
}

function showValue(obj,newValue) {

	document.getElementById(obj.id + "Disp").innerHTML = newValue;
	switch(obj.id){
		case "degrees" :
			var degrees = newValue;
			var rad = -degrees / 180 * Math.PI;
			for(var i=0; i<marks.length; i++){
				var pt = rotate2d(vertexs[i].x, vertexs[i].y , rad);
				marks[i].x =  pt.x + offset.x + ct.x;
				marks[i].y =  pt.y + offset.y + ct.y;
			}
			break;
	}

    render();
}

              
            
!
999px

Console