1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // FogTest.cpp: Tests basic usage of glFog.
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 #include "util/random_utils.h"
13
14 #include <stdint.h>
15
16 using namespace angle;
17
18 class FogTest : public ANGLETest<>
19 {
20 protected:
FogTest()21 FogTest()
22 {
23 setWindowWidth(32);
24 setWindowHeight(32);
25 setConfigRedBits(8);
26 setConfigGreenBits(8);
27 setConfigBlueBits(8);
28 setConfigAlphaBits(8);
29 setConfigDepthBits(24);
30 }
31 };
32
33 // Initial state check.
TEST_P(FogTest,InitialState)34 TEST_P(FogTest, InitialState)
35 {
36 EXPECT_GL_FALSE(glIsEnabled(GL_FOG));
37 EXPECT_GL_NO_ERROR();
38
39 GLint fogMode;
40 glGetIntegerv(GL_FOG_MODE, &fogMode);
41 EXPECT_GL_NO_ERROR();
42 EXPECT_GLENUM_EQ(GL_EXP, fogMode);
43
44 GLfloat fogModeAsFloat;
45 glGetFloatv(GL_FOG_MODE, &fogModeAsFloat);
46 EXPECT_GL_NO_ERROR();
47 EXPECT_GLENUM_EQ(GL_EXP, fogModeAsFloat);
48
49 GLfloat fogStart;
50 GLfloat fogEnd;
51 GLfloat fogDensity;
52
53 glGetFloatv(GL_FOG_START, &fogStart);
54 EXPECT_GL_NO_ERROR();
55 glGetFloatv(GL_FOG_END, &fogEnd);
56 EXPECT_GL_NO_ERROR();
57 glGetFloatv(GL_FOG_DENSITY, &fogDensity);
58 EXPECT_GL_NO_ERROR();
59
60 EXPECT_EQ(0.0f, fogStart);
61 EXPECT_EQ(1.0f, fogEnd);
62 EXPECT_EQ(1.0f, fogDensity);
63
64 const GLColor32F kInitialFogColor(0.0f, 0.0f, 0.0f, 0.0f);
65 GLColor32F initialFogColor;
66 glGetFloatv(GL_FOG_COLOR, &initialFogColor.R);
67 EXPECT_GL_NO_ERROR();
68
69 EXPECT_EQ(kInitialFogColor, initialFogColor);
70 }
71
72 // Negative test for parameter names.
TEST_P(FogTest,NegativeParameter)73 TEST_P(FogTest, NegativeParameter)
74 {
75 glFogfv(0, nullptr);
76 EXPECT_GL_ERROR(GL_INVALID_ENUM);
77 }
78
79 // Negative test for parameter values.
TEST_P(FogTest,NegativeValues)80 TEST_P(FogTest, NegativeValues)
81 {
82 glFogf(GL_FOG_MODE, 0.0f);
83 EXPECT_GL_ERROR(GL_INVALID_VALUE);
84
85 glFogf(GL_FOG_DENSITY, -1.0f);
86 EXPECT_GL_ERROR(GL_INVALID_VALUE);
87 }
88
89 // Checks that fog state can be set.
TEST_P(FogTest,Set)90 TEST_P(FogTest, Set)
91 {
92 GLfloat fogValue[4] = {};
93
94 glFogf(GL_FOG_MODE, GL_EXP2);
95 EXPECT_GL_NO_ERROR();
96
97 glGetFloatv(GL_FOG_MODE, fogValue);
98 EXPECT_GL_NO_ERROR();
99 EXPECT_GLENUM_EQ(GL_EXP2, fogValue[0]);
100
101 glFogf(GL_FOG_DENSITY, 2.0f);
102 EXPECT_GL_NO_ERROR();
103
104 glGetFloatv(GL_FOG_DENSITY, fogValue);
105 EXPECT_GL_NO_ERROR();
106 EXPECT_GLENUM_EQ(2.0f, fogValue[0]);
107
108 glFogf(GL_FOG_START, 2.0f);
109 EXPECT_GL_NO_ERROR();
110
111 glGetFloatv(GL_FOG_START, fogValue);
112 EXPECT_GL_NO_ERROR();
113 EXPECT_GLENUM_EQ(2.0f, fogValue[0]);
114
115 glFogf(GL_FOG_END, 2.0f);
116 EXPECT_GL_NO_ERROR();
117
118 glGetFloatv(GL_FOG_END, fogValue);
119 EXPECT_GL_NO_ERROR();
120 EXPECT_GLENUM_EQ(2.0f, fogValue[0]);
121
122 const GLColor32F testColor(0.1f, 0.2f, 0.3f, 0.4f);
123 glFogfv(GL_FOG_COLOR, &testColor.R);
124 EXPECT_GL_NO_ERROR();
125 glGetFloatv(GL_FOG_COLOR, fogValue);
126 EXPECT_GL_NO_ERROR();
127 EXPECT_EQ(0.1f, fogValue[0]);
128 EXPECT_EQ(0.2f, fogValue[1]);
129 EXPECT_EQ(0.3f, fogValue[2]);
130 EXPECT_EQ(0.4f, fogValue[3]);
131 }
132
133 class FogBlendTest : public ANGLETest<>
134 {
135 protected:
FogBlendTest()136 FogBlendTest()
137 {
138 setWindowWidth(512);
139 setWindowHeight(512);
140 setConfigRedBits(8);
141 setConfigGreenBits(8);
142 setConfigBlueBits(8);
143 setConfigAlphaBits(8);
144 setConfigDepthBits(24);
145 }
146 };
147
148 // Draws a circle with a shadow effect using fog and blending. As seen in Street Fighter IV.
TEST_P(FogBlendTest,ShadowEffect)149 TEST_P(FogBlendTest, ShadowEffect)
150 {
151 glEnableClientState(GL_VERTEX_ARRAY);
152 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
153
154 glEnable(GL_TEXTURE_2D);
155 glEnable(GL_BLEND);
156 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
157
158 int32_t w = getWindowWidth();
159 int32_t h = getWindowHeight();
160
161 int32_t radius = h / 4;
162
163 std::vector<GLColor> colors;
164 for (int32_t y = 0; y < h; y++)
165 {
166 for (int32_t x = 0; x < w; x++)
167 {
168 int32_t centerDistanceX = x - w / 2;
169 int32_t centerDistanceY = y - h / 2;
170
171 float centerDistance =
172 sqrt(centerDistanceX * centerDistanceX + centerDistanceY * centerDistanceY);
173
174 if (centerDistance > static_cast<float>(radius))
175 {
176 colors.push_back(GLColor::transparentBlack);
177 }
178 else
179 {
180 colors.push_back(GLColor::green);
181 }
182 }
183 }
184
185 GLTexture texture;
186 glBindTexture(GL_TEXTURE_2D, texture);
187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
191 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
192
193 glClearColor(GLColor::red.R, GLColor::red.G, GLColor::red.B, GLColor::red.A);
194 glClearDepthf(1);
195 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
196 glViewport(0, 0, w, h);
197 glMatrixMode(GL_PROJECTION);
198 glLoadIdentity();
199 glOrthof(0, w, h, 0, 0, 1);
200 glMatrixMode(GL_MODELVIEW);
201 glLoadIdentity();
202 glShadeModel(GL_FLAT);
203
204 // TODO(http://anglebug.com/42266063): This currently renders incorrectly on ANGLE
205 // Draw shadow effect
206 glEnable(GL_FOG);
207 const GLfloat fogColor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
208 glFogfv(GL_FOG_COLOR, fogColor);
209
210 glFogf(GL_FOG_MODE, GL_LINEAR);
211 glFogf(GL_FOG_START, -1);
212 glFogf(GL_FOG_END, -0.1);
213
214 GLfloat shadowOffset = 32.0f;
215 GLfloat wf = static_cast<GLfloat>(w);
216 GLfloat hf = static_cast<GLfloat>(h);
217
218 const GLfloat shadowPositions[8] = {shadowOffset, 0, shadowOffset, hf,
219 wf + shadowOffset, 0, wf + shadowOffset, hf};
220 glVertexPointer(2, GL_FLOAT, 0, shadowPositions);
221
222 const GLfloat texcoords[8] = {0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0};
223 glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
224
225 glColor4f(1, 1, 1, 0.6);
226
227 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
228
229 // Draws color circle
230 glDisable(GL_FOG);
231
232 const GLfloat positions[8] = {
233 0, 0, 0, hf, wf, 0, wf, hf,
234 };
235 glVertexPointer(2, GL_FLOAT, 0, positions);
236
237 glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
238
239 glColor4f(1, 1, 1, 1);
240
241 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
242
243 // The circle should be green
244 EXPECT_PIXEL_COLOR_NEAR(w / 2, h / 2, GLColor::green, 0);
245
246 // The background should be red
247 EXPECT_PIXEL_COLOR_NEAR(w / 8, h / 8, GLColor::red, 0);
248 EXPECT_PIXEL_COLOR_NEAR(w - w / 8, h / 8, GLColor::red, 0);
249 EXPECT_PIXEL_COLOR_NEAR(w / 8, h - h / 8, GLColor::red, 0);
250 EXPECT_PIXEL_COLOR_NEAR(w - w / 8, h - h / 8, GLColor::red, 0);
251
252 // The shadow should be darkened red
253 float shadowCenterX = w / 2 + radius + shadowOffset / 2.0f;
254 EXPECT_PIXEL_COLOR_NEAR(shadowCenterX, h / 2, GLColor(102u, 0, 0, 194u), 0);
255 }
256
257 ANGLE_INSTANTIATE_TEST_ES1(FogTest);
258 ANGLE_INSTANTIATE_TEST_ES1(FogBlendTest);
259