blob: 461758837f836ccd1be4121991d2ab70ea6f941b [file] [log] [blame]
Chris Craik03188872015-02-02 18:39:33 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "GlopBuilder.h"
17
18#include "Caches.h"
19#include "Glop.h"
20#include "Matrix.h"
Chris Craik03188872015-02-02 18:39:33 -080021#include "renderstate/MeshState.h"
22#include "renderstate/RenderState.h"
Chris Craik117bdbc2015-02-05 10:12:38 -080023#include "SkiaShader.h"
24#include "Texture.h"
Chris Craik03188872015-02-02 18:39:33 -080025#include "utils/PaintUtils.h"
Chris Craik117bdbc2015-02-05 10:12:38 -080026#include "VertexBuffer.h"
Chris Craik03188872015-02-02 18:39:33 -080027
28#include <GLES2/gl2.h>
29#include <SkPaint.h>
30
31namespace android {
32namespace uirenderer {
33
Chris Craik117bdbc2015-02-05 10:12:38 -080034#define TRIGGER_STAGE(stageFlag) \
35 LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
Chris Craik0519c812015-02-11 13:17:06 -080036 mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
Chris Craik117bdbc2015-02-05 10:12:38 -080037
Chris Craik08fa43f2015-02-09 18:58:32 -080038#define REQUIRE_STAGES(requiredFlags) \
Chris Craik0519c812015-02-11 13:17:06 -080039 LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
Chris Craik08fa43f2015-02-09 18:58:32 -080040 "not prepared for current stage")
41
Chris Craik922d3a72015-02-13 17:47:21 -080042static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
Chris Craik0519c812015-02-11 13:17:06 -080043 TextureVertex::setUV(quadVertex++, uvs.left, uvs.top);
44 TextureVertex::setUV(quadVertex++, uvs.right, uvs.top);
45 TextureVertex::setUV(quadVertex++, uvs.left, uvs.bottom);
46 TextureVertex::setUV(quadVertex++, uvs.right, uvs.bottom);
47}
48
Chris Craik03188872015-02-02 18:39:33 -080049GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
50 : mRenderState(renderState)
51 , mCaches(caches)
Chris Craik922d3a72015-02-13 17:47:21 -080052 , mShader(nullptr)
Chris Craik0519c812015-02-11 13:17:06 -080053 , mOutGlop(outGlop) {
Chris Craik117bdbc2015-02-05 10:12:38 -080054 mStageFlags = kInitialStage;
55}
56
Chris Craik0519c812015-02-11 13:17:06 -080057////////////////////////////////////////////////////////////////////////////////
58// Mesh
59////////////////////////////////////////////////////////////////////////////////
60
61GlopBuilder& GlopBuilder::setMeshUnitQuad() {
62 TRIGGER_STAGE(kMeshStage);
63
64 mOutGlop->mesh.vertexFlags = kNone_Attrib;
65 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
66 mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
67 mOutGlop->mesh.vertices = nullptr;
68 mOutGlop->mesh.indexBufferObject = 0;
69 mOutGlop->mesh.indices = nullptr;
70 mOutGlop->mesh.elementCount = 4;
71 mOutGlop->mesh.stride = kTextureVertexStride;
72 mOutGlop->mesh.texCoordOffset = nullptr;
73 return *this;
74}
75
Chris Craikf27133d2015-02-19 09:51:53 -080076GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
Chris Craik0519c812015-02-11 13:17:06 -080077 TRIGGER_STAGE(kMeshStage);
78
79 mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
80 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
81
82 if (CC_UNLIKELY(uvMapper)) {
83 Rect uvs(0, 0, 1, 1);
84 uvMapper->map(uvs);
85 setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
86
87 mOutGlop->mesh.vertexBufferObject = 0;
88 mOutGlop->mesh.vertices = &mOutGlop->mesh.mappedVertices[0];
Chris Craikf27133d2015-02-19 09:51:53 -080089 mOutGlop->mesh.texCoordOffset = &mOutGlop->mesh.mappedVertices[0].u;
Chris Craik0519c812015-02-11 13:17:06 -080090 } else {
91 // standard UV coordinates, use regular unit quad VBO
92 mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
93 mOutGlop->mesh.vertices = nullptr;
Chris Craikf27133d2015-02-19 09:51:53 -080094 mOutGlop->mesh.texCoordOffset = (GLvoid*) kMeshTextureOffset;
Chris Craik0519c812015-02-11 13:17:06 -080095 }
96 mOutGlop->mesh.indexBufferObject = 0;
97 mOutGlop->mesh.indices = nullptr;
98 mOutGlop->mesh.elementCount = 4;
99 mOutGlop->mesh.stride = kTextureVertexStride;
Chris Craik0519c812015-02-11 13:17:06 -0800100 mDescription.hasTexture = true;
Chris Craik0519c812015-02-11 13:17:06 -0800101 return *this;
102}
103
104GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
105 TRIGGER_STAGE(kMeshStage);
106
107 mOutGlop->mesh.vertexFlags = kNone_Attrib;
108 mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
109 mOutGlop->mesh.vertexBufferObject = 0;
110 mOutGlop->mesh.vertices = vertexData;
111 mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
112 mOutGlop->mesh.indices = nullptr;
Chris Craikf27133d2015-02-19 09:51:53 -0800113 mOutGlop->mesh.texCoordOffset = nullptr;
Chris Craik0519c812015-02-11 13:17:06 -0800114 mOutGlop->mesh.elementCount = 6 * quadCount;
115 mOutGlop->mesh.stride = kVertexStride;
Chris Craik0519c812015-02-11 13:17:06 -0800116
117 return *this;
118}
119
Chris Craikf27133d2015-02-19 09:51:53 -0800120GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) {
121 TRIGGER_STAGE(kMeshStage);
122
123 mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
124 mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
125 mOutGlop->mesh.vertexBufferObject = 0;
126 mOutGlop->mesh.vertices = &vertexData[0].x;
127 mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
128 mOutGlop->mesh.indices = nullptr;
129 mOutGlop->mesh.texCoordOffset = &vertexData[0].u;
130 mOutGlop->mesh.elementCount = elementCount;
131 mOutGlop->mesh.stride = kTextureVertexStride;
132 mDescription.hasTexture = true;
133 return *this;
134}
135
Chris Craik117bdbc2015-02-05 10:12:38 -0800136GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
137 TRIGGER_STAGE(kMeshStage);
138
139 const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags();
140
141 bool alphaVertex = flags & VertexBuffer::kAlpha;
142 bool indices = flags & VertexBuffer::kIndices;
143 mOutGlop->mesh.vertexFlags = alphaVertex ? kAlpha_Attrib : kNone_Attrib;
144 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
145 mOutGlop->mesh.vertexBufferObject = 0;
146 mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
147 mOutGlop->mesh.indexBufferObject = 0;
148 mOutGlop->mesh.indices = vertexBuffer.getIndices();
Chris Craikf27133d2015-02-19 09:51:53 -0800149 mOutGlop->mesh.texCoordOffset = nullptr;
Chris Craik0519c812015-02-11 13:17:06 -0800150 mOutGlop->mesh.elementCount = indices
Chris Craik117bdbc2015-02-05 10:12:38 -0800151 ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
152 mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
153
154 mDescription.hasVertexAlpha = alphaVertex;
155 mDescription.useShadowAlphaInterp = shadowInterp;
156 return *this;
Chris Craik03188872015-02-02 18:39:33 -0800157}
158
Chris Craik0519c812015-02-11 13:17:06 -0800159////////////////////////////////////////////////////////////////////////////////
160// Fill
161////////////////////////////////////////////////////////////////////////////////
Chris Craik117bdbc2015-02-05 10:12:38 -0800162
Chris Craik0519c812015-02-11 13:17:06 -0800163void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode,
164 const SkShader* shader, const SkColorFilter* colorFilter) {
Chris Craik03188872015-02-02 18:39:33 -0800165 if (mode != SkXfermode::kClear_Mode) {
Chris Craik03188872015-02-02 18:39:33 -0800166 float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
Chris Craik117bdbc2015-02-05 10:12:38 -0800167 if (!shader) {
168 float colorScale = alpha / 255.0f;
169 mOutGlop->fill.color = {
Chris Craik117bdbc2015-02-05 10:12:38 -0800170 colorScale * SkColorGetR(color),
171 colorScale * SkColorGetG(color),
Chris Craik0519c812015-02-11 13:17:06 -0800172 colorScale * SkColorGetB(color),
173 alpha
Chris Craik117bdbc2015-02-05 10:12:38 -0800174 };
175 } else {
Chris Craik0519c812015-02-11 13:17:06 -0800176 mOutGlop->fill.color = { 1, 1, 1, alpha };
Chris Craik03188872015-02-02 18:39:33 -0800177 }
Chris Craik03188872015-02-02 18:39:33 -0800178 } else {
Chris Craik0519c812015-02-11 13:17:06 -0800179 mOutGlop->fill.color = { 0, 0, 0, 1 };
Chris Craik03188872015-02-02 18:39:33 -0800180 }
181 const bool SWAP_SRC_DST = false;
Chris Craik03188872015-02-02 18:39:33 -0800182
Chris Craik117bdbc2015-02-05 10:12:38 -0800183 mOutGlop->blend = { GL_ZERO, GL_ZERO };
Chris Craik03188872015-02-02 18:39:33 -0800184 if (mOutGlop->fill.color.a < 1.0f
Chris Craik08fa43f2015-02-09 18:58:32 -0800185 || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
Chris Craikf27133d2015-02-19 09:51:53 -0800186 || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
Chris Craik0519c812015-02-11 13:17:06 -0800187 || mOutGlop->roundRectClipState
Chris Craik117bdbc2015-02-05 10:12:38 -0800188 || PaintUtils::isBlendedShader(shader)
Chris Craik03188872015-02-02 18:39:33 -0800189 || PaintUtils::isBlendedColorFilter(colorFilter)
190 || mode != SkXfermode::kSrcOver_Mode) {
191 if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
192 Blend::getFactors(mode, SWAP_SRC_DST,
193 &mOutGlop->blend.src, &mOutGlop->blend.dst);
194 } else {
195 // These blend modes are not supported by OpenGL directly and have
196 // to be implemented using shaders. Since the shader will perform
197 // the blending, don't enable GL blending off here
198 // If the blend mode cannot be implemented using shaders, fall
199 // back to the default SrcOver blend mode instead
Chris Craik117bdbc2015-02-05 10:12:38 -0800200 if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
Chris Craik03188872015-02-02 18:39:33 -0800201 mDescription.framebufferMode = mode;
202 mDescription.swapSrcDst = SWAP_SRC_DST;
203 // blending in shader, don't enable
204 } else {
205 // unsupported
206 Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
207 &mOutGlop->blend.src, &mOutGlop->blend.dst);
208 }
209 }
210 }
Chris Craik922d3a72015-02-13 17:47:21 -0800211 mShader = shader; // shader resolved in ::build()
Chris Craik03188872015-02-02 18:39:33 -0800212
Chris Craik117bdbc2015-02-05 10:12:38 -0800213 if (colorFilter) {
214 SkColor color;
215 SkXfermode::Mode mode;
216 SkScalar srcColorMatrix[20];
217 if (colorFilter->asColorMode(&color, &mode)) {
218 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
219 mDescription.colorMode = mode;
220
221 const float alpha = SkColorGetA(color) / 255.0f;
222 float colorScale = alpha / 255.0f;
223 mOutGlop->fill.filter.color = {
Chris Craik117bdbc2015-02-05 10:12:38 -0800224 colorScale * SkColorGetR(color),
225 colorScale * SkColorGetG(color),
226 colorScale * SkColorGetB(color),
Chris Craik0519c812015-02-11 13:17:06 -0800227 alpha,
Chris Craik117bdbc2015-02-05 10:12:38 -0800228 };
229 } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
230 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
231
232 float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
233 memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
234 memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
235 memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
236 memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
237
238 // Skia uses the range [0..255] for the addition vector, but we need
239 // the [0..1] range to apply the vector in GLSL
240 float* colorVector = mOutGlop->fill.filter.matrix.vector;
241 colorVector[0] = srcColorMatrix[4] / 255.0f;
242 colorVector[1] = srcColorMatrix[9] / 255.0f;
243 colorVector[2] = srcColorMatrix[14] / 255.0f;
244 colorVector[3] = srcColorMatrix[19] / 255.0f;
Chris Craik2ab95d72015-02-06 15:25:51 -0800245 } else {
246 LOG_ALWAYS_FATAL("unsupported ColorFilter");
Chris Craik117bdbc2015-02-05 10:12:38 -0800247 }
248 } else {
249 mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
250 }
Chris Craik0519c812015-02-11 13:17:06 -0800251}
Chris Craik117bdbc2015-02-05 10:12:38 -0800252
Chris Craik0519c812015-02-11 13:17:06 -0800253GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
254 const SkPaint* paint, float alphaScale) {
255 TRIGGER_STAGE(kFillStage);
256 REQUIRE_STAGES(kMeshStage);
257
Chris Craikf27133d2015-02-19 09:51:53 -0800258 mOutGlop->fill.texture = { &texture, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE };
Chris Craik0519c812015-02-11 13:17:06 -0800259
260 if (paint) {
261 int color = paint->getColor();
262 SkShader* shader = paint->getShader();
263
264 if (!isAlphaMaskTexture) {
265 // Texture defines color, so disable shaders, and reset all non-alpha color channels
266 color |= 0x00FFFFFF;
267 shader = nullptr;
268 }
269 setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()),
270 shader, paint->getColorFilter());
271 } else {
272 mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
273
274 const bool SWAP_SRC_DST = false;
275 if (alphaScale < 1.0f
276 || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
277 || texture.blend
278 || mOutGlop->roundRectClipState) {
279 Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
280 &mOutGlop->blend.src, &mOutGlop->blend.dst);
281 } else {
282 mOutGlop->blend = { GL_ZERO, GL_ZERO };
283 }
284 }
285
Chris Craikf27133d2015-02-19 09:51:53 -0800286 mDescription.hasAlpha8Texture = isAlphaMaskTexture;
Chris Craik0519c812015-02-11 13:17:06 -0800287 if (isAlphaMaskTexture) {
Chris Craik2bb8f562015-02-17 16:42:02 -0800288 mDescription.modulate = mOutGlop->fill.color.isNotBlack();
Chris Craik0519c812015-02-11 13:17:06 -0800289 } else {
290 mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
291 }
Chris Craik03188872015-02-02 18:39:33 -0800292 return *this;
293}
294
Chris Craik0519c812015-02-11 13:17:06 -0800295GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
296 TRIGGER_STAGE(kFillStage);
297 REQUIRE_STAGES(kMeshStage);
298
Chris Craikf27133d2015-02-19 09:51:53 -0800299 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
Chris Craik0519c812015-02-11 13:17:06 -0800300
301 setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
302 paint.getShader(), paint.getColorFilter());
303 mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
304 return *this;
305}
306
Chris Craik2bb8f562015-02-17 16:42:02 -0800307GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
Chris Craik30036092015-02-12 10:41:39 -0800308 const SkPaint& paint, float alphaScale) {
309 TRIGGER_STAGE(kFillStage);
310 REQUIRE_STAGES(kMeshStage);
311
Chris Craikf27133d2015-02-19 09:51:53 -0800312 //specify invalid filter/clamp, since these are always static for PathTextures
313 mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
Chris Craik30036092015-02-12 10:41:39 -0800314
315 setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
316 paint.getShader(), paint.getColorFilter());
317
Chris Craikf27133d2015-02-19 09:51:53 -0800318 mDescription.hasAlpha8Texture = true;
Chris Craik2bb8f562015-02-17 16:42:02 -0800319 mDescription.modulate = mOutGlop->fill.color.isNotBlack();
Chris Craik30036092015-02-12 10:41:39 -0800320 return *this;
321}
322
Chris Craik2bb8f562015-02-17 16:42:02 -0800323GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
324 const SkPaint& paint, float alphaScale) {
325 TRIGGER_STAGE(kFillStage);
326 REQUIRE_STAGES(kMeshStage);
327
Chris Craikf27133d2015-02-19 09:51:53 -0800328 //specify invalid filter/clamp, since these are always static for ShadowTextures
329 mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
Chris Craik2bb8f562015-02-17 16:42:02 -0800330
331 const int ALPHA_BITMASK = SK_ColorBLACK;
332 const int COLOR_BITMASK = ~ALPHA_BITMASK;
333 if ((shadowColor & ALPHA_BITMASK) == ALPHA_BITMASK) {
334 // shadow color is fully opaque: override its alpha with that of paint
335 shadowColor &= paint.getColor() | COLOR_BITMASK;
336 }
337
338 setFill(shadowColor, alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
339 paint.getShader(), paint.getColorFilter());
340
Chris Craikf27133d2015-02-19 09:51:53 -0800341 mDescription.hasAlpha8Texture = true;
Chris Craik2bb8f562015-02-17 16:42:02 -0800342 mDescription.modulate = mOutGlop->fill.color.isNotBlack();
343 return *this;
344}
345
346GlopBuilder& GlopBuilder::setFillBlack() {
347 TRIGGER_STAGE(kFillStage);
348 REQUIRE_STAGES(kMeshStage);
349
Chris Craikf27133d2015-02-19 09:51:53 -0800350 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
Chris Craik2bb8f562015-02-17 16:42:02 -0800351 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr);
Chris Craik2bb8f562015-02-17 16:42:02 -0800352 return *this;
353}
354
355GlopBuilder& GlopBuilder::setFillClear() {
356 TRIGGER_STAGE(kFillStage);
357 REQUIRE_STAGES(kMeshStage);
358
Chris Craikf27133d2015-02-19 09:51:53 -0800359 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
Chris Craik2bb8f562015-02-17 16:42:02 -0800360 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr);
Chris Craik2bb8f562015-02-17 16:42:02 -0800361 return *this;
362}
Chris Craikf27133d2015-02-19 09:51:53 -0800363
364GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
365 float alpha, SkXfermode::Mode mode) {
366 TRIGGER_STAGE(kFillStage);
367 REQUIRE_STAGES(kMeshStage);
368
369 mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE };
370 mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
371
372 setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter);
373
374 mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
375 return *this;
376}
377
Chris Craik0519c812015-02-11 13:17:06 -0800378////////////////////////////////////////////////////////////////////////////////
379// Transform
380////////////////////////////////////////////////////////////////////////////////
381
Chris Craikf27133d2015-02-19 09:51:53 -0800382GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
Chris Craik0519c812015-02-11 13:17:06 -0800383 const Matrix4& transform, bool fudgingOffset) {
384 TRIGGER_STAGE(kTransformStage);
385
386 mOutGlop->transform.ortho.load(ortho);
387 mOutGlop->transform.canvas.load(transform);
388 mOutGlop->transform.fudgingOffset = fudgingOffset;
389 return *this;
390}
391
Chris Craik0519c812015-02-11 13:17:06 -0800392////////////////////////////////////////////////////////////////////////////////
393// ModelView
394////////////////////////////////////////////////////////////////////////////////
395
396GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
397 TRIGGER_STAGE(kModelViewStage);
398
399 mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
400 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
401 mOutGlop->bounds = destination;
402 return *this;
403}
404
405GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) {
406 TRIGGER_STAGE(kModelViewStage);
407 REQUIRE_STAGES(kTransformStage | kFillStage);
408
409 float left = destination.left;
410 float top = destination.top;
411
412 const Matrix4& canvasTransform = mOutGlop->transform.canvas;
413 if (CC_LIKELY(canvasTransform.isPureTranslate())) {
Chris Craikf27133d2015-02-19 09:51:53 -0800414 // snap by adjusting the model view matrix
Chris Craik0519c812015-02-11 13:17:06 -0800415 const float translateX = canvasTransform.getTranslateX();
416 const float translateY = canvasTransform.getTranslateY();
417
418 left = (int) floorf(left + translateX + 0.5f) - translateX;
419 top = (int) floorf(top + translateY + 0.5f) - translateY;
Chris Craikf27133d2015-02-19 09:51:53 -0800420 mOutGlop->fill.texture.filter = GL_NEAREST;
Chris Craik0519c812015-02-11 13:17:06 -0800421 }
422
423 mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
424 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
425 mOutGlop->bounds = destination;
426 return *this;
427}
428
429GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
430 TRIGGER_STAGE(kModelViewStage);
431
432 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
433 mOutGlop->bounds = source;
434 mOutGlop->bounds.translate(offsetX, offsetY);
435 return *this;
436}
437
Chris Craikf27133d2015-02-19 09:51:53 -0800438GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
439 TRIGGER_STAGE(kModelViewStage);
440 REQUIRE_STAGES(kTransformStage | kFillStage);
441
442 const Matrix4& canvasTransform = mOutGlop->transform.canvas;
443 if (CC_LIKELY(canvasTransform.isPureTranslate())) {
444 // snap by adjusting the model view matrix
445 const float translateX = canvasTransform.getTranslateX();
446 const float translateY = canvasTransform.getTranslateY();
447
448 offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
449 offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
450 mOutGlop->fill.texture.filter = GL_NEAREST;
451 }
452
453 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
454 mOutGlop->bounds.translate(offsetX, offsetY);
455 return *this;
456}
457
458////////////////////////////////////////////////////////////////////////////////
459// RoundRectClip
460////////////////////////////////////////////////////////////////////////////////
461
Chris Craik0519c812015-02-11 13:17:06 -0800462GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
463 TRIGGER_STAGE(kRoundRectClipStage);
464
465 mOutGlop->roundRectClipState = roundRectClipState;
466 mDescription.hasRoundRectClip = roundRectClipState != nullptr;
467 return *this;
468}
469
470////////////////////////////////////////////////////////////////////////////////
471// Build
472////////////////////////////////////////////////////////////////////////////////
473
Chris Craikf27133d2015-02-19 09:51:53 -0800474void verify(const ProgramDescription& description, const Glop& glop) {
475 bool hasTexture = glop.fill.texture.texture != nullptr;
476 LOG_ALWAYS_FATAL_IF(description.hasTexture != hasTexture);
477 LOG_ALWAYS_FATAL_IF((glop.mesh.vertexFlags & kTextureCoord_Attrib) != hasTexture);
478}
479
Chris Craik03188872015-02-02 18:39:33 -0800480void GlopBuilder::build() {
Chris Craik08fa43f2015-02-09 18:58:32 -0800481 REQUIRE_STAGES(kAllStages);
Chris Craik117bdbc2015-02-05 10:12:38 -0800482
Chris Craik922d3a72015-02-13 17:47:21 -0800483 // serialize shader info into ShaderData
Chris Craikf27133d2015-02-19 09:51:53 -0800484 GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
Chris Craik922d3a72015-02-13 17:47:21 -0800485 SkiaShader::store(mCaches, mShader, mOutGlop->transform.modelView,
486 &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
487
Chris Craik03188872015-02-02 18:39:33 -0800488 mOutGlop->fill.program = mCaches.programCache.get(mDescription);
Chris Craik117bdbc2015-02-05 10:12:38 -0800489 mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
Chris Craik0519c812015-02-11 13:17:06 -0800490
491 // duplicates ProgramCache's definition of color uniform presence
492 const bool singleColor = !mDescription.hasTexture
493 && !mDescription.hasExternalTexture
494 && !mDescription.hasGradient
495 && !mDescription.hasBitmap;
496 mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
Chris Craikf27133d2015-02-19 09:51:53 -0800497
498 verify(mDescription, *mOutGlop);
Chris Craik03188872015-02-02 18:39:33 -0800499}
500
501} /* namespace uirenderer */
502} /* namespace android */