forked from akira-cn/graphics
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
1,094 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import {Vector2D} from '../common/lib/vector2d.js'; | ||
|
||
const canvas = document.querySelector('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
const {width, height} = canvas; | ||
const w = 0.5 * width, | ||
h = 0.5 * height; | ||
ctx.translate(w, h); | ||
ctx.scale(1, -1); | ||
|
||
function draw(context, points, { | ||
fillStyle = 'black', | ||
close = false, | ||
rule = 'nonzero', | ||
} = {}) { | ||
context.beginPath(); | ||
context.moveTo(...points[0]); | ||
for(let i = 1; i < points.length; i++) { | ||
context.lineTo(...points[i]); | ||
} | ||
if(close) context.closePath(); | ||
context.fillStyle = fillStyle; | ||
context.fill(rule); | ||
} | ||
|
||
const points = [new Vector2D(0, 100)]; | ||
for(let i = 1; i <= 4; i++) { | ||
const p = points[0].copy().rotate(i * Math.PI * 0.4); | ||
points.push(p); | ||
} | ||
|
||
const polygon = [ | ||
...points, | ||
]; | ||
|
||
ctx.save(); | ||
ctx.translate(-128, 0); | ||
draw(ctx, polygon); | ||
ctx.restore(); | ||
|
||
const stars = [ | ||
points[0], | ||
points[2], | ||
points[4], | ||
points[1], | ||
points[3], | ||
]; | ||
|
||
ctx.save(); | ||
ctx.translate(128, 0); | ||
// draw(ctx, stars); | ||
draw(ctx, stars, {rule: 'evenodd'}); | ||
ctx.restore(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Canvas2D填充</title> | ||
</head> | ||
<body> | ||
<canvas width="512" height="512"></canvas> | ||
<script type="module" src="./app.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import {earcut} from '../common/lib/earcut.js'; | ||
import {Vector2D} from '../common/lib/vector2d.js'; | ||
|
||
function inTriangle(p1, p2, p3, point) { | ||
const a = p2.copy().sub(p1); | ||
const b = p3.copy().sub(p2); | ||
const c = p1.copy().sub(p3); | ||
|
||
const u1 = point.copy().sub(p1); | ||
const u2 = point.copy().sub(p2); | ||
const u3 = point.copy().sub(p3); | ||
|
||
const s1 = Math.sign(a.cross(u1)); | ||
let p = a.dot(u1) / a.length ** 2; | ||
if(s1 === 0 && p >= 0 && p <= 1) return true; | ||
|
||
const s2 = Math.sign(b.cross(u2)); | ||
p = b.dot(u1) / b.length ** 2; | ||
if(s2 === 0 && p >= 0 && p <= 1) return true; | ||
|
||
const s3 = Math.sign(c.cross(u3)); | ||
p = c.dot(u1) / c.length ** 2; | ||
if(s3 === 0 && p >= 0 && p <= 1) return true; | ||
|
||
return s1 === s2 && s2 === s3; | ||
} | ||
|
||
function isPointInPath({vertices, cells}, point) { | ||
let ret = false; | ||
for(let i = 0; i < cells.length; i += 3) { | ||
const p1 = new Vector2D(...vertices[cells[i]]); | ||
const p2 = new Vector2D(...vertices[cells[i + 1]]); | ||
const p3 = new Vector2D(...vertices[cells[i + 2]]); | ||
if(inTriangle(p1, p2, p3, point)) { | ||
ret = true; | ||
break; | ||
} | ||
} | ||
return ret; | ||
} | ||
|
||
const canvas = document.querySelector('canvas'); | ||
const gl = canvas.getContext('webgl'); | ||
|
||
const vertex = ` | ||
attribute vec2 position; | ||
uniform vec4 u_color; | ||
varying vec4 vColor; | ||
void main() { | ||
gl_PointSize = 1.0; | ||
gl_Position = vec4(position, 1.0, 1.0); | ||
vColor = u_color; | ||
} | ||
`; | ||
|
||
const fragment = ` | ||
precision mediump float; | ||
varying vec4 vColor; | ||
void main() | ||
{ | ||
gl_FragColor = vColor; | ||
} | ||
`; | ||
|
||
const vertexShader = gl.createShader(gl.VERTEX_SHADER); | ||
gl.shaderSource(vertexShader, vertex); | ||
gl.compileShader(vertexShader); | ||
|
||
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); | ||
gl.shaderSource(fragmentShader, fragment); | ||
gl.compileShader(fragmentShader); | ||
|
||
|
||
const program = gl.createProgram(); | ||
gl.attachShader(program, vertexShader); | ||
gl.attachShader(program, fragmentShader); | ||
gl.linkProgram(program); | ||
gl.useProgram(program); | ||
|
||
const vertices = [ | ||
[-0.7, 0.5], | ||
[-0.4, 0.3], | ||
[-0.25, 0.71], | ||
[-0.1, 0.56], | ||
[-0.1, 0.13], | ||
[0.4, 0.21], | ||
[0, -0.6], | ||
[-0.3, -0.3], | ||
[-0.6, -0.3], | ||
[-0.45, 0.0], | ||
]; | ||
|
||
const points = vertices.flat(); | ||
const triangles = earcut(points); | ||
// console.log(triangles); | ||
|
||
const position = new Float32Array(points); | ||
const cells = new Uint16Array(triangles); | ||
|
||
const pointBuffer = gl.createBuffer(); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, pointBuffer); | ||
gl.bufferData(gl.ARRAY_BUFFER, position, gl.STATIC_DRAW); | ||
|
||
const vPosition = gl.getAttribLocation(program, 'position'); | ||
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0); | ||
gl.enableVertexAttribArray(vPosition); | ||
|
||
const cellsBuffer = gl.createBuffer(); | ||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cellsBuffer); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, cells, gl.STATIC_DRAW); | ||
|
||
const colorLoc = gl.getUniformLocation(program, 'u_color'); | ||
gl.uniform4fv(colorLoc, [1, 0, 0, 1]); | ||
|
||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
gl.drawElements(gl.TRIANGLES, cells.length, gl.UNSIGNED_SHORT, 0); | ||
|
||
const {left, top} = canvas.getBoundingClientRect(); | ||
canvas.addEventListener('mousemove', (evt) => { | ||
const {x, y} = evt; | ||
// 坐标转换 | ||
const offsetX = 2 * (x - left) / canvas.width - 1.0; | ||
const offsetY = 1.0 - 2 * (y - top) / canvas.height; | ||
|
||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
|
||
const colorLoc = gl.getUniformLocation(program, 'u_color'); | ||
if(isPointInPath({vertices, cells}, new Vector2D(offsetX, offsetY))) { | ||
gl.uniform4fv(colorLoc, [0, 0.5, 0, 1]); | ||
} else { | ||
gl.uniform4fv(colorLoc, [1, 0, 0, 1]); | ||
} | ||
|
||
gl.drawElements(gl.TRIANGLES, cells.length, gl.UNSIGNED_SHORT, 0); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import {earcut} from '../common/lib/earcut.js'; | ||
|
||
const canvas = document.querySelector('canvas'); | ||
const gl = canvas.getContext('webgl'); | ||
|
||
const vertex = ` | ||
attribute vec2 position; | ||
void main() { | ||
gl_PointSize = 1.0; | ||
gl_Position = vec4(position, 1.0, 1.0); | ||
} | ||
`; | ||
|
||
const fragment = ` | ||
precision mediump float; | ||
void main() | ||
{ | ||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); | ||
} | ||
`; | ||
|
||
const vertexShader = gl.createShader(gl.VERTEX_SHADER); | ||
gl.shaderSource(vertexShader, vertex); | ||
gl.compileShader(vertexShader); | ||
|
||
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); | ||
gl.shaderSource(fragmentShader, fragment); | ||
gl.compileShader(fragmentShader); | ||
|
||
|
||
const program = gl.createProgram(); | ||
gl.attachShader(program, vertexShader); | ||
gl.attachShader(program, fragmentShader); | ||
gl.linkProgram(program); | ||
gl.useProgram(program); | ||
|
||
// const points = new Float32Array([ | ||
// -1, -1, | ||
// 0, 1, | ||
// 1, -1, | ||
// ]); | ||
|
||
const vertices = [ | ||
[-0.7, 0.5], | ||
[-0.4, 0.3], | ||
[-0.25, 0.71], | ||
[-0.1, 0.56], | ||
[-0.1, 0.13], | ||
[0.4, 0.21], | ||
[0, -0.6], | ||
[-0.3, -0.3], | ||
[-0.6, -0.3], | ||
[-0.45, 0.0], | ||
]; | ||
|
||
const points = vertices.flat(); | ||
const triangles = earcut(points); | ||
// console.log(triangles); | ||
|
||
const position = new Float32Array(points); | ||
const cells = new Uint16Array(triangles); | ||
|
||
const pointBuffer = gl.createBuffer(); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, pointBuffer); | ||
gl.bufferData(gl.ARRAY_BUFFER, position, gl.STATIC_DRAW); | ||
|
||
const vPosition = gl.getAttribLocation(program, 'position'); | ||
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0); | ||
gl.enableVertexAttribArray(vPosition); | ||
|
||
const cellsBuffer = gl.createBuffer(); | ||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cellsBuffer); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, cells, gl.STATIC_DRAW); | ||
|
||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
gl.drawElements(gl.LINE_STRIP, cells.length, gl.UNSIGNED_SHORT, 0); | ||
|
||
// const canvas = document.querySelector('canvas'); | ||
// const ctx = canvas.getContext('2d'); | ||
// const {width, height} = canvas; | ||
// ctx.translate(0.5 * width, 0.5 * height); | ||
// ctx.scale(1, -1); | ||
|
||
// const poitions = vertices.map(([x, y]) => [x * 256, y * 256]); | ||
|
||
// function draw(points, strokeStyle = 'black', fillStyle = null) { | ||
// ctx.strokeStyle = strokeStyle; | ||
// ctx.beginPath(); | ||
// ctx.moveTo(...points[0]); | ||
// for(let i = 1; i < points.length; i++) { | ||
// ctx.lineTo(...points[i]); | ||
// } | ||
// ctx.closePath(); | ||
// if(fillStyle) { | ||
// ctx.fillStyle = fillStyle; | ||
// ctx.fill(); | ||
// } | ||
// ctx.stroke(); | ||
// } | ||
|
||
// draw(poitions); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const vertices = [ | ||
[-0.7, 0.5], | ||
[-0.4, 0.3], | ||
[-0.25, 0.71], | ||
[-0.1, 0.56], | ||
[-0.1, 0.13], | ||
[0.4, 0.21], | ||
[0, -0.6], | ||
[-0.3, -0.3], | ||
[-0.6, -0.3], | ||
[-0.45, 0.0], | ||
]; | ||
|
||
const canvas = document.querySelector('canvas'); | ||
const ctx = canvas.getContext('2d'); | ||
const {width, height} = canvas; | ||
ctx.translate(0.5 * width, 0.5 * height); | ||
ctx.scale(1, -1); | ||
|
||
const poitions = vertices.map(([x, y]) => [x * 256, y * 256]); | ||
|
||
function draw(ctx, points, strokeStyle = 'black', fillStyle = null) { | ||
ctx.strokeStyle = strokeStyle; | ||
ctx.beginPath(); | ||
ctx.moveTo(...points[0]); | ||
for(let i = 1; i < points.length; i++) { | ||
ctx.lineTo(...points[i]); | ||
} | ||
ctx.closePath(); | ||
if(fillStyle) { | ||
ctx.fillStyle = fillStyle; | ||
ctx.fill(); | ||
} | ||
ctx.stroke(); | ||
} | ||
|
||
function isPointInPath(ctx, x, y) { | ||
const cloned = ctx.canvas.cloneNode().getContext('2d'); | ||
cloned.translate(0.5 * width, 0.5 * height); | ||
cloned.scale(1, -1); | ||
let ret = false; | ||
draw(cloned, poitions, 'transparent', 'red'); | ||
ret |= cloned.isPointInPath(x, y); | ||
if(!ret) { | ||
draw(cloned, [[100, 100], [100, 200], [150, 200]], 'transparent', 'blue'); | ||
ret |= cloned.isPointInPath(x, y); | ||
} | ||
return ret; | ||
} | ||
|
||
draw(ctx, poitions, 'transparent', 'red'); | ||
draw(ctx, [[100, 100], [100, 200], [150, 200]], 'transparent', 'blue'); | ||
|
||
const {left, top} = canvas.getBoundingClientRect(); | ||
|
||
canvas.addEventListener('mousemove', (evt) => { | ||
const {x, y} = evt; | ||
// 坐标转换 | ||
const offsetX = x - left; | ||
const offsetY = y - top; | ||
|
||
ctx.clearRect(-256, -256, 512, 512); | ||
|
||
if(isPointInPath(ctx, offsetX, offsetY)) { | ||
draw(ctx, poitions, 'transparent', 'green'); | ||
draw(ctx, [[100, 100], [100, 200], [150, 200]], 'transparent', 'orange'); | ||
} else { | ||
draw(ctx, poitions, 'transparent', 'red'); | ||
draw(ctx, [[100, 100], [100, 200], [150, 200]], 'transparent', 'blue'); | ||
} | ||
}); |
Oops, something went wrong.