Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
060f108c
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
060f108c
编写于
4月 23, 2021
作者:
F
Ferhat
提交者:
GitHub
4月 23, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add web ImageShader support for drawVertices. (#25729)
上级
7676dbc9
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
665 addition
and
180 deletion
+665
-180
lib/web_ui/dev/goldens_lock.yaml
lib/web_ui/dev/goldens_lock.yaml
+1
-1
lib/web_ui/lib/src/engine/bitmap_canvas.dart
lib/web_ui/lib/src/engine/bitmap_canvas.dart
+4
-3
lib/web_ui/lib/src/engine/html/recording_canvas.dart
lib/web_ui/lib/src/engine/html/recording_canvas.dart
+10
-0
lib/web_ui/lib/src/engine/html/render_vertices.dart
lib/web_ui/lib/src/engine/html/render_vertices.dart
+293
-40
lib/web_ui/lib/src/engine/html/shaders/shader.dart
lib/web_ui/lib/src/engine/html/shaders/shader.dart
+18
-3
lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart
lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart
+32
-0
lib/web_ui/lib/src/ui/painting.dart
lib/web_ui/lib/src/ui/painting.dart
+3
-6
lib/web_ui/test/golden_tests/engine/draw_vertices_golden_test.dart
...i/test/golden_tests/engine/draw_vertices_golden_test.dart
+304
-127
未找到文件。
lib/web_ui/dev/goldens_lock.yaml
浏览文件 @
060f108c
repository
:
https://github.com/flutter/goldens.git
revision
:
d885b270d90e031fdda2efd640eb5d6b6fbc9ce5
revision
:
449cb88e9ffed446e4e7df9beb73814e5fb11ead
lib/web_ui/lib/src/engine/bitmap_canvas.dart
浏览文件 @
060f108c
...
...
@@ -940,12 +940,13 @@ class BitmapCanvas extends EngineCanvas {
// blendMode. https://github.com/flutter/flutter/issues/40096
// Move rendering to OffscreenCanvas so that transform is preserved
// as well.
assert
(
paint
.
shader
==
null
,
'Linear/Radial/SweepGradient
and ImageShader
not supported yet'
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
ImageShader
,
'Linear/Radial/SweepGradient not supported yet'
);
final
Int32List
?
colors
=
vertices
.
_colors
;
final
ui
.
VertexMode
mode
=
vertices
.
_mode
;
html
.
CanvasRenderingContext2D
?
ctx
=
_canvasPool
.
context
;
if
(
colors
==
null
&&
paint
.
style
!=
ui
.
PaintingStyle
.
fill
)
{
if
(
colors
==
null
&&
paint
.
style
!=
ui
.
PaintingStyle
.
fill
&&
paint
.
shader
==
null
)
{
final
Float32List
positions
=
mode
==
ui
.
VertexMode
.
triangles
?
vertices
.
_positions
:
_convertVertexPositions
(
mode
,
vertices
.
_positions
);
...
...
lib/web_ui/lib/src/engine/html/recording_canvas.dart
浏览文件 @
060f108c
...
...
@@ -321,6 +321,7 @@ class RecordingCanvas {
void
drawLine
(
ui
.
Offset
p1
,
ui
.
Offset
p2
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
final
double
paintSpread
=
math
.
max
(
_getPaintSpread
(
paint
),
1.0
);
final
PaintDrawLine
command
=
PaintDrawLine
(
p1
,
p2
,
paint
.
paintData
);
// TODO(yjbanov): This can be optimized. Currently we create a box around
...
...
@@ -344,6 +345,7 @@ class RecordingCanvas {
void
drawPaint
(
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
renderStrategy
.
hasArbitraryPaint
=
true
;
_didDraw
=
true
;
final
PaintDrawPaint
command
=
PaintDrawPaint
(
paint
.
paintData
);
...
...
@@ -353,6 +355,7 @@ class RecordingCanvas {
void
drawRect
(
ui
.
Rect
rect
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
if
(
paint
.
shader
!=
null
)
{
renderStrategy
.
hasArbitraryPaint
=
true
;
}
...
...
@@ -369,6 +372,7 @@ class RecordingCanvas {
void
drawRRect
(
ui
.
RRect
rrect
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
if
(
paint
.
shader
!=
null
||
!
rrect
.
webOnlyUniformRadii
)
{
renderStrategy
.
hasArbitraryPaint
=
true
;
}
...
...
@@ -385,6 +389,7 @@ class RecordingCanvas {
void
drawDRRect
(
ui
.
RRect
outer
,
ui
.
RRect
inner
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
// Check the inner bounds are contained within the outer bounds
// see: https://cs.chromium.org/chromium/src/third_party/skia/src/core/SkCanvas.cpp?l=1787-1789
ui
.
Rect
innerRect
=
inner
.
outerRect
;
...
...
@@ -443,6 +448,7 @@ class RecordingCanvas {
void
drawOval
(
ui
.
Rect
rect
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
renderStrategy
.
hasArbitraryPaint
=
true
;
_didDraw
=
true
;
final
double
paintSpread
=
_getPaintSpread
(
paint
);
...
...
@@ -457,6 +463,7 @@ class RecordingCanvas {
void
drawCircle
(
ui
.
Offset
c
,
double
radius
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
renderStrategy
.
hasArbitraryPaint
=
true
;
_didDraw
=
true
;
final
double
paintSpread
=
_getPaintSpread
(
paint
);
...
...
@@ -474,6 +481,7 @@ class RecordingCanvas {
void
drawPath
(
ui
.
Path
path
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
if
(
paint
.
shader
==
null
)
{
// For Rect/RoundedRect paths use drawRect/drawRRect code paths for
// DomCanvas optimization.
...
...
@@ -510,6 +518,7 @@ class RecordingCanvas {
void
drawImage
(
ui
.
Image
image
,
ui
.
Offset
offset
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
renderStrategy
.
hasArbitraryPaint
=
true
;
renderStrategy
.
hasImageElements
=
true
;
_didDraw
=
true
;
...
...
@@ -547,6 +556,7 @@ class RecordingCanvas {
void
drawImageRect
(
ui
.
Image
image
,
ui
.
Rect
src
,
ui
.
Rect
dst
,
SurfacePaint
paint
)
{
assert
(!
_recordingEnded
);
assert
(
paint
.
shader
==
null
||
paint
.
shader
is
!
ImageShader
,
'ImageShader not supported yet'
);
renderStrategy
.
hasArbitraryPaint
=
true
;
renderStrategy
.
hasImageElements
=
true
;
_didDraw
=
true
;
...
...
lib/web_ui/lib/src/engine/html/render_vertices.dart
浏览文件 @
060f108c
...
...
@@ -49,6 +49,10 @@ class SurfaceVertices implements ui.Vertices {
}
}
/// Lazily initializes web gl.
///
/// Used to treeshake WebGlRenderer when user doesn't create Vertices object
/// to use the API.
void
initWebGl
(
)
{
_glRenderer
??=
_WebGlRenderer
();
}
...
...
@@ -85,6 +89,45 @@ class _WebGlRenderer implements _GlRenderer {
/// Cached vertex shader reused by [drawVertices] and gradients.
static
String
?
_baseVertexShader
;
static
String
?
_textureVertexShader
;
static
void
_setupVertexTransforms
(
_GlContext
gl
,
_GlProgram
glProgram
,
double
offsetX
,
double
offsetY
,
double
widthInPixels
,
double
heightInPixels
,
Matrix4
transform
)
{
Object
transformUniform
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_ctransform'
);
Matrix4
transformAtOffset
=
transform
.
clone
()
..
translate
(-
offsetX
,
-
offsetY
);
gl
.
setUniformMatrix4fv
(
transformUniform
,
false
,
transformAtOffset
.
storage
);
// Set uniform to scale 0..width/height pixels coordinates to -1..1
// clipspace range and flip the Y axis.
Object
resolution
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_scale'
);
gl
.
setUniform4f
(
resolution
,
2.0
/
widthInPixels
.
toDouble
(),
-
2.0
/
heightInPixels
.
toDouble
(),
1
,
1
);
Object
shift
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_shift'
);
gl
.
setUniform4f
(
shift
,
-
1
,
1
,
0
,
0
);
}
static
void
_setupTextureScalar
(
_GlContext
gl
,
_GlProgram
glProgram
,
double
sx
,
double
sy
)
{
Object
scalar
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_texscale'
);
gl
.
setUniform2f
(
scalar
,
sx
,
sy
);
}
static
dynamic
_tileModeToGlWrapping
(
_GlContext
gl
,
ui
.
TileMode
tileMode
)
{
switch
(
tileMode
)
{
case
ui
.
TileMode
.
clamp
:
return
gl
.
kClampToEdge
;
case
ui
.
TileMode
.
decal
:
return
gl
.
kClampToEdge
;
case
ui
.
TileMode
.
mirror
:
return
gl
.
kMirroredRepeat
;
case
ui
.
TileMode
.
repeated
:
return
gl
.
kRepeat
;
}
}
@override
void
drawVertices
(
html
.
CanvasRenderingContext2D
?
context
,
...
...
@@ -94,6 +137,7 @@ class _WebGlRenderer implements _GlRenderer {
SurfaceVertices
vertices
,
ui
.
BlendMode
blendMode
,
SurfacePaintData
paint
)
{
// Compute bounds of vertices.
final
Float32List
positions
=
vertices
.
_positions
;
ui
.
Rect
bounds
=
_computeVerticesBounds
(
positions
,
transform
);
...
...
@@ -124,60 +168,137 @@ class _WebGlRenderer implements _GlRenderer {
if
(
widthInPixels
==
0
||
heightInPixels
==
0
)
{
return
;
}
final
String
vertexShader
=
writeBaseVertexShader
();
final
String
fragmentShader
=
_writeVerticesFragmentShader
();
final
bool
isWebGl2
=
webGLVersion
==
WebGLVersion
.
webgl2
;
final
ImageShader
?
imageShader
=
paint
.
shader
==
null
?
null
:
paint
.
shader
as
ImageShader
;
final
String
vertexShader
=
imageShader
==
null
?
writeBaseVertexShader
()
:
writeTextureVertexShader
();
final
String
fragmentShader
=
imageShader
==
null
?
_writeVerticesFragmentShader
()
:
_writeVerticesTextureFragmentShader
(
isWebGl2
,
imageShader
.
tileModeX
,
imageShader
.
tileModeY
);
_GlContext
gl
=
_GlContextCache
.
createGlContext
(
widthInPixels
,
heightInPixels
)!;
_GlProgram
glProgram
=
gl
.
useAndCacheProgram
(
vertexShader
,
fragmentShader
);
_GlProgram
glProgram
=
gl
.
cacheProgram
(
vertexShader
,
fragmentShader
);
gl
.
useProgram
(
glProgram
);
Object
transformUniform
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_ctransform'
);
Matrix4
transformAtOffset
=
transform
.
clone
()
..
translate
(-
offsetX
,
-
offsetY
);
gl
.
setUniformMatrix4fv
(
transformUniform
,
false
,
transformAtOffset
.
storage
);
Object
?
positionAttributeLocation
=
gl
.
getAttributeLocation
(
glProgram
.
program
,
'position'
);
// Set uniform to scale 0..width/height pixels coordinates to -1..1
// clipspace range and flip the Y axis.
Object
resolution
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_scale'
);
gl
.
setUniform4f
(
resolution
,
2.0
/
widthInPixels
.
toDouble
(),
-
2.0
/
heightInPixels
.
toDouble
(),
1
,
1
);
Object
shift
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_shift'
);
gl
.
setUniform4f
(
shift
,
-
1
,
1
,
0
,
0
);
_setupVertexTransforms
(
gl
,
glProgram
,
offsetX
,
offsetY
,
widthInPixels
.
toDouble
(),
heightInPixels
.
toDouble
(),
transform
);
if
(
imageShader
!=
null
)
{
/// To map from vertex position to texture coordinate in 0..1 range,
/// we setup scalar to be used in vertex shader.
_setupTextureScalar
(
gl
,
glProgram
,
1.0
/
imageShader
.
_image
.
width
.
toDouble
(),
1.0
/
imageShader
.
_image
.
height
.
toDouble
());
}
// Setup geometry.
//
// Create buffer for vertex coordinates.
Object
positionsBuffer
=
gl
.
createBuffer
()!;
assert
(
positionsBuffer
!=
null
);
// ignore: unnecessary_null_comparison
Object
?
vao
;
if
(
imageShader
!=
null
)
{
if
(
isWebGl2
)
{
// Create a vertex array object.
vao
=
gl
.
createVertexArray
();
// Set vertex array object as active one.
gl
.
bindVertexArray
(
vao
!);
}
}
// Turn on position attribute.
gl
.
enableVertexAttribArray
(
positionAttributeLocation
);
// Bind buffer as position buffer and transfer data.
gl
.
bindArrayBuffer
(
positionsBuffer
);
gl
.
bufferData
(
positions
,
gl
.
kStaticDraw
);
Object
?
positionLoc
=
gl
.
getAttributeLocation
(
glProgram
.
program
,
'position'
);
// Setup data format for attribute.
js_util
.
callMethod
(
gl
.
glContext
,
'vertexAttribPointer'
,
<
dynamic
>[
positionLoc
,
2
,
gl
.
kFloat
,
false
,
0
,
0
,
positionAttributeLocation
,
2
,
gl
.
kFloat
,
false
,
0
,
0
,
]);
gl
.
enableVertexAttribArray
(
0
);
// Setup color buffer.
Object
?
colorsBuffer
=
gl
.
createBuffer
();
gl
.
bindArrayBuffer
(
colorsBuffer
);
final
int
vertexCount
=
positions
.
length
~/
2
;
// Buffer kBGRA_8888.
if
(
vertices
.
_colors
==
null
)
{
final
ui
.
Color
color
=
paint
.
color
??
ui
.
Color
(
0xFF000000
);
Uint32List
vertexColors
=
Uint32List
(
vertexCount
);
for
(
int
i
=
0
;
i
<
vertexCount
;
i
++)
{
vertexColors
[
i
]
=
color
.
value
;
Object
?
texture
;
if
(
imageShader
==
null
)
{
// Setup color buffer.
Object
?
colorsBuffer
=
gl
.
createBuffer
();
gl
.
bindArrayBuffer
(
colorsBuffer
);
// Buffer kBGRA_8888.
if
(
vertices
.
_colors
==
null
)
{
final
ui
.
Color
color
=
paint
.
color
??
ui
.
Color
(
0xFF000000
);
Uint32List
vertexColors
=
Uint32List
(
vertexCount
);
for
(
int
i
=
0
;
i
<
vertexCount
;
i
++)
{
vertexColors
[
i
]
=
color
.
value
;
}
gl
.
bufferData
(
vertexColors
,
gl
.
kStaticDraw
);
}
else
{
gl
.
bufferData
(
vertices
.
_colors
,
gl
.
kStaticDraw
);
}
gl
.
bufferData
(
vertexColors
,
gl
.
kStaticDraw
);
Object
colorLoc
=
gl
.
getAttributeLocation
(
glProgram
.
program
,
'color'
);
js_util
.
callMethod
(
gl
.
glContext
,
'vertexAttribPointer'
,
<
dynamic
>[
colorLoc
,
4
,
gl
.
kUnsignedByte
,
true
,
0
,
0
]);
gl
.
enableVertexAttribArray
(
colorLoc
);
}
else
{
gl
.
bufferData
(
vertices
.
_colors
,
gl
.
kStaticDraw
);
// Copy image it to the texture.
texture
=
gl
.
createTexture
();
// Texture units are a global array of references to the textures.
// By setting activeTexture, we associate the bound texture to a unit.
// Every time we call a texture function such as texImage2D with a target
// like TEXTURE_2D, it looks up texture by using the currently active
// unit.
// In our case we have a single texture unit 0.
gl
.
activeTexture
(
gl
.
kTexture0
);
gl
.
bindTexture
(
gl
.
kTexture2D
,
texture
);
gl
.
texImage2D
(
gl
.
kTexture2D
,
0
,
gl
.
kRGBA
,
gl
.
kRGBA
,
gl
.
kUnsignedByte
,
imageShader
.
_image
.
imgElement
);
if
(
isWebGl2
)
{
// Texture REPEAT and MIRROR is only supported in WebGL 2, for
// WebGL 1.0 we let shader compute correct uv coordinates.
gl
.
texParameteri
(
gl
.
kTexture2D
,
gl
.
kTextureWrapS
,
_tileModeToGlWrapping
(
gl
,
imageShader
.
tileModeX
));
gl
.
texParameteri
(
gl
.
kTexture2D
,
gl
.
kTextureWrapT
,
_tileModeToGlWrapping
(
gl
,
imageShader
.
tileModeY
));
// Mipmapping saves your texture in different resolutions
// so the graphics card can choose which resolution is optimal
// without artifacts.
gl
.
generateMipmap
(
gl
.
kTexture2D
);
}
else
{
// For webgl1, if a texture is not mipmap complete, then the return
// value of a texel fetch is (0, 0, 0, 1), so we have to set
// minifying function to filter.
// See https://www.khronos.org/registry/webgl/specs/1.0.0/#5.13.8.
gl
.
texParameteri
(
gl
.
kTexture2D
,
gl
.
kTextureWrapS
,
gl
.
kClampToEdge
);
gl
.
texParameteri
(
gl
.
kTexture2D
,
gl
.
kTextureWrapT
,
gl
.
kClampToEdge
);
gl
.
texParameteri
(
gl
.
kTexture2D
,
gl
.
kTextureMinFilter
,
gl
.
kLinear
);
}
}
Object
colorLoc
=
gl
.
getAttributeLocation
(
glProgram
.
program
,
'color'
);
js_util
.
callMethod
(
gl
.
glContext
,
'vertexAttribPointer'
,
<
dynamic
>[
colorLoc
,
4
,
gl
.
kUnsignedByte
,
true
,
0
,
0
]);
gl
.
enableVertexAttribArray
(
1
);
// Finally render triangles.
gl
.
clear
();
final
Uint16List
?
indices
=
vertices
.
_indices
;
if
(
indices
==
null
)
{
gl
.
drawTriangles
(
vertexCount
,
vertices
.
_mode
);
...
...
@@ -191,6 +312,10 @@ class _WebGlRenderer implements _GlRenderer {
gl
.
drawElements
(
gl
.
kTriangles
,
indices
.
length
,
gl
.
kUnsignedShort
);
}
if
(
vao
!=
null
)
{
gl
.
unbindVertexArray
();
}
context
!.
save
();
context
.
resetTransform
();
gl
.
drawImage
(
context
,
offsetX
,
offsetY
);
...
...
@@ -331,6 +456,26 @@ class _WebGlRenderer implements _GlRenderer {
return
_baseVertexShader
!;
}
static
String
writeTextureVertexShader
()
{
if
(
_textureVertexShader
==
null
)
{
ShaderBuilder
builder
=
ShaderBuilder
(
webGLVersion
);
builder
.
addIn
(
ShaderType
.
kVec4
,
name:
'position'
);
builder
.
addUniform
(
ShaderType
.
kMat4
,
name:
'u_ctransform'
);
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'u_scale'
);
builder
.
addUniform
(
ShaderType
.
kVec2
,
name:
'u_texscale'
);
builder
.
addUniform
(
ShaderType
.
kVec4
,
name:
'u_shift'
);
builder
.
addOut
(
ShaderType
.
kVec2
,
name:
'v_texcoord'
);
ShaderMethod
method
=
builder
.
addMethod
(
'main'
);
method
.
addStatement
(
'gl_Position = ((u_ctransform * position) * u_scale) + u_shift;'
);
method
.
addStatement
(
'v_texcoord = vec2(position.x * u_texscale.x, '
'(position.y * u_texscale.y));'
);
_textureVertexShader
=
builder
.
build
();
}
return
_textureVertexShader
!;
}
/// This fragment shader enables Int32List of colors to be passed directly
/// to gl context buffer for rendering by decoding RGBA8888.
/// #version 300 es
...
...
@@ -349,6 +494,33 @@ class _WebGlRenderer implements _GlRenderer {
return
builder
.
build
();
}
String
_writeVerticesTextureFragmentShader
(
bool
isWebGl2
,
ui
.
TileMode
?
tileModeX
,
ui
.
TileMode
?
tileModeY
)
{
ShaderBuilder
builder
=
ShaderBuilder
.
fragment
(
webGLVersion
);
builder
.
floatPrecision
=
ShaderPrecision
.
kMedium
;
builder
.
addIn
(
ShaderType
.
kVec2
,
name:
'v_texcoord'
);
builder
.
addUniform
(
ShaderType
.
kSampler2D
,
name:
'u_texture'
);
ShaderMethod
method
=
builder
.
addMethod
(
'main'
);
if
(
isWebGl2
||
tileModeX
==
null
||
tileModeY
==
null
||
(
tileModeX
==
ui
.
TileMode
.
clamp
&&
tileModeY
==
ui
.
TileMode
.
clamp
))
{
method
.
addStatement
(
'
${builder.fragmentColor.name}
= '
'
${builder.texture2DFunction}
(u_texture, v_texcoord);'
);
}
else
{
// Repeat and mirror are not supported for webgl1. Write code to
// adjust texture coordinate.
//
// This will write u and v floats, clamp/repeat and mirror the value and
// pass it to sampler.
method
.
addTileStatements
(
'v_texcoord.x'
,
'u'
,
tileModeX
);
method
.
addTileStatements
(
'v_texcoord.y'
,
'v'
,
tileModeY
);
method
.
addStatement
(
'vec2 uv = vec2(u, v);'
);
method
.
addStatement
(
'
${builder.fragmentColor.name}
= '
'
${builder.texture2DFunction}
(u_texture, uv);'
);
}
return
builder
.
build
();
}
@override
void
drawHairline
(
html
.
CanvasRenderingContext2D
?
_ctx
,
Float32List
positions
)
{
assert
(
positions
!=
null
);
// ignore: unnecessary_null_comparison
...
...
@@ -490,11 +662,20 @@ class _GlContext {
dynamic
_kStaticDraw
;
dynamic
_kFloat
;
dynamic
_kColorBufferBit
;
dynamic
_kTexture2D
;
dynamic
_kTextureWrapS
;
dynamic
_kTextureWrapT
;
dynamic
_kRepeat
;
dynamic
_kClampToEdge
;
dynamic
_kMirroredRepeat
;
dynamic
_kTriangles
;
dynamic
_kLinkStatus
;
dynamic
_kUnsignedByte
;
dynamic
_kUnsignedShort
;
dynamic
_kRGBA
;
dynamic
_kLinear
;
dynamic
_kTextureMinFilter
;
int
?
_kTexture0
;
Object
?
_canvas
;
int
?
_widthInPixels
;
...
...
@@ -531,7 +712,7 @@ class _GlContext {
left
,
top
,
_widthInPixels
,
_heightInPixels
]);
}
_GlProgram
useAndC
acheProgram
(
_GlProgram
c
acheProgram
(
String
vertexShaderSource
,
String
fragmentShaderSource
)
{
String
cacheKey
=
'
$vertexShaderSource
||
$fragmentShaderSource
'
;
_GlProgram
?
cachedProgram
=
_programCache
[
cacheKey
];
...
...
@@ -547,7 +728,6 @@ class _GlContext {
linkProgram
(
program
);
cachedProgram
=
_GlProgram
(
program
);
_programCache
[
cacheKey
]
=
cachedProgram
;
useProgram
(
program
);
}
return
cachedProgram
;
}
...
...
@@ -582,8 +762,8 @@ class _GlContext {
}
}
void
useProgram
(
Object
?
program
)
{
js_util
.
callMethod
(
glContext
,
'useProgram'
,
<
dynamic
>[
program
]);
void
useProgram
(
_GlProgram
program
)
{
js_util
.
callMethod
(
glContext
,
'useProgram'
,
<
dynamic
>[
program
.
program
]);
}
Object
?
createBuffer
()
=>
...
...
@@ -593,10 +773,55 @@ class _GlContext {
js_util
.
callMethod
(
glContext
,
'bindBuffer'
,
<
dynamic
>[
kArrayBuffer
,
buffer
]);
}
Object
?
createVertexArray
()
=>
js_util
.
callMethod
(
glContext
,
'createVertexArray'
,
const
<
dynamic
>[]);
void
bindVertexArray
(
Object
vertexObjectArray
)
{
js_util
.
callMethod
(
glContext
,
'bindVertexArray'
,
<
dynamic
>[
vertexObjectArray
]);
}
void
unbindVertexArray
()
{
js_util
.
callMethod
(
glContext
,
'bindVertexArray'
,
<
dynamic
>[
null
]);
}
void
bindElementArrayBuffer
(
Object
?
buffer
)
{
js_util
.
callMethod
(
glContext
,
'bindBuffer'
,
<
dynamic
>[
kElementArrayBuffer
,
buffer
]);
}
Object
?
createTexture
()
=>
js_util
.
callMethod
(
glContext
,
'createTexture'
,
const
<
dynamic
>[]);
void
generateMipmap
(
dynamic
target
)
=>
js_util
.
callMethod
(
glContext
,
'generateMipmap'
,
<
dynamic
>[
target
]);
void
bindTexture
(
dynamic
target
,
Object
?
buffer
)
{
js_util
.
callMethod
(
glContext
,
'bindTexture'
,
<
dynamic
>[
target
,
buffer
]);
}
void
activeTexture
(
int
textureUnit
)
{
js_util
.
callMethod
(
glContext
,
'activeTexture'
,
<
dynamic
>[
textureUnit
]);
}
void
texImage2D
(
dynamic
target
,
int
level
,
dynamic
internalFormat
,
dynamic
format
,
dynamic
dataType
,
dynamic
pixels
,
{
int
?
width
,
int
?
height
,
int
border
=
0
})
{
if
(
width
==
null
)
{
js_util
.
callMethod
(
glContext
,
'texImage2D'
,
<
dynamic
>[
target
,
level
,
internalFormat
,
format
,
dataType
,
pixels
]);
}
else
{
js_util
.
callMethod
(
glContext
,
'texImage2D'
,
<
dynamic
>[
target
,
level
,
internalFormat
,
width
,
height
,
border
,
format
,
dataType
,
pixels
]);
}
}
void
texParameteri
(
dynamic
target
,
dynamic
parameterName
,
dynamic
value
)
{
js_util
.
callMethod
(
glContext
,
'texParameteri'
,
<
dynamic
>[
target
,
parameterName
,
value
]);
}
void
deleteBuffer
(
Object
buffer
)
{
js_util
.
callMethod
(
glContext
,
'deleteBuffer'
,
<
dynamic
>[
buffer
]);
}
...
...
@@ -609,7 +834,7 @@ class _GlContext {
js_util
.
callMethod
(
glContext
,
'bufferData'
,
<
dynamic
>[
kElementArrayBuffer
,
data
,
type
]);
}
void
enableVertexAttribArray
(
int
index
)
{
void
enableVertexAttribArray
(
dynamic
index
)
{
js_util
.
callMethod
(
glContext
,
'enableVertexAttribArray'
,
<
dynamic
>[
index
]);
}
...
...
@@ -706,6 +931,34 @@ class _GlContext {
dynamic
get
kColorBufferBit
=>
_kColorBufferBit
??=
js_util
.
getProperty
(
glContext
,
'COLOR_BUFFER_BIT'
);
dynamic
get
kTexture2D
=>
_kTexture2D
??=
js_util
.
getProperty
(
glContext
,
'TEXTURE_2D'
);
int
get
kTexture0
=>
_kTexture0
??=
js_util
.
getProperty
(
glContext
,
'TEXTURE0'
)
as
int
;
dynamic
get
kTextureWrapS
=>
_kTextureWrapS
??=
js_util
.
getProperty
(
glContext
,
'TEXTURE_WRAP_S'
);
dynamic
get
kTextureWrapT
=>
_kTextureWrapT
??=
js_util
.
getProperty
(
glContext
,
'TEXTURE_WRAP_T'
);
dynamic
get
kRepeat
=>
_kRepeat
??=
js_util
.
getProperty
(
glContext
,
'REPEAT'
);
dynamic
get
kClampToEdge
=>
_kClampToEdge
??=
js_util
.
getProperty
(
glContext
,
'CLAMP_TO_EDGE'
);
dynamic
get
kMirroredRepeat
=>
_kMirroredRepeat
??=
js_util
.
getProperty
(
glContext
,
'MIRRORED_REPEAT'
);
dynamic
get
kLinear
=>
_kLinear
??=
js_util
.
getProperty
(
glContext
,
'LINEAR'
);
dynamic
get
kTextureMinFilter
=>
_kTextureMinFilter
??=
js_util
.
getProperty
(
glContext
,
'TEXTURE_MIN_FILTER'
);
/// Returns reference to uniform in program.
Object
getUniformLocation
(
Object
program
,
String
uniformName
)
{
Object
?
res
=
js_util
...
...
lib/web_ui/lib/src/engine/html/shaders/shader.dart
浏览文件 @
060f108c
...
...
@@ -51,9 +51,10 @@ class GradientSweep extends EngineGradient {
NormalizedGradient
normalizedGradient
=
NormalizedGradient
(
colors
,
stops:
colorStops
);
_GlProgram
glProgram
=
gl
.
useAndC
acheProgram
(
_GlProgram
glProgram
=
gl
.
c
acheProgram
(
_WebGlRenderer
.
writeBaseVertexShader
(),
_createSweepFragmentShader
(
normalizedGradient
,
tileMode
));
gl
.
useProgram
(
glProgram
);
Object
tileOffset
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_tile_offset'
);
...
...
@@ -134,6 +135,18 @@ class GradientSweep extends EngineGradient {
final
Float32List
?
matrix4
;
}
class
ImageShader
implements
ui
.
ImageShader
{
ImageShader
(
ui
.
Image
image
,
this
.
tileModeX
,
this
.
tileModeY
,
this
.
matrix4
,
this
.
filterQuality
)
:
_image
=
image
as
HtmlImage
;
final
ui
.
TileMode
tileModeX
;
final
ui
.
TileMode
tileModeY
;
final
Float64List
matrix4
;
final
ui
.
FilterQuality
?
filterQuality
;
final
HtmlImage
_image
;
}
class
GradientLinear
extends
EngineGradient
{
GradientLinear
(
this
.
from
,
...
...
@@ -221,9 +234,10 @@ class GradientLinear extends EngineGradient {
NormalizedGradient
normalizedGradient
=
NormalizedGradient
(
colors
,
stops:
colorStops
);
_GlProgram
glProgram
=
gl
.
useAndC
acheProgram
(
_GlProgram
glProgram
=
gl
.
c
acheProgram
(
_WebGlRenderer
.
writeBaseVertexShader
(),
_createLinearFragmentShader
(
normalizedGradient
,
tileMode
));
gl
.
useProgram
(
glProgram
);
// Setup from/to uniforms.
//
...
...
@@ -491,10 +505,11 @@ class GradientRadial extends EngineGradient {
NormalizedGradient
normalizedGradient
=
NormalizedGradient
(
colors
,
stops:
colorStops
);
_GlProgram
glProgram
=
gl
.
useAndC
acheProgram
(
_GlProgram
glProgram
=
gl
.
c
acheProgram
(
_WebGlRenderer
.
writeBaseVertexShader
(),
_createRadialFragmentShader
(
normalizedGradient
,
shaderBounds
,
tileMode
));
gl
.
useProgram
(
glProgram
);
Object
tileOffset
=
gl
.
getUniformLocation
(
glProgram
.
program
,
'u_tile_offset'
);
...
...
lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart
浏览文件 @
060f108c
...
...
@@ -229,6 +229,8 @@ class ShaderBuilder {
String
_precisionToString
(
int
precision
)
=>
precision
==
ShaderPrecision
.
kLow
?
'lowp'
:
precision
==
ShaderPrecision
.
kMedium
?
'mediump'
:
'highp'
;
String
get
texture2DFunction
=>
isWebGl2
?
'texture'
:
'texture2D'
;
}
class
ShaderMethod
{
...
...
@@ -256,6 +258,36 @@ class ShaderMethod {
}
}
/// Adds statements to compute tiling in 0..1 coordinate space.
///
/// For clamp we simply assign source value to destination.
///
/// For repeat, we use fractional part of source value.
/// float destination = fract(source);
///
/// For mirror, we repeat every 2 units, by scaling and measuring distance
/// from floor.
/// float destination = 1.0 - source;
/// destination = abs((destination - 2.0 * floor(destination * 0.5)) - 1.0);
void
addTileStatements
(
String
source
,
String
destination
,
ui
.
TileMode
tileMode
)
{
switch
(
tileMode
)
{
case
ui
.
TileMode
.
repeated
:
addStatement
(
'float
$destination
= fract(
$source
);'
);
break
;
case
ui
.
TileMode
.
mirror
:
addStatement
(
'float
$destination
= (
$source
- 1.0);'
);
addStatement
(
'
$destination
= '
'abs((
$destination
- 2.0 * floor(
$destination
* 0.5)) - 1.0);'
);
break
;
case
ui
.
TileMode
.
clamp
:
case
ui
.
TileMode
.
decal
:
addStatement
(
'float
$destination
=
$source
;'
);
break
;
}
}
void
write
(
StringBuffer
buffer
)
{
buffer
.
writeln
(
'
$returnType
$name
() {'
);
for
(
String
statement
in
_statements
)
{
...
...
lib/web_ui/lib/src/ui/painting.dart
浏览文件 @
060f108c
...
...
@@ -693,12 +693,9 @@ class Shadow {
class
ImageShader
extends
Shader
{
factory
ImageShader
(
Image
image
,
TileMode
tmx
,
TileMode
tmy
,
Float64List
matrix4
,
{
FilterQuality
?
filterQuality
,
})
{
if
(
engine
.
useCanvasKit
)
{
return
engine
.
CkImageShader
(
image
,
tmx
,
tmy
,
matrix4
,
filterQuality
);
}
throw
UnsupportedError
(
'ImageShader not implemented for web platform.'
);
}
})
=>
engine
.
useCanvasKit
?
engine
.
CkImageShader
(
image
,
tmx
,
tmy
,
matrix4
,
filterQuality
)
:
engine
.
ImageShader
(
image
,
tmx
,
tmy
,
matrix4
,
filterQuality
);
}
class
ImmutableBuffer
{
...
...
lib/web_ui/test/golden_tests/engine/draw_vertices_golden_test.dart
浏览文件 @
060f108c
...
...
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:html'
as
html
;
import
'dart:typed_data'
;
import
'dart:js_util'
as
js_util
;
import
'package:test/bootstrap/browser.dart'
;
import
'package:test/test.dart'
;
import
'package:ui/ui.dart'
hide
TextStyle
;
import
'package:ui/ui.dart'
hide
TextStyle
,
ImageShader
;
import
'package:ui/src/engine.dart'
;
import
'package:web_engine_tester/golden_tester.dart'
;
...
...
@@ -24,9 +26,10 @@ void testMain() async {
// Commit a recording canvas to a bitmap, and compare with the expected
Future
<
void
>
_checkScreenshot
(
RecordingCanvas
rc
,
String
fileName
,
{
Rect
region
=
const
Rect
.
fromLTWH
(
0
,
0
,
500
,
500
),
bool
write
=
false
})
async
{
final
EngineCanvas
engineCanvas
=
BitmapCanvas
(
screenRect
,
RenderStrategy
());
double
maxDiffRatePercent
=
0.0
,
bool
write
=
false
})
async
{
final
EngineCanvas
engineCanvas
=
BitmapCanvas
(
screenRect
,
RenderStrategy
());
rc
.
endRecording
();
rc
.
apply
(
engineCanvas
,
screenRect
);
...
...
@@ -39,7 +42,7 @@ void testMain() async {
'
$fileName
.png'
,
region:
region
,
write:
write
,
maxDiffRatePercent:
0.0
,
maxDiffRatePercent:
maxDiffRatePercent
,
);
}
finally
{
// The page is reused across tests, so remove the element after taking the
...
...
@@ -56,179 +59,353 @@ void testMain() async {
await
webOnlyFontCollection
.
ensureFontsLoaded
();
});
Future
<
void
>
_testVertices
(
String
fileName
,
Vertices
vertices
,
BlendMode
blendMode
,
Paint
paint
,
{
bool
write:
false
})
async
{
Future
<
void
>
_testVertices
(
String
fileName
,
Vertices
vertices
,
BlendMode
blendMode
,
Paint
paint
,
{
bool
write:
false
})
async
{
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
rc
.
drawVertices
(
vertices
as
SurfaceVertices
,
blendMode
,
paint
as
SurfacePaint
);
rc
.
drawVertices
(
vertices
as
SurfaceVertices
,
blendMode
,
paint
as
SurfacePaint
);
await
_checkScreenshot
(
rc
,
fileName
,
write:
write
);
}
test
(
'Should draw green hairline triangles when colors array is null.'
,
()
async
{
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
()
async
{
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]));
await
_testVertices
(
'draw_vertices_hairline_triangle'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
await
_testVertices
(
'draw_vertices_hairline_triangle'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
});
test
(
'Should draw black hairline triangles when colors array is null'
'
and Paint() has no color.'
,
()
async
{
test
(
'
Should draw black hairline triangles when colors array is null'
' and Paint() has no color.'
,
()
async
{
// ignore: unused_local_variable
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]));
await
_testVertices
(
'draw_vertices_hairline_triangle_black'
,
vertices
,
BlendMode
.
srcOver
,
Paint
());
await
_testVertices
(
'draw_vertices_hairline_triangle_black'
,
vertices
,
BlendMode
.
srcOver
,
Paint
());
});
/// Regression test for https://github.com/flutter/flutter/issues/71442.
test
(
'Should draw filled triangles when colors array is null'
' and Paint() has color.'
,
()
async
{
// ignore: unused_local_variable
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]));
await
_testVertices
(
'draw_vertices_triangle_green_filled'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()
..
style
=
PaintingStyle
.
fill
..
color
=
const
Color
(
0xFF00FF00
)
);
});
test
(
'Should draw hairline triangleFan.'
,
()
async
{
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleFan
,
test
(
'Should draw filled triangles when colors array is null'
' and Paint() has color.'
,
()
async
{
// ignore: unused_local_variable
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
150.0
,
150.0
,
20.0
,
10.0
,
80.0
,
20.0
,
220.0
,
15.0
,
280.0
,
30.0
,
300.0
,
420.0
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]));
await
_testVertices
(
'draw_vertices_
hairline_triangle_fan
'
,
'draw_vertices_
triangle_green_filled
'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
Paint
()
..
style
=
PaintingStyle
.
fill
..
color
=
const
Color
(
0xFF00FF00
));
});
test
(
'Should draw hairline triangle
Strip.'
,
()
async
{
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleStrip
,
test
(
'Should draw hairline triangle
Fan.'
,
()
async
{
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleFan
,
Float32List
.
fromList
([
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
150.0
,
150.0
,
20.0
,
10.0
,
80.0
,
20.0
,
220.0
,
15.0
,
280.0
,
30.0
,
300.0
,
420.0
]));
await
_testVertices
(
'draw_vertices_hairline_triangle_strip'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
await
_testVertices
(
'draw_vertices_hairline_triangle_fan'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
});
test
(
'Should draw triangles with colors.'
,
()
async
{
test
(
'Should draw hairline triangleStrip.'
,
()
async
{
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleStrip
,
Float32List
.
fromList
([
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]));
await
_testVertices
(
'draw_vertices_hairline_triangle_strip'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
});
test
(
'Should draw triangles with colors.'
,
()
async
{
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
150.0
,
150.0
,
20.0
,
10.0
,
80.0
,
20.0
,
220.0
,
15.0
,
280.0
,
30.0
,
300.0
,
420.0
]),
colors:
colors
);
150.0
,
150.0
,
20.0
,
10.0
,
80.0
,
20.0
,
220.0
,
15.0
,
280.0
,
30.0
,
300.0
,
420.0
]),
colors:
colors
);
await
_testVertices
(
'draw_vertices_triangles'
,
vertices
,
BlendMode
.
srcOver
,
await
_testVertices
(
'draw_vertices_triangles'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
});
test
(
'Should draw triangles with colors and indices.'
,
()
async
{
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF0000FF
]);
final
Uint16List
indices
=
Uint16List
.
fromList
(<
int
>[
0
,
1
,
2
,
3
,
4
,
0
]);
final
Int32List
colors
=
Int32List
.
fromList
(
<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF0000FF
]);
final
Uint16List
indices
=
Uint16List
.
fromList
(<
int
>[
0
,
1
,
2
,
3
,
4
,
0
]);
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
210.0
,
150.0
,
30.0
,
110.0
,
80.0
,
30.0
,
220.0
,
15.0
,
280.0
,
30.0
,
]),
colors:
colors
,
210.0
,
150.0
,
30.0
,
110.0
,
80.0
,
30.0
,
220.0
,
15.0
,
280.0
,
30.0
,
]),
colors:
colors
,
indices:
indices
);
rc
.
drawVertices
(
vertices
as
SurfaceVertices
,
BlendMode
.
srcOver
,
SurfacePaint
());
rc
.
drawVertices
(
vertices
as
SurfaceVertices
,
BlendMode
.
srcOver
,
SurfacePaint
());
await
_checkScreenshot
(
rc
,
'draw_vertices_triangles_indexed'
);
});
test
(
'Should draw triangleFan with colors.'
,
()
async
{
test
(
'Should draw triangleFan with colors.'
,
()
async
{
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleFan
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleFan
,
Float32List
.
fromList
([
150.0
,
150.0
,
20.0
,
10.0
,
80.0
,
20.0
,
220.0
,
15.0
,
280.0
,
30.0
,
300.0
,
420.0
]),
colors:
colors
);
150.0
,
150.0
,
20.0
,
10.0
,
80.0
,
20.0
,
220.0
,
15.0
,
280.0
,
30.0
,
300.0
,
420.0
]),
colors:
colors
);
await
_testVertices
(
'draw_vertices_triangle_fan'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
await
_testVertices
(
'draw_vertices_triangle_fan'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
});
test
(
'Should draw triangleStrip with colors.'
,
()
async
{
test
(
'Should draw triangleStrip with colors.'
,
()
async
{
final
Int32List
colors
=
Int32List
.
fromList
(<
int
>[
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleStrip
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
,
0xFFFF0000
,
0xFF00FF00
,
0xFF0000FF
]);
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangleStrip
,
Float32List
.
fromList
([
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]),
colors:
colors
);
await
_testVertices
(
'draw_vertices_triangle_strip'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
20.0
,
20.0
,
220.0
,
10.0
,
110.0
,
220.0
,
220.0
,
320.0
,
20.0
,
310.0
,
200.0
,
420.0
]),
colors:
colors
);
await
_testVertices
(
'draw_vertices_triangle_strip'
,
vertices
,
BlendMode
.
srcOver
,
Paint
()..
color
=
Color
.
fromARGB
(
255
,
0
,
128
,
0
));
});
Future
<
void
>
testTexture
(
TileMode
tileMode
,
String
filename
)
async
{
final
Uint16List
indices
=
Uint16List
.
fromList
(<
int
>[
0
,
1
,
2
,
3
,
4
,
0
]);
final
RecordingCanvas
rc
=
RecordingCanvas
(
const
Rect
.
fromLTRB
(
0
,
0
,
500
,
500
));
final
Vertices
vertices
=
Vertices
.
raw
(
VertexMode
.
triangles
,
Float32List
.
fromList
([
210.0
,
150.0
,
0.0
,
0.0
,
80.0
,
30.0
,
220.0
,
15.0
,
280.0
,
30.0
,
]),
indices:
indices
);
Float32List
matrix4
=
Matrix4
.
identity
().
storage
;
final
HtmlImage
img
=
await
createTestImage
();
final
SurfacePaint
paint
=
SurfacePaint
();
final
ImageShader
imgShader
=
ImageShader
(
img
,
tileMode
,
tileMode
,
Float64List
.
fromList
(
matrix4
),
FilterQuality
.
high
);
paint
.
shader
=
imgShader
;
rc
.
drawVertices
(
vertices
as
SurfaceVertices
,
BlendMode
.
srcOver
,
paint
);
await
_checkScreenshot
(
rc
,
filename
,
maxDiffRatePercent:
1.0
);
}
test
(
'Should draw triangle with texture and indices'
,
()
async
{
await
testTexture
(
TileMode
.
clamp
,
'draw_vertices_texture'
);
});
test
(
'Should draw triangle with texture and indices'
,
()
async
{
await
testTexture
(
TileMode
.
mirror
,
'draw_vertices_texture_mirror'
);
});
test
(
'Should draw triangle with texture and indices'
,
()
async
{
await
testTexture
(
TileMode
.
repeated
,
'draw_vertices_texture_repeated'
);
});
}
Future
<
HtmlImage
>
createTestImage
({
int
width
=
50
,
int
height
=
40
})
{
html
.
CanvasElement
canvas
=
new
html
.
CanvasElement
(
width:
width
,
height:
height
);
html
.
CanvasRenderingContext2D
ctx
=
canvas
.
context2D
;
ctx
.
fillStyle
=
'#E04040'
;
ctx
.
fillRect
(
0
,
0
,
width
/
3
,
height
);
ctx
.
fill
();
ctx
.
fillStyle
=
'#40E080'
;
ctx
.
fillRect
(
width
/
3
,
0
,
width
/
3
,
height
);
ctx
.
fill
();
ctx
.
fillStyle
=
'#2040E0'
;
ctx
.
fillRect
(
2
*
width
/
3
,
0
,
width
/
3
,
height
);
ctx
.
fill
();
html
.
ImageElement
imageElement
=
html
.
ImageElement
();
Completer
<
HtmlImage
>
completer
=
Completer
();
imageElement
.
onLoad
.
listen
((
event
)
{
completer
.
complete
(
HtmlImage
(
imageElement
,
width
,
height
));
});
imageElement
.
src
=
js_util
.
callMethod
(
canvas
,
'toDataURL'
,
<
dynamic
>[]);
return
completer
.
future
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录