Serenity Operating System
1/*
2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
3 * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
4 * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 */
8
9#include <LibGL/GLContext.h>
10
11namespace GL {
12
13template<typename T>
14void GLContext::get_light_param(GLenum light, GLenum pname, T* params)
15{
16 auto const& light_state = m_light_states[light - GL_LIGHT0];
17 switch (pname) {
18 case GL_AMBIENT:
19 params[0] = light_state.ambient_intensity.x();
20 params[1] = light_state.ambient_intensity.y();
21 params[2] = light_state.ambient_intensity.z();
22 params[3] = light_state.ambient_intensity.w();
23 break;
24 case GL_DIFFUSE:
25 params[0] = light_state.diffuse_intensity.x();
26 params[1] = light_state.diffuse_intensity.y();
27 params[2] = light_state.diffuse_intensity.z();
28 params[3] = light_state.diffuse_intensity.w();
29 break;
30 case GL_SPECULAR:
31 params[0] = light_state.specular_intensity.x();
32 params[1] = light_state.specular_intensity.y();
33 params[2] = light_state.specular_intensity.z();
34 params[3] = light_state.specular_intensity.w();
35 break;
36 case GL_SPOT_DIRECTION:
37 params[0] = light_state.spotlight_direction.x();
38 params[1] = light_state.spotlight_direction.y();
39 params[2] = light_state.spotlight_direction.z();
40 break;
41 case GL_SPOT_EXPONENT:
42 *params = light_state.spotlight_exponent;
43 break;
44 case GL_SPOT_CUTOFF:
45 *params = light_state.spotlight_cutoff_angle;
46 break;
47 case GL_CONSTANT_ATTENUATION:
48 *params = light_state.constant_attenuation;
49 break;
50 case GL_LINEAR_ATTENUATION:
51 *params = light_state.linear_attenuation;
52 break;
53 case GL_QUADRATIC_ATTENUATION:
54 *params = light_state.quadratic_attenuation;
55 break;
56 }
57}
58
59template<typename T>
60void GLContext::get_material_param(Face face, GLenum pname, T* params)
61{
62 auto const& material = m_material_states[face];
63 switch (pname) {
64 case GL_AMBIENT:
65 params[0] = static_cast<T>(material.ambient.x());
66 params[1] = static_cast<T>(material.ambient.y());
67 params[2] = static_cast<T>(material.ambient.z());
68 params[3] = static_cast<T>(material.ambient.w());
69 break;
70 case GL_DIFFUSE:
71 params[0] = static_cast<T>(material.diffuse.x());
72 params[1] = static_cast<T>(material.diffuse.y());
73 params[2] = static_cast<T>(material.diffuse.z());
74 params[3] = static_cast<T>(material.diffuse.w());
75 break;
76 case GL_SPECULAR:
77 params[0] = static_cast<T>(material.specular.x());
78 params[1] = static_cast<T>(material.specular.y());
79 params[2] = static_cast<T>(material.specular.z());
80 params[3] = static_cast<T>(material.specular.w());
81 break;
82 case GL_EMISSION:
83 params[0] = static_cast<T>(material.emissive.x());
84 params[1] = static_cast<T>(material.emissive.y());
85 params[2] = static_cast<T>(material.emissive.z());
86 params[3] = static_cast<T>(material.emissive.w());
87 break;
88 case GL_SHININESS:
89 *params = material.shininess;
90 break;
91 }
92}
93
94void GLContext::gl_color_material(GLenum face, GLenum mode)
95{
96 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color_material, face, mode);
97 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
98
99 RETURN_WITH_ERROR_IF(face != GL_FRONT
100 && face != GL_BACK
101 && face != GL_FRONT_AND_BACK,
102 GL_INVALID_ENUM);
103 RETURN_WITH_ERROR_IF(mode != GL_EMISSION
104 && mode != GL_AMBIENT
105 && mode != GL_DIFFUSE
106 && mode != GL_SPECULAR
107 && mode != GL_AMBIENT_AND_DIFFUSE,
108 GL_INVALID_ENUM);
109
110 m_color_material_face = face;
111 m_color_material_mode = mode;
112
113 m_light_state_is_dirty = true;
114}
115
116void GLContext::gl_get_light(GLenum light, GLenum pname, void* params, GLenum type)
117{
118 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_get_light, light, pname, params, type);
119 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
120 RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light > GL_LIGHT0 + m_device_info.num_lights, GL_INVALID_ENUM);
121 RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_SPOT_DIRECTION || pname == GL_SPOT_EXPONENT || pname == GL_SPOT_CUTOFF || pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION), GL_INVALID_ENUM);
122
123 if (type == GL_FLOAT)
124 get_light_param<GLfloat>(light, pname, static_cast<GLfloat*>(params));
125 else if (type == GL_INT)
126 get_light_param<GLint>(light, pname, static_cast<GLint*>(params));
127 else
128 VERIFY_NOT_REACHED();
129}
130
131void GLContext::gl_get_material(GLenum face, GLenum pname, void* params, GLenum type)
132{
133 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_get_material, face, pname, params, type);
134 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
135 RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_EMISSION), GL_INVALID_ENUM);
136 RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK), GL_INVALID_ENUM);
137
138 Face material_face = Front;
139 switch (face) {
140 case GL_FRONT:
141 material_face = Front;
142 break;
143 case GL_BACK:
144 material_face = Back;
145 break;
146 }
147
148 if (type == GL_FLOAT)
149 get_material_param<GLfloat>(material_face, pname, static_cast<GLfloat*>(params));
150 else if (type == GL_INT)
151 get_material_param<GLint>(material_face, pname, static_cast<GLint*>(params));
152 else
153 VERIFY_NOT_REACHED();
154}
155
156void GLContext::gl_light_model(GLenum pname, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
157{
158 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_light_model, pname, x, y, z, w);
159
160 RETURN_WITH_ERROR_IF(pname != GL_LIGHT_MODEL_AMBIENT
161 && pname != GL_LIGHT_MODEL_COLOR_CONTROL
162 && pname != GL_LIGHT_MODEL_LOCAL_VIEWER
163 && pname != GL_LIGHT_MODEL_TWO_SIDE,
164 GL_INVALID_ENUM);
165
166 auto lighting_params = m_rasterizer->light_model();
167
168 switch (pname) {
169 case GL_LIGHT_MODEL_AMBIENT:
170 lighting_params.scene_ambient_color = { x, y, z, w };
171 break;
172 case GL_LIGHT_MODEL_COLOR_CONTROL: {
173 auto color_control = static_cast<GLenum>(x);
174 RETURN_WITH_ERROR_IF(color_control != GL_SINGLE_COLOR && color_control != GL_SEPARATE_SPECULAR_COLOR, GL_INVALID_ENUM);
175 lighting_params.color_control = (color_control == GL_SINGLE_COLOR) ? GPU::ColorControl::SingleColor : GPU::ColorControl::SeparateSpecularColor;
176 break;
177 }
178 case GL_LIGHT_MODEL_LOCAL_VIEWER:
179 // 0 means the viewer is at infinity
180 // 1 means they're in local (eye) space
181 lighting_params.viewer_at_infinity = (x == 0.f);
182 break;
183 case GL_LIGHT_MODEL_TWO_SIDE:
184 lighting_params.two_sided_lighting = (x != 0.f);
185 break;
186 default:
187 VERIFY_NOT_REACHED();
188 }
189
190 m_rasterizer->set_light_model_params(lighting_params);
191}
192
193void GLContext::gl_light_modelv(GLenum pname, void const* params, GLenum type)
194{
195 VERIFY(type == GL_FLOAT || type == GL_INT);
196
197 auto parameters_to_vector = [&]<typename T>(T const* params) -> FloatVector4 {
198 return (pname == GL_LIGHT_MODEL_AMBIENT)
199 ? Vector4<T> { params[0], params[1], params[2], params[3] }.template to_type<float>()
200 : Vector4<T> { params[0], 0, 0, 0 }.template to_type<float>();
201 };
202
203 auto light_model_parameters = (type == GL_FLOAT)
204 ? parameters_to_vector(reinterpret_cast<GLfloat const*>(params))
205 : parameters_to_vector(reinterpret_cast<GLint const*>(params));
206
207 // Normalize integers to -1..1
208 if (pname == GL_LIGHT_MODEL_AMBIENT && type == GL_INT)
209 light_model_parameters = (light_model_parameters + 2147483648.f) / 2147483647.5f - 1.f;
210
211 gl_light_model(pname, light_model_parameters[0], light_model_parameters[1], light_model_parameters[2], light_model_parameters[3]);
212}
213
214void GLContext::gl_lightf(GLenum light, GLenum pname, GLfloat param)
215{
216 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_lightf, light, pname, param);
217
218 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
219 RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light >= (GL_LIGHT0 + m_device_info.num_lights), GL_INVALID_ENUM);
220 RETURN_WITH_ERROR_IF(!(pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION || pname != GL_SPOT_EXPONENT || pname != GL_SPOT_CUTOFF), GL_INVALID_ENUM);
221 RETURN_WITH_ERROR_IF(param < 0.f, GL_INVALID_VALUE);
222
223 auto& light_state = m_light_states.at(light - GL_LIGHT0);
224
225 switch (pname) {
226 case GL_CONSTANT_ATTENUATION:
227 light_state.constant_attenuation = param;
228 break;
229 case GL_LINEAR_ATTENUATION:
230 light_state.linear_attenuation = param;
231 break;
232 case GL_QUADRATIC_ATTENUATION:
233 light_state.quadratic_attenuation = param;
234 break;
235 case GL_SPOT_EXPONENT:
236 RETURN_WITH_ERROR_IF(param > 128.f, GL_INVALID_VALUE);
237 light_state.spotlight_exponent = param;
238 break;
239 case GL_SPOT_CUTOFF:
240 RETURN_WITH_ERROR_IF(param > 90.f && param != 180.f, GL_INVALID_VALUE);
241 light_state.spotlight_cutoff_angle = param;
242 break;
243 default:
244 VERIFY_NOT_REACHED();
245 }
246
247 m_light_state_is_dirty = true;
248}
249
250void GLContext::gl_lightfv(GLenum light, GLenum pname, GLfloat const* params)
251{
252 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_lightfv, light, pname, params);
253 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
254 RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light >= (GL_LIGHT0 + m_device_info.num_lights), GL_INVALID_ENUM);
255 RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_POSITION || pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION || pname == GL_SPOT_CUTOFF || pname == GL_SPOT_EXPONENT || pname == GL_SPOT_DIRECTION), GL_INVALID_ENUM);
256
257 auto& light_state = m_light_states.at(light - GL_LIGHT0);
258
259 switch (pname) {
260 case GL_AMBIENT:
261 light_state.ambient_intensity = { params[0], params[1], params[2], params[3] };
262 break;
263 case GL_DIFFUSE:
264 light_state.diffuse_intensity = { params[0], params[1], params[2], params[3] };
265 break;
266 case GL_SPECULAR:
267 light_state.specular_intensity = { params[0], params[1], params[2], params[3] };
268 break;
269 case GL_POSITION:
270 light_state.position = { params[0], params[1], params[2], params[3] };
271 light_state.position = model_view_matrix() * light_state.position;
272 break;
273 case GL_CONSTANT_ATTENUATION:
274 RETURN_WITH_ERROR_IF(params[0] < 0.f, GL_INVALID_VALUE);
275 light_state.constant_attenuation = params[0];
276 break;
277 case GL_LINEAR_ATTENUATION:
278 RETURN_WITH_ERROR_IF(params[0] < 0.f, GL_INVALID_VALUE);
279 light_state.linear_attenuation = params[0];
280 break;
281 case GL_QUADRATIC_ATTENUATION:
282 RETURN_WITH_ERROR_IF(params[0] < 0.f, GL_INVALID_VALUE);
283 light_state.quadratic_attenuation = params[0];
284 break;
285 case GL_SPOT_EXPONENT: {
286 auto exponent = params[0];
287 RETURN_WITH_ERROR_IF(exponent < 0.f || exponent > 128.f, GL_INVALID_VALUE);
288 light_state.spotlight_exponent = exponent;
289 break;
290 }
291 case GL_SPOT_CUTOFF: {
292 auto cutoff = params[0];
293 RETURN_WITH_ERROR_IF((cutoff < 0.f || cutoff > 90.f) && cutoff != 180.f, GL_INVALID_VALUE);
294 light_state.spotlight_cutoff_angle = cutoff;
295 break;
296 }
297 case GL_SPOT_DIRECTION: {
298 FloatVector4 direction_vector = { params[0], params[1], params[2], 0.f };
299 direction_vector = model_view_matrix() * direction_vector;
300 light_state.spotlight_direction = direction_vector.xyz();
301 break;
302 }
303 default:
304 VERIFY_NOT_REACHED();
305 }
306
307 m_light_state_is_dirty = true;
308}
309
310void GLContext::gl_lightiv(GLenum light, GLenum pname, GLint const* params)
311{
312 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_lightiv, light, pname, params);
313 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
314 RETURN_WITH_ERROR_IF(light < GL_LIGHT0 || light >= (GL_LIGHT0 + m_device_info.num_lights), GL_INVALID_ENUM);
315 RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_POSITION || pname == GL_CONSTANT_ATTENUATION || pname == GL_LINEAR_ATTENUATION || pname == GL_QUADRATIC_ATTENUATION || pname == GL_SPOT_CUTOFF || pname == GL_SPOT_EXPONENT || pname == GL_SPOT_DIRECTION), GL_INVALID_ENUM);
316
317 auto& light_state = m_light_states[light - GL_LIGHT0];
318
319 auto const to_float_vector = [](GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
320 return FloatVector4(x, y, z, w);
321 };
322
323 switch (pname) {
324 case GL_AMBIENT:
325 light_state.ambient_intensity = to_float_vector(params[0], params[1], params[2], params[3]);
326 break;
327 case GL_DIFFUSE:
328 light_state.diffuse_intensity = to_float_vector(params[0], params[1], params[2], params[3]);
329 break;
330 case GL_SPECULAR:
331 light_state.specular_intensity = to_float_vector(params[0], params[1], params[2], params[3]);
332 break;
333 case GL_POSITION:
334 light_state.position = to_float_vector(params[0], params[1], params[2], params[3]);
335 light_state.position = model_view_matrix() * light_state.position;
336 break;
337 case GL_CONSTANT_ATTENUATION:
338 RETURN_WITH_ERROR_IF(params[0] < 0, GL_INVALID_VALUE);
339 light_state.constant_attenuation = static_cast<float>(params[0]);
340 break;
341 case GL_LINEAR_ATTENUATION:
342 RETURN_WITH_ERROR_IF(params[0] < 0, GL_INVALID_VALUE);
343 light_state.linear_attenuation = static_cast<float>(params[0]);
344 break;
345 case GL_QUADRATIC_ATTENUATION:
346 RETURN_WITH_ERROR_IF(params[0] < 0, GL_INVALID_VALUE);
347 light_state.quadratic_attenuation = static_cast<float>(params[0]);
348 break;
349 case GL_SPOT_EXPONENT: {
350 auto exponent = static_cast<float>(params[0]);
351 RETURN_WITH_ERROR_IF(exponent < 0.f || exponent > 128.f, GL_INVALID_VALUE);
352 light_state.spotlight_exponent = exponent;
353 break;
354 }
355 case GL_SPOT_CUTOFF: {
356 auto cutoff = static_cast<float>(params[0]);
357 RETURN_WITH_ERROR_IF((cutoff < 0.f || cutoff > 90.f) && cutoff != 180.f, GL_INVALID_VALUE);
358 light_state.spotlight_cutoff_angle = cutoff;
359 break;
360 }
361 case GL_SPOT_DIRECTION: {
362 auto direction_vector = to_float_vector(params[0], params[1], params[2], 0.0f);
363 direction_vector = model_view_matrix() * direction_vector;
364 light_state.spotlight_direction = direction_vector.xyz();
365 break;
366 }
367 default:
368 VERIFY_NOT_REACHED();
369 }
370
371 m_light_state_is_dirty = true;
372}
373
374void GLContext::gl_materialf(GLenum face, GLenum pname, GLfloat param)
375{
376 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_materialf, face, pname, param);
377 RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM);
378 RETURN_WITH_ERROR_IF(pname != GL_SHININESS, GL_INVALID_ENUM);
379 RETURN_WITH_ERROR_IF(param > 128.0f, GL_INVALID_VALUE);
380
381 switch (face) {
382 case GL_FRONT:
383 m_material_states[Face::Front].shininess = param;
384 break;
385 case GL_BACK:
386 m_material_states[Face::Back].shininess = param;
387 break;
388 case GL_FRONT_AND_BACK:
389 m_material_states[Face::Front].shininess = param;
390 m_material_states[Face::Back].shininess = param;
391 break;
392 default:
393 VERIFY_NOT_REACHED();
394 }
395
396 m_light_state_is_dirty = true;
397}
398
399void GLContext::gl_materialfv(GLenum face, GLenum pname, GLfloat const* params)
400{
401 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_materialfv, face, pname, params);
402 RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM);
403 RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_EMISSION || pname == GL_SHININESS || pname == GL_AMBIENT_AND_DIFFUSE), GL_INVALID_ENUM);
404 RETURN_WITH_ERROR_IF((pname == GL_SHININESS && *params > 128.0f), GL_INVALID_VALUE);
405
406 auto update_material = [](GPU::Material& material, GLenum pname, GLfloat const* params) {
407 switch (pname) {
408 case GL_AMBIENT:
409 material.ambient = { params[0], params[1], params[2], params[3] };
410 break;
411 case GL_DIFFUSE:
412 material.diffuse = { params[0], params[1], params[2], params[3] };
413 break;
414 case GL_SPECULAR:
415 material.specular = { params[0], params[1], params[2], params[3] };
416 break;
417 case GL_EMISSION:
418 material.emissive = { params[0], params[1], params[2], params[3] };
419 break;
420 case GL_SHININESS:
421 material.shininess = params[0];
422 break;
423 case GL_AMBIENT_AND_DIFFUSE:
424 material.ambient = { params[0], params[1], params[2], params[3] };
425 material.diffuse = { params[0], params[1], params[2], params[3] };
426 break;
427 }
428 };
429
430 switch (face) {
431 case GL_FRONT:
432 update_material(m_material_states[Face::Front], pname, params);
433 break;
434 case GL_BACK:
435 update_material(m_material_states[Face::Back], pname, params);
436 break;
437 case GL_FRONT_AND_BACK:
438 update_material(m_material_states[Face::Front], pname, params);
439 update_material(m_material_states[Face::Back], pname, params);
440 break;
441 }
442
443 m_light_state_is_dirty = true;
444}
445
446void GLContext::gl_materialiv(GLenum face, GLenum pname, GLint const* params)
447{
448 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_materialiv, face, pname, params);
449 RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM);
450 RETURN_WITH_ERROR_IF(!(pname == GL_AMBIENT || pname == GL_DIFFUSE || pname == GL_SPECULAR || pname == GL_EMISSION || pname == GL_SHININESS || pname == GL_AMBIENT_AND_DIFFUSE), GL_INVALID_ENUM);
451 RETURN_WITH_ERROR_IF((pname == GL_SHININESS && *params > 128), GL_INVALID_VALUE);
452
453 auto update_material = [](GPU::Material& material, GLenum pname, GLint const* params) {
454 switch (pname) {
455 case GL_AMBIENT:
456 material.ambient = { static_cast<float>(params[0]), static_cast<float>(params[1]), static_cast<float>(params[2]), static_cast<float>(params[3]) };
457 break;
458 case GL_DIFFUSE:
459 material.diffuse = { static_cast<float>(params[0]), static_cast<float>(params[1]), static_cast<float>(params[2]), static_cast<float>(params[3]) };
460 break;
461 case GL_SPECULAR:
462 material.specular = { static_cast<float>(params[0]), static_cast<float>(params[1]), static_cast<float>(params[2]), static_cast<float>(params[3]) };
463 break;
464 case GL_EMISSION:
465 material.emissive = { static_cast<float>(params[0]), static_cast<float>(params[1]), static_cast<float>(params[2]), static_cast<float>(params[3]) };
466 break;
467 case GL_SHININESS:
468 material.shininess = static_cast<float>(params[0]);
469 break;
470 case GL_AMBIENT_AND_DIFFUSE:
471 material.ambient = { static_cast<float>(params[0]), static_cast<float>(params[1]), static_cast<float>(params[2]), static_cast<float>(params[3]) };
472 material.diffuse = { static_cast<float>(params[0]), static_cast<float>(params[1]), static_cast<float>(params[2]), static_cast<float>(params[3]) };
473 break;
474 }
475 };
476
477 switch (face) {
478 case GL_FRONT:
479 update_material(m_material_states[Face::Front], pname, params);
480 break;
481 case GL_BACK:
482 update_material(m_material_states[Face::Back], pname, params);
483 break;
484 case GL_FRONT_AND_BACK:
485 update_material(m_material_states[Face::Front], pname, params);
486 update_material(m_material_states[Face::Back], pname, params);
487 break;
488 }
489
490 m_light_state_is_dirty = true;
491}
492
493void GLContext::gl_shade_model(GLenum mode)
494{
495 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_shade_model, mode);
496
497 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
498 RETURN_WITH_ERROR_IF(mode != GL_FLAT && mode != GL_SMOOTH, GL_INVALID_ENUM);
499
500 auto options = m_rasterizer->options();
501 options.shade_smooth = (mode == GL_SMOOTH);
502 m_rasterizer->set_options(options);
503}
504
505void GLContext::sync_light_state()
506{
507 if (!m_light_state_is_dirty)
508 return;
509
510 m_light_state_is_dirty = false;
511
512 auto options = m_rasterizer->options();
513 options.color_material_enabled = m_color_material_enabled;
514 switch (m_color_material_face) {
515 case GL_BACK:
516 options.color_material_face = GPU::ColorMaterialFace::Back;
517 break;
518 case GL_FRONT:
519 options.color_material_face = GPU::ColorMaterialFace::Front;
520 break;
521 case GL_FRONT_AND_BACK:
522 options.color_material_face = GPU::ColorMaterialFace::FrontAndBack;
523 break;
524 default:
525 VERIFY_NOT_REACHED();
526 }
527 switch (m_color_material_mode) {
528 case GL_AMBIENT:
529 options.color_material_mode = GPU::ColorMaterialMode::Ambient;
530 break;
531 case GL_AMBIENT_AND_DIFFUSE:
532 options.color_material_mode = GPU::ColorMaterialMode::AmbientAndDiffuse;
533 break;
534 case GL_DIFFUSE:
535 options.color_material_mode = GPU::ColorMaterialMode::Diffuse;
536 break;
537 case GL_EMISSION:
538 options.color_material_mode = GPU::ColorMaterialMode::Emissive;
539 break;
540 case GL_SPECULAR:
541 options.color_material_mode = GPU::ColorMaterialMode::Specular;
542 break;
543 default:
544 VERIFY_NOT_REACHED();
545 }
546 m_rasterizer->set_options(options);
547
548 for (auto light_id = 0u; light_id < m_device_info.num_lights; light_id++) {
549 auto const& current_light_state = m_light_states.at(light_id);
550 m_rasterizer->set_light_state(light_id, current_light_state);
551 }
552
553 m_rasterizer->set_material_state(GPU::Face::Front, m_material_states[Face::Front]);
554 m_rasterizer->set_material_state(GPU::Face::Back, m_material_states[Face::Back]);
555}
556
557}