Skip to content

Commit

Permalink
#154 グラデーションの描画処理を改修
Browse files Browse the repository at this point in the history
  • Loading branch information
ienaga committed Dec 18, 2024
1 parent 4750ffc commit a79c3e0
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 150 deletions.
28 changes: 14 additions & 14 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@
<script>
window.addEventListener("DOMContentLoaded", async () =>
{
// next2d.load("develop");
const { Sprite, Shape } = next2d.display;
const root = await next2d.createRootMovieClip(480, 480, 1);
const shape = root.addChild(new Shape());
shape.x = 75;
shape.y = 75;
shape
.graphics
.beginFill(0x0000ff)
// // 半時計回り
.moveTo(75, 75).curveTo(65, 60, 75, 50).curveTo(60, 60, 50, 50).curveTo(60, 60, 50, 75).curveTo(60, 60, 75, 75)
// // // 時計回り
// // .moveTo(0, 0).curveTo(50, 25, 100, 0).curveTo(70, 50, 100, 100).curveTo(50, 50, 0, 100).curveTo(20, 50, 0, 0)
.endFill()
next2d.load("develop");
// const { Sprite, Shape } = next2d.display;
// const root = await next2d.createRootMovieClip(480, 480, 1);
// const shape = root.addChild(new Shape());
// shape.x = 75;
// shape.y = 75;
// shape
// .graphics
// .beginFill(0x0000ff)
// // // 半時計回り
// .moveTo(75, 75).curveTo(65, 60, 75, 50).curveTo(60, 60, 50, 50).curveTo(60, 60, 50, 75).curveTo(60, 60, 75, 75)
// // // // 時計回り
// // // .moveTo(0, 0).curveTo(50, 25, 100, 0).curveTo(70, 50, 100, 100).curveTo(50, 50, 0, 100).curveTo(20, 50, 0, 0)
// .endFill()
// // non-zero
// // .beginFill(0x00ff00)
// // .moveTo(75, 75).curveTo(170, 30, 75, 50).curveTo(50, 10, 50, 50).curveTo(95, 25+35/2, 50, 75).lineTo(75, 75)
Expand Down
6 changes: 3 additions & 3 deletions packages/webgl/src/Context/usecase/ContextClipUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const execute = (): void =>
const useGrid = !!gridData;

if ($context.containerClip) {
$gl.stencilMask(1 << (level - 1));
$gl.stencilMask(1 << level - 1);
}

const shaderManager = variantsShapeMaskShaderService(false, useGrid);
Expand Down Expand Up @@ -95,7 +95,7 @@ export const execute = (): void =>
// 比較して 00001000 以上であれば 00001*** で更新し、そうでなければ 00000*** で更新する。
// 下位3ビットは元の値を保持する必要があるので 11111000 でマスクする。

const mask = 1 << (level - 1);
const mask = 1 << level - 1;
$gl.stencilMask(~(mask - 1));
$gl.stencilFunc($gl.LEQUAL, 0, 0xff);
$gl.stencilOp($gl.ZERO, $gl.REPLACE, $gl.REPLACE);
Expand All @@ -115,7 +115,7 @@ export const execute = (): void =>
}

if ($context.containerClip) {
const mask = 1 << (level - 1);
const mask = 1 << level - 1;
$gl.stencilMask(~(mask - 1));
$gl.stencilFunc($gl.LEQUAL, 0, 0xff);
$gl.stencilOp($gl.ZERO, $gl.REPLACE, $gl.REPLACE);
Expand Down
56 changes: 15 additions & 41 deletions packages/webgl/src/Context/usecase/ContextDrawFillUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { execute as vertexArrayObjectCreateFillObjectUseCase } from "../../VertexArrayObject/usecase/VertexArrayObjectBindFillMeshUseCase";
import { execute as vertexArrayObjectReleaseVertexArrayObjectService } from "../../VertexArrayObject/service/VertexArrayObjectReleaseVertexArrayObjectService";
import { execute as variantsShapeSolidColorShaderService } from "../../Shader/Variants/Shape/service/VariantsShapeSolidColorShaderService";
import { execute as variantsShapeMaskShaderService } from "../../Shader/Variants/Shape/service/VariantsShapeMaskShaderService";
import { execute as shaderManagerSetFillUniformService } from "../../Shader/ShaderManager/service/ShaderManagerSetFillUniformService";
import { execute as shaderManagerSetMaskUniformService } from "../../Shader/ShaderManager/service/ShaderManagerSetMaskUniformService";
import { execute as shaderManagerFillUseCase } from "../../Shader/ShaderManager/usecase/ShaderManagerFillUseCase";
import { execute as contextNormalFillUseCase } from "./ContextNormalFillUseCase";
import { execute as contextLinearGradientFillUseCase } from "./ContextLinearGradientFillUseCase";
import { execute as contextRadialGradientUseCase } from "./ContextRadialGradientUseCase";
import { $gl } from "../../WebGLUtil";
import {
$terminateGrid,
Expand Down Expand Up @@ -34,58 +32,34 @@ export const execute = (): void =>
$gl.stencilMask(0xff);

let offset = 0;
let useGrid: boolean = false;
let gridData: Float32Array | null = null;
for (let idx = 0; idx < $fillBufferIndexes.length; idx++) {

const indexCount = $fillBufferIndexes[idx];

if ($gridDataMap.has(idx)) {
gridData = $gridDataMap.get(idx) as Float32Array | null;
useGrid = !!gridData;
}

// mask setting
$gl.stencilFunc($gl.ALWAYS, 0, 0xff);
$gl.stencilOpSeparate($gl.FRONT, $gl.KEEP, $gl.KEEP, $gl.INCR_WRAP);
$gl.stencilOpSeparate($gl.BACK, $gl.KEEP, $gl.KEEP, $gl.DECR_WRAP);
$gl.colorMask(false, false, false, false);

$gl.enable($gl.SAMPLE_ALPHA_TO_COVERAGE);

const coverageShader = variantsShapeMaskShaderService(false, useGrid);
if (gridData) {
shaderManagerSetMaskUniformService(coverageShader, gridData);
}
shaderManagerFillUseCase(
coverageShader, vertexArrayObject, offset, indexCount
);
$gl.disable($gl.SAMPLE_ALPHA_TO_COVERAGE);

// draw shape setting
$gl.stencilFunc($gl.NOTEQUAL, 0, 0xff);
$gl.stencilOp($gl.KEEP, $gl.ZERO, $gl.ZERO);
$gl.colorMask(true, true, true, true);

const type = $fillTypes[idx];
switch (type) {

case "fill":
{
const shaderManager = variantsShapeSolidColorShaderService(false, useGrid);
if (gridData) {
shaderManagerSetFillUniformService(shaderManager, gridData);
}
shaderManagerFillUseCase(
shaderManager, vertexArrayObject, offset, indexCount
);
}
case "fill": // 通常のShapeの塗り
contextNormalFillUseCase(
vertexArrayObject, offset, indexCount, gridData
);
break;

case "gradient":
case "linear": // 線形グラデーションの塗り
contextLinearGradientFillUseCase(
vertexArrayObject, offset, indexCount, gridData
);
break;

case "pattern":
case "radial": // 円形グラデーションの塗り
contextRadialGradientUseCase(
vertexArrayObject, offset, indexCount, gridData
);
break;

}
Expand Down
103 changes: 18 additions & 85 deletions packages/webgl/src/Context/usecase/ContextGradientFillUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import type { ShaderManager } from "../../Shader/ShaderManager";
import { $getVertices } from "../../PathCommand";
import { execute as gradientLUTGenerateShapeTextureUseCase } from "../../Shader/GradientLUTGenerator/usecase/GradientLUTGenerateShapeTextureUseCase";
import { execute as variantsGradientShapeShaderUseCase } from "../../Shader/Variants/Gradient/usecase/VariantsGradientShapeShaderUseCase";
import { execute as shaderManagerSetMaskUniformService } from "../../Shader/ShaderManager/service/ShaderManagerSetMaskUniformService";
import { execute as shaderManagerFillUseCase } from "../../Shader/ShaderManager/usecase/ShaderManagerFillUseCase";
import { execute as vertexArrayObjectCreateFillObjectUseCase } from "../../VertexArrayObject/usecase/VertexArrayObjectBindFillMeshUseCase";
import { execute as vertexArrayObjectReleaseVertexArrayObjectService } from "../../VertexArrayObject/service/VertexArrayObjectReleaseVertexArrayObjectService";
import { execute as variantsShapeMaskShaderService } from "../../Shader/Variants/Shape/service/VariantsShapeMaskShaderService";
import { execute as shaderManagerSetGradientFillUniformService } from "../../Shader/ShaderManager/service/ShaderManagerSetGradientFillUniformService";
import { execute as textureManagerBind0UseCase } from "../../TextureManager/usecase/TextureManagerBind0UseCase";
import { execute as meshFillGenerateUseCase } from "../../Mesh/usecase/MeshFillGenerateUseCase";
import { $gradientData } from "../../Gradient";
import {
$gl,
$context,
$inverseMatrix,
$linearGradientXY,
$poolFloat32Array6,
$poolFloat32Array4
} from "../../WebGLUtil";
$addFillBuffer,
$fillTypes,
$fillBufferIndexes
} from "../../Mesh";

/**
* @description グラデーション塗りを描画
Expand Down Expand Up @@ -46,76 +35,20 @@ export const execute = (
return ;
}

const textureObject = gradientLUTGenerateShapeTextureUseCase(stops, interpolation);
textureManagerBind0UseCase(textureObject);
// 塗りの種類を追加
$fillTypes.push(type === 0 ? "linear" : "radial");

let shaderManager: ShaderManager | null = null;
if (type === 0) { // linear
shaderManager = variantsGradientShapeShaderUseCase(
false, false, false, spread
);
const fillMesh = meshFillGenerateUseCase(vertices);
$addFillBuffer(fillMesh.buffer);

const points = $linearGradientXY(matrix);
// 塗りのインデックスを追加
$fillBufferIndexes.push(fillMesh.indexCount);

const inverseMatrix = $inverseMatrix($context.$matrix);
shaderManagerSetGradientFillUniformService(
shaderManager, type, $context.$matrix,
inverseMatrix, 0, points
);

$poolFloat32Array4(points);
$poolFloat32Array6(inverseMatrix);
} else { // radial

$context.save();
$context.transform(
matrix[0], matrix[1], matrix[2],
matrix[3], matrix[4], matrix[5]
);

shaderManager = variantsGradientShapeShaderUseCase(
false, true, Boolean(focal), spread
);

const prevMatrix = $context.$stack[$context.$stack.length - 1];

const inverseMatrix = $inverseMatrix($context.$matrix);
shaderManagerSetGradientFillUniformService(
shaderManager, type, prevMatrix,
inverseMatrix, focal
);

$context.restore();

$poolFloat32Array6(inverseMatrix);
$gradientData.push(stops);
$gradientData.push(matrix);
$gradientData.push(spread);
$gradientData.push(interpolation);
if (type === 1) {
$gradientData.push(focal);
}

const vertexArrayObject = vertexArrayObjectCreateFillObjectUseCase(vertices);

// mask on
$gl.enable($gl.STENCIL_TEST);
$gl.stencilMask(0xff);

// draw shape
$gl.enable($gl.SAMPLE_ALPHA_TO_COVERAGE);
$gl.stencilFunc($gl.ALWAYS, 0, 0xff);
$gl.stencilOp($gl.KEEP, $gl.INVERT, $gl.INVERT);
$gl.colorMask(false, false, false, false);

const coverageShader = variantsShapeMaskShaderService(false);
shaderManagerSetMaskUniformService(coverageShader);
shaderManagerFillUseCase(coverageShader, vertexArrayObject);
$gl.disable($gl.SAMPLE_ALPHA_TO_COVERAGE);

// draw shape range
$gl.stencilFunc($gl.NOTEQUAL, 0, 0xff);
$gl.stencilOp($gl.KEEP, $gl.ZERO, $gl.ZERO);
$gl.colorMask(true, true, true, true);
shaderManagerFillUseCase(shaderManager as ShaderManager, vertexArrayObject);

// mask off
$gl.disable($gl.STENCIL_TEST);

// release vertex array
vertexArrayObjectReleaseVertexArrayObjectService(vertexArrayObject);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { IVertexArrayObject } from "../../interface/IVertexArrayObject";
import { execute as gradientLUTGenerateShapeTextureUseCase } from "../../Shader/GradientLUTGenerator/usecase/GradientLUTGenerateShapeTextureUseCase";
import { execute as textureManagerBind0UseCase } from "../../TextureManager/usecase/TextureManagerBind0UseCase";
import { execute as variantsShapeMaskShaderService } from "../../Shader/Variants/Shape/service/VariantsShapeMaskShaderService";
import { execute as shaderManagerSetMaskUniformService } from "../../Shader/ShaderManager/service/ShaderManagerSetMaskUniformService";
import { execute as shaderManagerFillUseCase } from "../../Shader/ShaderManager/usecase/ShaderManagerFillUseCase";
import { execute as variantsGradientShapeShaderUseCase } from "../../Shader/Variants/Gradient/usecase/VariantsGradientShapeShaderUseCase";
import { execute as shaderManagerSetGradientFillUniformService } from "../../Shader/ShaderManager/service/ShaderManagerSetGradientFillUniformService";
import { $gradientData } from "../../Gradient";
import {
$gl,
$linearGradientXY,
$inverseMatrix,
$context,
$poolFloat32Array6,
$poolFloat32Array4
} from "../../WebGLUtil";

/**
* @description 線形グラデーションのシェーダーを実行します。
* Execute the linear gradient shader.
*
* @param {IVertexArrayObject} vertex_array_object
* @param {number} offset
* @param {number} index_count
* @param {Float32Array | null} [grid_data=null]
* @return {void}
* @method
* @protected
*/
export const execute = (
vertex_array_object: IVertexArrayObject,
offset: number,
index_count: number,
grid_data: Float32Array | null
): void => {

const stops = $gradientData.shift() as number[];
const matrix = $gradientData.shift() as Float32Array;
const spread = $gradientData.shift() as number;
const interpolation = $gradientData.shift() as number;

$gl.disable($gl.STENCIL_TEST);
const textureObject = gradientLUTGenerateShapeTextureUseCase(stops, interpolation);
textureManagerBind0UseCase(textureObject);

$gl.enable($gl.STENCIL_TEST);
$gl.frontFace($gl.CCW);
$gl.stencilMask(0xff);

// mask setting
$gl.stencilFunc($gl.ALWAYS, 0, 0xff);
$gl.stencilOpSeparate($gl.FRONT, $gl.KEEP, $gl.KEEP, $gl.INCR_WRAP);
$gl.stencilOpSeparate($gl.BACK, $gl.KEEP, $gl.KEEP, $gl.DECR_WRAP);
$gl.colorMask(false, false, false, false);

$gl.enable($gl.SAMPLE_ALPHA_TO_COVERAGE);

const useGrid = !!grid_data;
const coverageShader = variantsShapeMaskShaderService(false, useGrid);
if (grid_data) {
shaderManagerSetMaskUniformService(coverageShader, grid_data);
}
shaderManagerFillUseCase(
coverageShader, vertex_array_object, offset, index_count
);
$gl.disable($gl.SAMPLE_ALPHA_TO_COVERAGE);

$gl.stencilFunc($gl.NOTEQUAL, 0, 0xff);
$gl.stencilOp($gl.KEEP, $gl.ZERO, $gl.ZERO);
$gl.colorMask(true, true, true, true);

const shaderManager = variantsGradientShapeShaderUseCase(
false, false, false, spread, useGrid
);

const points = $linearGradientXY(matrix);
const inverseMatrix = $inverseMatrix($context.$matrix);
shaderManagerSetGradientFillUniformService(
shaderManager, 0, $context.$matrix,
inverseMatrix, 0, points, grid_data
);

$poolFloat32Array4(points);
$poolFloat32Array6(inverseMatrix);

shaderManagerFillUseCase(
shaderManager, vertex_array_object, offset, index_count
);
};
Loading

0 comments on commit a79c3e0

Please sign in to comment.