ContextParameter.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. #include <AK/Debug.h>
  9. #include <LibGL/GLContext.h>
  10. namespace GL {
  11. Optional<ContextParameter> GLContext::get_context_parameter(GLenum name)
  12. {
  13. switch (name) {
  14. case GL_ALPHA_BITS:
  15. return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
  16. case GL_ALPHA_TEST:
  17. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_alpha_test_enabled } };
  18. case GL_BLEND:
  19. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_blend_enabled } };
  20. case GL_BLEND_DST_ALPHA:
  21. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_blend_destination_factor) } };
  22. case GL_BLEND_SRC_ALPHA:
  23. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_blend_source_factor) } };
  24. case GL_BLUE_BITS:
  25. return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
  26. case GL_COLOR_MATERIAL:
  27. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_color_material_enabled } };
  28. case GL_COLOR_MATERIAL_FACE:
  29. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_color_material_face) } };
  30. case GL_COLOR_MATERIAL_MODE:
  31. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_color_material_mode) } };
  32. case GL_CULL_FACE:
  33. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_cull_faces } };
  34. case GL_DEPTH_BITS:
  35. return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
  36. case GL_DEPTH_TEST:
  37. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_depth_test_enabled } };
  38. case GL_DITHER:
  39. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_dither_enabled } };
  40. case GL_DOUBLEBUFFER:
  41. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = true } };
  42. case GL_FOG: {
  43. auto fog_enabled = m_rasterizer->options().fog_enabled;
  44. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = fog_enabled } };
  45. }
  46. case GL_GREEN_BITS:
  47. return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
  48. case GL_LIGHTING:
  49. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_lighting_enabled } };
  50. case GL_LINE_SMOOTH:
  51. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_line_smooth } };
  52. case GL_MAX_CLIP_PLANES:
  53. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.max_clip_planes) } };
  54. case GL_MAX_LIGHTS:
  55. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.num_lights) } };
  56. case GL_MAX_MODELVIEW_STACK_DEPTH:
  57. return ContextParameter { .type = GL_INT, .value = { .integer_value = MODELVIEW_MATRIX_STACK_LIMIT } };
  58. case GL_MAX_PROJECTION_STACK_DEPTH:
  59. return ContextParameter { .type = GL_INT, .value = { .integer_value = PROJECTION_MATRIX_STACK_LIMIT } };
  60. case GL_MAX_TEXTURE_SIZE:
  61. return ContextParameter { .type = GL_INT, .value = { .integer_value = 4096 } };
  62. case GL_MAX_TEXTURE_STACK_DEPTH:
  63. return ContextParameter { .type = GL_INT, .value = { .integer_value = TEXTURE_MATRIX_STACK_LIMIT } };
  64. case GL_MAX_TEXTURE_UNITS:
  65. return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_texture_units.size()) } };
  66. case GL_NORMALIZE:
  67. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_normalize } };
  68. case GL_PACK_ALIGNMENT:
  69. return ContextParameter { .type = GL_INT, .value = { .integer_value = m_pack_alignment } };
  70. case GL_PACK_IMAGE_HEIGHT:
  71. return ContextParameter { .type = GL_BOOL, .value = { .integer_value = 0 } };
  72. case GL_PACK_LSB_FIRST:
  73. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = false } };
  74. case GL_PACK_ROW_LENGTH:
  75. return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } };
  76. case GL_PACK_SKIP_PIXELS:
  77. return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } };
  78. case GL_PACK_SKIP_ROWS:
  79. return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } };
  80. case GL_PACK_SWAP_BYTES:
  81. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = false } };
  82. case GL_POINT_SMOOTH:
  83. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_point_smooth } };
  84. case GL_POINT_SIZE:
  85. return ContextParameter { .type = GL_DOUBLE, .value = { .double_value = static_cast<GLdouble>(m_point_size) } };
  86. case GL_POLYGON_OFFSET_FILL:
  87. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_depth_offset_enabled } };
  88. case GL_RED_BITS:
  89. return ContextParameter { .type = GL_INT, .value = { .integer_value = sizeof(float) * 8 } };
  90. case GL_SCISSOR_BOX: {
  91. auto scissor_box = m_rasterizer->options().scissor_box;
  92. return ContextParameter {
  93. .type = GL_INT,
  94. .count = 4,
  95. .value = {
  96. .integer_list = {
  97. scissor_box.x(),
  98. scissor_box.y(),
  99. scissor_box.width(),
  100. scissor_box.height(),
  101. } }
  102. };
  103. }
  104. case GL_SCISSOR_TEST: {
  105. auto scissor_enabled = m_rasterizer->options().scissor_enabled;
  106. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = scissor_enabled } };
  107. }
  108. case GL_STENCIL_BITS:
  109. return ContextParameter { .type = GL_INT, .value = { .integer_value = m_device_info.stencil_bits } };
  110. case GL_STENCIL_CLEAR_VALUE:
  111. return ContextParameter { .type = GL_INT, .value = { .integer_value = m_clear_stencil } };
  112. case GL_STENCIL_TEST:
  113. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_stencil_test_enabled } };
  114. case GL_TEXTURE_1D:
  115. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_1d_enabled() } };
  116. case GL_TEXTURE_2D:
  117. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_2d_enabled() } };
  118. case GL_TEXTURE_3D:
  119. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_3d_enabled() } };
  120. case GL_TEXTURE_CUBE_MAP:
  121. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = m_active_texture_unit->texture_cube_map_enabled() } };
  122. case GL_TEXTURE_GEN_Q:
  123. case GL_TEXTURE_GEN_R:
  124. case GL_TEXTURE_GEN_S:
  125. case GL_TEXTURE_GEN_T: {
  126. auto generation_enabled = texture_coordinate_generation(m_active_texture_unit_index, name).enabled;
  127. return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = generation_enabled } };
  128. }
  129. case GL_UNPACK_ALIGNMENT:
  130. return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpack_alignment } };
  131. case GL_UNPACK_IMAGE_HEIGHT:
  132. return ContextParameter { .type = GL_BOOL, .value = { .integer_value = 0 } };
  133. case GL_UNPACK_LSB_FIRST:
  134. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = false } };
  135. case GL_UNPACK_ROW_LENGTH:
  136. return ContextParameter { .type = GL_INT, .value = { .integer_value = m_unpack_row_length } };
  137. case GL_UNPACK_SKIP_PIXELS:
  138. return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } };
  139. case GL_UNPACK_SKIP_ROWS:
  140. return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } };
  141. case GL_UNPACK_SWAP_BYTES:
  142. return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = false } };
  143. case GL_VIEWPORT:
  144. return ContextParameter {
  145. .type = GL_INT,
  146. .count = 4,
  147. .value = {
  148. .integer_list = {
  149. m_viewport.x(),
  150. m_viewport.y(),
  151. m_viewport.width(),
  152. m_viewport.height(),
  153. } }
  154. };
  155. default:
  156. dbgln_if(GL_DEBUG, "get_context_parameter({:#x}): unknown context parameter", name);
  157. return {};
  158. }
  159. }
  160. void GLContext::gl_disable(GLenum capability)
  161. {
  162. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_disable, capability);
  163. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  164. auto rasterizer_options = m_rasterizer->options();
  165. bool update_rasterizer_options = false;
  166. switch (capability) {
  167. case GL_CLIP_PLANE0:
  168. case GL_CLIP_PLANE1:
  169. case GL_CLIP_PLANE2:
  170. case GL_CLIP_PLANE3:
  171. case GL_CLIP_PLANE4:
  172. case GL_CLIP_PLANE5: {
  173. auto plane_idx = static_cast<size_t>(capability) - GL_CLIP_PLANE0;
  174. m_clip_plane_attributes.enabled &= ~(1 << plane_idx);
  175. m_clip_planes_dirty = true;
  176. break;
  177. }
  178. case GL_COLOR_MATERIAL:
  179. m_color_material_enabled = false;
  180. break;
  181. case GL_CULL_FACE:
  182. m_cull_faces = false;
  183. rasterizer_options.enable_culling = false;
  184. update_rasterizer_options = true;
  185. break;
  186. case GL_DEPTH_TEST:
  187. m_depth_test_enabled = false;
  188. rasterizer_options.enable_depth_test = false;
  189. update_rasterizer_options = true;
  190. break;
  191. case GL_BLEND:
  192. m_blend_enabled = false;
  193. rasterizer_options.enable_blending = false;
  194. update_rasterizer_options = true;
  195. break;
  196. case GL_ALPHA_TEST:
  197. m_alpha_test_enabled = false;
  198. rasterizer_options.enable_alpha_test = false;
  199. update_rasterizer_options = true;
  200. break;
  201. case GL_DITHER:
  202. m_dither_enabled = false;
  203. break;
  204. case GL_FOG:
  205. rasterizer_options.fog_enabled = false;
  206. update_rasterizer_options = true;
  207. break;
  208. case GL_LIGHTING:
  209. m_lighting_enabled = false;
  210. rasterizer_options.lighting_enabled = false;
  211. update_rasterizer_options = true;
  212. break;
  213. case GL_LIGHT0:
  214. case GL_LIGHT1:
  215. case GL_LIGHT2:
  216. case GL_LIGHT3:
  217. case GL_LIGHT4:
  218. case GL_LIGHT5:
  219. case GL_LIGHT6:
  220. case GL_LIGHT7:
  221. m_light_states.at(capability - GL_LIGHT0).is_enabled = false;
  222. m_light_state_is_dirty = true;
  223. break;
  224. case GL_LINE_SMOOTH:
  225. m_line_smooth = false;
  226. rasterizer_options.line_smooth = false;
  227. update_rasterizer_options = true;
  228. break;
  229. case GL_NORMALIZE:
  230. m_normalize = false;
  231. rasterizer_options.normalization_enabled = false;
  232. update_rasterizer_options = true;
  233. break;
  234. case GL_POINT_SMOOTH:
  235. m_point_smooth = false;
  236. rasterizer_options.point_smooth = false;
  237. update_rasterizer_options = true;
  238. break;
  239. case GL_POLYGON_OFFSET_FILL:
  240. m_depth_offset_enabled = false;
  241. rasterizer_options.depth_offset_enabled = false;
  242. update_rasterizer_options = true;
  243. break;
  244. case GL_SCISSOR_TEST:
  245. rasterizer_options.scissor_enabled = false;
  246. update_rasterizer_options = true;
  247. break;
  248. case GL_STENCIL_TEST:
  249. m_stencil_test_enabled = false;
  250. rasterizer_options.enable_stencil_test = false;
  251. update_rasterizer_options = true;
  252. break;
  253. case GL_TEXTURE_1D:
  254. m_active_texture_unit->set_texture_1d_enabled(false);
  255. m_sampler_config_is_dirty = true;
  256. break;
  257. case GL_TEXTURE_2D:
  258. m_active_texture_unit->set_texture_2d_enabled(false);
  259. m_sampler_config_is_dirty = true;
  260. break;
  261. case GL_TEXTURE_3D:
  262. m_active_texture_unit->set_texture_3d_enabled(false);
  263. m_sampler_config_is_dirty = true;
  264. break;
  265. case GL_TEXTURE_CUBE_MAP:
  266. m_active_texture_unit->set_texture_cube_map_enabled(false);
  267. m_sampler_config_is_dirty = true;
  268. break;
  269. case GL_TEXTURE_GEN_Q:
  270. case GL_TEXTURE_GEN_R:
  271. case GL_TEXTURE_GEN_S:
  272. case GL_TEXTURE_GEN_T:
  273. texture_coordinate_generation(m_active_texture_unit_index, capability).enabled = false;
  274. m_texcoord_generation_dirty = true;
  275. break;
  276. default:
  277. dbgln_if(GL_DEBUG, "gl_disable({:#x}): unknown parameter", capability);
  278. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  279. }
  280. if (update_rasterizer_options)
  281. m_rasterizer->set_options(rasterizer_options);
  282. }
  283. void GLContext::gl_disable_client_state(GLenum cap)
  284. {
  285. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  286. switch (cap) {
  287. case GL_COLOR_ARRAY:
  288. m_client_side_color_array_enabled = false;
  289. break;
  290. case GL_NORMAL_ARRAY:
  291. m_client_side_normal_array_enabled = false;
  292. break;
  293. case GL_TEXTURE_COORD_ARRAY:
  294. m_client_side_texture_coord_array_enabled[m_client_active_texture] = false;
  295. break;
  296. case GL_VERTEX_ARRAY:
  297. m_client_side_vertex_array_enabled = false;
  298. break;
  299. default:
  300. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  301. }
  302. }
  303. void GLContext::gl_enable(GLenum capability)
  304. {
  305. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_enable, capability);
  306. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  307. auto rasterizer_options = m_rasterizer->options();
  308. bool update_rasterizer_options = false;
  309. switch (capability) {
  310. case GL_CLIP_PLANE0:
  311. case GL_CLIP_PLANE1:
  312. case GL_CLIP_PLANE2:
  313. case GL_CLIP_PLANE3:
  314. case GL_CLIP_PLANE4:
  315. case GL_CLIP_PLANE5: {
  316. auto plane_idx = static_cast<size_t>(capability) - GL_CLIP_PLANE0;
  317. m_clip_plane_attributes.enabled |= (1 << plane_idx);
  318. m_clip_planes_dirty = true;
  319. break;
  320. }
  321. case GL_COLOR_MATERIAL:
  322. m_color_material_enabled = true;
  323. break;
  324. case GL_CULL_FACE:
  325. m_cull_faces = true;
  326. rasterizer_options.enable_culling = true;
  327. update_rasterizer_options = true;
  328. break;
  329. case GL_DEPTH_TEST:
  330. m_depth_test_enabled = true;
  331. rasterizer_options.enable_depth_test = true;
  332. update_rasterizer_options = true;
  333. break;
  334. case GL_BLEND:
  335. m_blend_enabled = true;
  336. rasterizer_options.enable_blending = true;
  337. update_rasterizer_options = true;
  338. break;
  339. case GL_ALPHA_TEST:
  340. m_alpha_test_enabled = true;
  341. rasterizer_options.enable_alpha_test = true;
  342. update_rasterizer_options = true;
  343. break;
  344. case GL_DITHER:
  345. m_dither_enabled = true;
  346. break;
  347. case GL_FOG:
  348. rasterizer_options.fog_enabled = true;
  349. update_rasterizer_options = true;
  350. break;
  351. case GL_LIGHTING:
  352. m_lighting_enabled = true;
  353. rasterizer_options.lighting_enabled = true;
  354. update_rasterizer_options = true;
  355. break;
  356. case GL_LIGHT0:
  357. case GL_LIGHT1:
  358. case GL_LIGHT2:
  359. case GL_LIGHT3:
  360. case GL_LIGHT4:
  361. case GL_LIGHT5:
  362. case GL_LIGHT6:
  363. case GL_LIGHT7:
  364. m_light_states.at(capability - GL_LIGHT0).is_enabled = true;
  365. m_light_state_is_dirty = true;
  366. break;
  367. case GL_LINE_SMOOTH:
  368. m_line_smooth = true;
  369. rasterizer_options.line_smooth = true;
  370. update_rasterizer_options = true;
  371. break;
  372. case GL_NORMALIZE:
  373. m_normalize = true;
  374. rasterizer_options.normalization_enabled = true;
  375. update_rasterizer_options = true;
  376. break;
  377. case GL_POINT_SMOOTH:
  378. m_point_smooth = true;
  379. rasterizer_options.point_smooth = true;
  380. update_rasterizer_options = true;
  381. break;
  382. case GL_POLYGON_OFFSET_FILL:
  383. m_depth_offset_enabled = true;
  384. rasterizer_options.depth_offset_enabled = true;
  385. update_rasterizer_options = true;
  386. break;
  387. case GL_SCISSOR_TEST:
  388. rasterizer_options.scissor_enabled = true;
  389. update_rasterizer_options = true;
  390. break;
  391. case GL_STENCIL_TEST:
  392. m_stencil_test_enabled = true;
  393. rasterizer_options.enable_stencil_test = true;
  394. update_rasterizer_options = true;
  395. break;
  396. case GL_TEXTURE_1D:
  397. m_active_texture_unit->set_texture_1d_enabled(true);
  398. m_sampler_config_is_dirty = true;
  399. break;
  400. case GL_TEXTURE_2D:
  401. m_active_texture_unit->set_texture_2d_enabled(true);
  402. m_sampler_config_is_dirty = true;
  403. break;
  404. case GL_TEXTURE_3D:
  405. m_active_texture_unit->set_texture_3d_enabled(true);
  406. m_sampler_config_is_dirty = true;
  407. break;
  408. case GL_TEXTURE_CUBE_MAP:
  409. m_active_texture_unit->set_texture_cube_map_enabled(true);
  410. m_sampler_config_is_dirty = true;
  411. break;
  412. case GL_TEXTURE_GEN_Q:
  413. case GL_TEXTURE_GEN_R:
  414. case GL_TEXTURE_GEN_S:
  415. case GL_TEXTURE_GEN_T:
  416. texture_coordinate_generation(m_active_texture_unit_index, capability).enabled = true;
  417. m_texcoord_generation_dirty = true;
  418. break;
  419. default:
  420. dbgln_if(GL_DEBUG, "gl_enable({:#x}): unknown parameter", capability);
  421. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  422. }
  423. if (update_rasterizer_options)
  424. m_rasterizer->set_options(rasterizer_options);
  425. }
  426. void GLContext::gl_enable_client_state(GLenum cap)
  427. {
  428. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  429. switch (cap) {
  430. case GL_COLOR_ARRAY:
  431. m_client_side_color_array_enabled = true;
  432. break;
  433. case GL_NORMAL_ARRAY:
  434. m_client_side_normal_array_enabled = true;
  435. break;
  436. case GL_TEXTURE_COORD_ARRAY:
  437. m_client_side_texture_coord_array_enabled[m_client_active_texture] = true;
  438. break;
  439. case GL_VERTEX_ARRAY:
  440. m_client_side_vertex_array_enabled = true;
  441. break;
  442. default:
  443. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  444. }
  445. }
  446. void GLContext::gl_get_booleanv(GLenum pname, GLboolean* data)
  447. {
  448. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  449. auto optional_parameter = get_context_parameter(pname);
  450. RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
  451. auto parameter = optional_parameter.release_value();
  452. switch (parameter.type) {
  453. case GL_BOOL:
  454. *data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
  455. break;
  456. case GL_DOUBLE:
  457. *data = (parameter.value.double_value == 0.0) ? GL_FALSE : GL_TRUE;
  458. break;
  459. case GL_INT:
  460. *data = (parameter.value.integer_value == 0) ? GL_FALSE : GL_TRUE;
  461. break;
  462. default:
  463. VERIFY_NOT_REACHED();
  464. }
  465. }
  466. void GLContext::gl_get_doublev(GLenum pname, GLdouble* params)
  467. {
  468. get_floating_point(pname, params);
  469. }
  470. template<typename T>
  471. void GLContext::get_floating_point(GLenum pname, T* params)
  472. {
  473. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  474. // Handle matrix retrieval first
  475. auto flatten_and_assign_matrix = [&params](FloatMatrix4x4 const& matrix) {
  476. auto elements = matrix.elements();
  477. for (size_t i = 0; i < 4; ++i) {
  478. for (size_t j = 0; j < 4; ++j) {
  479. // Return transposed matrix since OpenGL defines them as column-major
  480. params[i * 4 + j] = static_cast<T>(elements[j][i]);
  481. }
  482. }
  483. };
  484. switch (pname) {
  485. case GL_MODELVIEW_MATRIX:
  486. flatten_and_assign_matrix(m_model_view_matrix);
  487. return;
  488. case GL_PROJECTION_MATRIX:
  489. flatten_and_assign_matrix(m_projection_matrix);
  490. return;
  491. }
  492. // Regular parameters
  493. auto optional_parameter = get_context_parameter(pname);
  494. RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
  495. auto parameter = optional_parameter.release_value();
  496. switch (parameter.type) {
  497. case GL_BOOL:
  498. *params = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
  499. break;
  500. case GL_DOUBLE:
  501. for (size_t i = 0; i < parameter.count; ++i)
  502. params[i] = parameter.value.double_list[i];
  503. break;
  504. case GL_INT:
  505. for (size_t i = 0; i < parameter.count; ++i)
  506. params[i] = parameter.value.integer_list[i];
  507. break;
  508. default:
  509. VERIFY_NOT_REACHED();
  510. }
  511. }
  512. void GLContext::gl_get_floatv(GLenum pname, GLfloat* params)
  513. {
  514. get_floating_point(pname, params);
  515. }
  516. void GLContext::gl_get_integerv(GLenum pname, GLint* data)
  517. {
  518. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  519. auto optional_parameter = get_context_parameter(pname);
  520. RETURN_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM);
  521. auto parameter = optional_parameter.release_value();
  522. switch (parameter.type) {
  523. case GL_BOOL:
  524. *data = parameter.value.boolean_value ? GL_TRUE : GL_FALSE;
  525. break;
  526. case GL_DOUBLE: {
  527. double const int_range = static_cast<double>(NumericLimits<GLint>::max()) - NumericLimits<GLint>::min();
  528. for (size_t i = 0; i < parameter.count; ++i) {
  529. double const result_factor = (clamp(parameter.value.double_list[i], -1.0, 1.0) + 1.0) / 2.0;
  530. data[i] = static_cast<GLint>(NumericLimits<GLint>::min() + result_factor * int_range);
  531. }
  532. break;
  533. }
  534. case GL_INT:
  535. for (size_t i = 0; i < parameter.count; ++i)
  536. data[i] = parameter.value.integer_list[i];
  537. break;
  538. default:
  539. VERIFY_NOT_REACHED();
  540. }
  541. }
  542. GLboolean GLContext::gl_is_enabled(GLenum capability)
  543. {
  544. RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, 0);
  545. auto optional_parameter = get_context_parameter(capability);
  546. RETURN_VALUE_WITH_ERROR_IF(!optional_parameter.has_value(), GL_INVALID_ENUM, 0);
  547. auto parameter = optional_parameter.release_value();
  548. RETURN_VALUE_WITH_ERROR_IF(!parameter.is_capability, GL_INVALID_ENUM, 0);
  549. return parameter.value.boolean_value;
  550. }
  551. }