SoftwareGLContext.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /*
  2. * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
  3. * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@gmx.de>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "SoftwareGLContext.h"
  8. #include "GLStruct.h"
  9. #include "SoftwareRasterizer.h"
  10. #include <AK/Assertions.h>
  11. #include <AK/Debug.h>
  12. #include <AK/Format.h>
  13. #include <AK/QuickSort.h>
  14. #include <AK/Vector.h>
  15. #include <LibGfx/Bitmap.h>
  16. #include <LibGfx/Painter.h>
  17. #include <LibGfx/Vector4.h>
  18. #include <math.h>
  19. using AK::dbgln;
  20. namespace GL {
  21. // FIXME: We should set this up when we create the context!
  22. static constexpr size_t MATRIX_STACK_LIMIT = 1024;
  23. SoftwareGLContext::SoftwareGLContext(Gfx::Bitmap& frontbuffer)
  24. : m_frontbuffer(frontbuffer)
  25. , m_rasterizer(frontbuffer.size())
  26. {
  27. }
  28. void SoftwareGLContext::gl_begin(GLenum mode)
  29. {
  30. if (m_in_draw_state) {
  31. m_error = GL_INVALID_OPERATION;
  32. return;
  33. }
  34. if (mode < GL_TRIANGLES || mode > GL_POLYGON) {
  35. m_error = GL_INVALID_ENUM;
  36. return;
  37. }
  38. m_current_draw_mode = mode;
  39. m_in_draw_state = true; // Certain commands will now generate an error
  40. m_error = GL_NO_ERROR;
  41. }
  42. void SoftwareGLContext::gl_clear(GLbitfield mask)
  43. {
  44. if (m_in_draw_state) {
  45. m_error = GL_INVALID_OPERATION;
  46. return;
  47. }
  48. if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) {
  49. m_error = GL_INVALID_ENUM;
  50. return;
  51. }
  52. if (mask & GL_COLOR_BUFFER_BIT)
  53. m_rasterizer.clear_color(m_clear_color);
  54. if (mask & GL_DEPTH_BUFFER_BIT)
  55. m_rasterizer.clear_depth(static_cast<float>(m_clear_depth));
  56. m_error = GL_NO_ERROR;
  57. }
  58. void SoftwareGLContext::gl_clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
  59. {
  60. if (m_in_draw_state) {
  61. m_error = GL_INVALID_OPERATION;
  62. return;
  63. }
  64. m_clear_color = { red, green, blue, alpha };
  65. m_error = GL_NO_ERROR;
  66. }
  67. void SoftwareGLContext::gl_clear_depth(GLdouble depth)
  68. {
  69. if (m_in_draw_state) {
  70. m_error = GL_INVALID_OPERATION;
  71. return;
  72. }
  73. m_clear_depth = depth;
  74. m_error = GL_NO_ERROR;
  75. }
  76. void SoftwareGLContext::gl_color(GLdouble r, GLdouble g, GLdouble b, GLdouble a)
  77. {
  78. m_current_vertex_color = { (float)r, (float)g, (float)b, (float)a };
  79. m_error = GL_NO_ERROR;
  80. }
  81. void SoftwareGLContext::gl_end()
  82. {
  83. // At this point, the user has effectively specified that they are done with defining the geometry
  84. // of what they want to draw. We now need to do a few things (https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview):
  85. //
  86. // 1. Transform all of the vertices in the current vertex list into eye space by mulitplying the model-view matrix
  87. // 2. Transform all of the vertices from eye space into clip space by multiplying by the projection matrix
  88. // 3. If culling is enabled, we cull the desired faces (https://learnopengl.com/Advanced-OpenGL/Face-culling)
  89. // 4. Each element of the vertex is then divided by w to bring the positions into NDC (Normalized Device Coordinates)
  90. // 5. The vertices are sorted (for the rasteriser, how are we doing this? 3Dfx did this top to bottom in terms of vertex y co-ordinates)
  91. // 6. The vertices are then sent off to the rasteriser and drawn to the screen
  92. float scr_width = m_frontbuffer->width();
  93. float scr_height = m_frontbuffer->height();
  94. // Make sure we had a `glBegin` before this call...
  95. if (!m_in_draw_state) {
  96. m_error = GL_INVALID_OPERATION;
  97. return;
  98. }
  99. // Let's construct some triangles
  100. if (m_current_draw_mode == GL_TRIANGLES) {
  101. GLTriangle triangle;
  102. for (size_t i = 0; i < vertex_list.size(); i += 3) {
  103. triangle.vertices[0] = vertex_list.at(i);
  104. triangle.vertices[1] = vertex_list.at(i + 1);
  105. triangle.vertices[2] = vertex_list.at(i + 2);
  106. triangle_list.append(triangle);
  107. }
  108. } else if (m_current_draw_mode == GL_QUADS) {
  109. // We need to construct two triangles to form the quad
  110. GLTriangle triangle;
  111. VERIFY(vertex_list.size() % 4 == 0);
  112. for (size_t i = 0; i < vertex_list.size(); i += 4) {
  113. // Triangle 1
  114. triangle.vertices[0] = vertex_list.at(i);
  115. triangle.vertices[1] = vertex_list.at(i + 1);
  116. triangle.vertices[2] = vertex_list.at(i + 2);
  117. triangle_list.append(triangle);
  118. // Triangle 2
  119. triangle.vertices[0] = vertex_list.at(i + 2);
  120. triangle.vertices[1] = vertex_list.at(i + 3);
  121. triangle.vertices[2] = vertex_list.at(i);
  122. triangle_list.append(triangle);
  123. }
  124. } else if (m_current_draw_mode == GL_TRIANGLE_FAN) {
  125. GLTriangle triangle;
  126. triangle.vertices[0] = vertex_list.at(0); // Root vertex is always the vertex defined first
  127. for (size_t i = 1; i < vertex_list.size() - 1; i++) // This is technically `n-2` triangles. We start at index 1
  128. {
  129. triangle.vertices[1] = vertex_list.at(i);
  130. triangle.vertices[2] = vertex_list.at(i + 1);
  131. triangle_list.append(triangle);
  132. }
  133. } else if (m_current_draw_mode == GL_TRIANGLE_STRIP) {
  134. GLTriangle triangle;
  135. for (size_t i = 0; i < vertex_list.size() - 2; i++) {
  136. triangle.vertices[0] = vertex_list.at(i);
  137. triangle.vertices[1] = vertex_list.at(i + 1);
  138. triangle.vertices[2] = vertex_list.at(i + 2);
  139. triangle_list.append(triangle);
  140. }
  141. } else {
  142. m_error = GL_INVALID_ENUM;
  143. return;
  144. }
  145. // Now let's transform each triangle and send that to the GPU
  146. for (size_t i = 0; i < triangle_list.size(); i++) {
  147. GLTriangle& triangle = triangle_list.at(i);
  148. GLVertex& vertexa = triangle.vertices[0];
  149. GLVertex& vertexb = triangle.vertices[1];
  150. GLVertex& vertexc = triangle.vertices[2];
  151. FloatVector4 veca({ vertexa.x, vertexa.y, vertexa.z, 1.0f });
  152. FloatVector4 vecb({ vertexb.x, vertexb.y, vertexb.z, 1.0f });
  153. FloatVector4 vecc({ vertexc.x, vertexc.y, vertexc.z, 1.0f });
  154. // First multiply the vertex by the MODELVIEW matrix and then the PROJECTION matrix
  155. veca = m_model_view_matrix * veca;
  156. veca = m_projection_matrix * veca;
  157. vecb = m_model_view_matrix * vecb;
  158. vecb = m_projection_matrix * vecb;
  159. vecc = m_model_view_matrix * vecc;
  160. vecc = m_projection_matrix * vecc;
  161. // At this point, we're in clip space
  162. // Here's where we do the clipping. This is a really crude implementation of the
  163. // https://learnopengl.com/Getting-started/Coordinate-Systems
  164. // "Note that if only a part of a primitive e.g. a triangle is outside the clipping volume OpenGL
  165. // will reconstruct the triangle as one or more triangles to fit inside the clipping range. "
  166. //
  167. // ALL VERTICES ARE DEFINED IN A CLOCKWISE ORDER
  168. // Okay, let's do some face culling first
  169. Vector<FloatVector4> vecs;
  170. Vector<GLVertex> verts;
  171. vecs.append(veca);
  172. vecs.append(vecb);
  173. vecs.append(vecc);
  174. m_clipper.clip_triangle_against_frustum(vecs);
  175. // TODO: Copy color and UV information too!
  176. for (size_t vec_idx = 0; vec_idx < vecs.size(); vec_idx++) {
  177. FloatVector4& vec = vecs.at(vec_idx);
  178. GLVertex vertex;
  179. // Perform the perspective divide
  180. if (vec.w() != 0.0f) {
  181. vec.set_x(vec.x() / vec.w());
  182. vec.set_y(vec.y() / vec.w());
  183. vec.set_z(vec.z() / vec.w());
  184. }
  185. vertex.x = vec.x();
  186. vertex.y = vec.y();
  187. vertex.z = vec.z();
  188. vertex.w = vec.w();
  189. // FIXME: This is to suppress any -Wunused errors
  190. vertex.u = 0.0f;
  191. vertex.v = 0.0f;
  192. if (vec_idx == 0) {
  193. vertex.r = vertexa.r;
  194. vertex.g = vertexa.g;
  195. vertex.b = vertexa.b;
  196. vertex.a = vertexa.a;
  197. } else if (vec_idx == 1) {
  198. vertex.r = vertexb.r;
  199. vertex.g = vertexb.g;
  200. vertex.b = vertexb.b;
  201. vertex.a = vertexb.a;
  202. } else {
  203. vertex.r = vertexc.r;
  204. vertex.g = vertexc.g;
  205. vertex.b = vertexc.b;
  206. vertex.a = vertexc.a;
  207. }
  208. vertex.x = (vec.x() + 1.0f) * (scr_width / 2.0f) + 0.0f; // TODO: 0.0f should be something!?
  209. vertex.y = scr_height - ((vec.y() + 1.0f) * (scr_height / 2.0f) + 0.0f);
  210. vertex.z = vec.z();
  211. verts.append(vertex);
  212. }
  213. if (verts.size() == 0) {
  214. continue;
  215. } else if (verts.size() == 3) {
  216. GLTriangle tri;
  217. tri.vertices[0] = verts.at(0);
  218. tri.vertices[1] = verts.at(1);
  219. tri.vertices[2] = verts.at(2);
  220. processed_triangles.append(tri);
  221. } else if (verts.size() == 4) {
  222. GLTriangle tri1;
  223. GLTriangle tri2;
  224. tri1.vertices[0] = verts.at(0);
  225. tri1.vertices[1] = verts.at(1);
  226. tri1.vertices[2] = verts.at(2);
  227. processed_triangles.append(tri1);
  228. tri2.vertices[0] = verts.at(0);
  229. tri2.vertices[1] = verts.at(2);
  230. tri2.vertices[2] = verts.at(3);
  231. processed_triangles.append(tri2);
  232. }
  233. }
  234. for (size_t i = 0; i < processed_triangles.size(); i++) {
  235. GLTriangle& triangle = processed_triangles.at(i);
  236. // Let's calculate the (signed) area of the triangle
  237. // https://cp-algorithms.com/geometry/oriented-triangle-area.html
  238. float dxAB = triangle.vertices[0].x - triangle.vertices[1].x; // A.x - B.x
  239. float dxBC = triangle.vertices[1].x - triangle.vertices[2].x; // B.X - C.x
  240. float dyAB = triangle.vertices[0].y - triangle.vertices[1].y;
  241. float dyBC = triangle.vertices[1].y - triangle.vertices[2].y;
  242. float area = (dxAB * dyBC) - (dxBC * dyAB);
  243. if (area == 0.0f)
  244. continue;
  245. if (m_cull_faces) {
  246. bool is_front = (m_front_face == GL_CCW ? area > 0 : area < 0);
  247. if (is_front && (m_culled_sides == GL_FRONT || m_culled_sides == GL_FRONT_AND_BACK))
  248. continue;
  249. if (!is_front && (m_culled_sides == GL_BACK || m_culled_sides == GL_FRONT_AND_BACK))
  250. continue;
  251. }
  252. m_rasterizer.submit_triangle(triangle);
  253. }
  254. triangle_list.clear();
  255. processed_triangles.clear();
  256. vertex_list.clear();
  257. m_in_draw_state = false;
  258. m_error = GL_NO_ERROR;
  259. }
  260. void SoftwareGLContext::gl_frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
  261. {
  262. if (m_in_draw_state) {
  263. m_error = GL_INVALID_OPERATION;
  264. return;
  265. }
  266. // Let's do some math!
  267. // FIXME: Are we losing too much precision by doing this?
  268. float a = static_cast<float>((right + left) / (right - left));
  269. float b = static_cast<float>((top + bottom) / (top - bottom));
  270. float c = static_cast<float>(-((far_val + near_val) / (far_val - near_val)));
  271. float d = static_cast<float>(-((2 * (far_val * near_val)) / (far_val - near_val)));
  272. FloatMatrix4x4 frustum {
  273. ((2 * (float)near_val) / ((float)right - (float)left)), 0, a, 0,
  274. 0, ((2 * (float)near_val) / ((float)top - (float)bottom)), b, 0,
  275. 0, 0, c, d,
  276. 0, 0, -1, 0
  277. };
  278. if (m_current_matrix_mode == GL_PROJECTION) {
  279. m_projection_matrix = m_projection_matrix * frustum;
  280. } else if (m_current_matrix_mode == GL_MODELVIEW) {
  281. dbgln_if(GL_DEBUG, "glFrustum(): frustum created with curr_matrix_mode == GL_MODELVIEW!!!");
  282. m_projection_matrix = m_model_view_matrix * frustum;
  283. }
  284. m_error = GL_NO_ERROR;
  285. }
  286. void SoftwareGLContext::gl_ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
  287. {
  288. if (m_in_draw_state) {
  289. m_error = GL_INVALID_OPERATION;
  290. return;
  291. }
  292. if (left == right || bottom == top || near_val == far_val) {
  293. m_error = GL_INVALID_VALUE;
  294. return;
  295. }
  296. auto rl = right - left;
  297. auto tb = top - bottom;
  298. auto fn = far_val - near_val;
  299. auto tx = -(right + left) / rl;
  300. auto ty = -(top + bottom) / tb;
  301. auto tz = -(far_val + near_val) / fn;
  302. FloatMatrix4x4 projection {
  303. static_cast<float>(2 / rl), 0, 0, static_cast<float>(tx),
  304. 0, static_cast<float>(2 / tb), 0, static_cast<float>(ty),
  305. 0, 0, static_cast<float>(-2 / fn), static_cast<float>(tz),
  306. 0, 0, 0, 1
  307. };
  308. if (m_current_matrix_mode == GL_PROJECTION) {
  309. m_projection_matrix = m_projection_matrix * projection;
  310. } else if (m_current_matrix_mode == GL_MODELVIEW) {
  311. m_projection_matrix = m_model_view_matrix * projection;
  312. }
  313. m_error = GL_NO_ERROR;
  314. }
  315. GLenum SoftwareGLContext::gl_get_error()
  316. {
  317. if (m_in_draw_state) {
  318. return GL_INVALID_OPERATION;
  319. }
  320. return m_error;
  321. }
  322. GLubyte* SoftwareGLContext::gl_get_string(GLenum name)
  323. {
  324. if (m_in_draw_state) {
  325. m_error = GL_INVALID_OPERATION;
  326. return nullptr;
  327. }
  328. switch (name) {
  329. case GL_VENDOR:
  330. return reinterpret_cast<GLubyte*>(const_cast<char*>("The SerenityOS Developers"));
  331. case GL_RENDERER:
  332. return reinterpret_cast<GLubyte*>(const_cast<char*>("SerenityOS OpenGL"));
  333. case GL_VERSION:
  334. return reinterpret_cast<GLubyte*>(const_cast<char*>("OpenGL 1.2 SerenityOS"));
  335. default:
  336. dbgln_if(GL_DEBUG, "glGetString(): Unknown enum name!");
  337. break;
  338. }
  339. m_error = GL_INVALID_ENUM;
  340. return nullptr;
  341. }
  342. void SoftwareGLContext::gl_load_identity()
  343. {
  344. if (m_in_draw_state) {
  345. m_error = GL_INVALID_OPERATION;
  346. return;
  347. }
  348. if (m_current_matrix_mode == GL_PROJECTION)
  349. m_projection_matrix = FloatMatrix4x4::identity();
  350. else if (m_current_matrix_mode == GL_MODELVIEW)
  351. m_model_view_matrix = FloatMatrix4x4::identity();
  352. else
  353. VERIFY_NOT_REACHED();
  354. m_error = GL_NO_ERROR;
  355. }
  356. void SoftwareGLContext::gl_load_matrix(const FloatMatrix4x4& matrix)
  357. {
  358. if (m_in_draw_state) {
  359. m_error = GL_INVALID_OPERATION;
  360. return;
  361. }
  362. if (m_current_matrix_mode == GL_PROJECTION)
  363. m_projection_matrix = matrix;
  364. else if (m_current_matrix_mode == GL_MODELVIEW)
  365. m_model_view_matrix = matrix;
  366. else
  367. VERIFY_NOT_REACHED();
  368. m_error = GL_NO_ERROR;
  369. }
  370. void SoftwareGLContext::gl_matrix_mode(GLenum mode)
  371. {
  372. if (m_in_draw_state) {
  373. m_error = GL_INVALID_OPERATION;
  374. return;
  375. }
  376. if (mode < GL_MODELVIEW || mode > GL_PROJECTION) {
  377. m_error = GL_INVALID_ENUM;
  378. return;
  379. }
  380. m_current_matrix_mode = mode;
  381. m_error = GL_NO_ERROR;
  382. }
  383. void SoftwareGLContext::gl_push_matrix()
  384. {
  385. if (m_in_draw_state) {
  386. m_error = GL_INVALID_OPERATION;
  387. return;
  388. }
  389. dbgln_if(GL_DEBUG, "glPushMatrix(): Pushing matrix to the matrix stack (matrix_mode {})", m_current_matrix_mode);
  390. switch (m_current_matrix_mode) {
  391. case GL_PROJECTION:
  392. if (m_projection_matrix_stack.size() >= MATRIX_STACK_LIMIT) {
  393. m_error = GL_STACK_OVERFLOW;
  394. return;
  395. }
  396. m_projection_matrix_stack.append(m_projection_matrix);
  397. break;
  398. case GL_MODELVIEW:
  399. if (m_model_view_matrix_stack.size() >= MATRIX_STACK_LIMIT) {
  400. m_error = GL_STACK_OVERFLOW;
  401. return;
  402. }
  403. m_model_view_matrix_stack.append(m_model_view_matrix);
  404. break;
  405. default:
  406. dbgln_if(GL_DEBUG, "glPushMatrix(): Attempt to push matrix with invalid matrix mode {})", m_current_matrix_mode);
  407. return;
  408. }
  409. m_error = GL_NO_ERROR;
  410. }
  411. void SoftwareGLContext::gl_pop_matrix()
  412. {
  413. if (m_in_draw_state) {
  414. m_error = GL_INVALID_OPERATION;
  415. return;
  416. }
  417. dbgln_if(GL_DEBUG, "glPopMatrix(): Popping matrix from matrix stack (matrix_mode = {})", m_current_matrix_mode);
  418. // FIXME: Make sure stack::top() doesn't cause any nasty issues if it's empty (that could result in a lockup/hang)
  419. switch (m_current_matrix_mode) {
  420. case GL_PROJECTION:
  421. if (m_projection_matrix_stack.size() == 0) {
  422. m_error = GL_STACK_UNDERFLOW;
  423. return;
  424. }
  425. m_projection_matrix = m_projection_matrix_stack.take_last();
  426. break;
  427. case GL_MODELVIEW:
  428. if (m_model_view_matrix_stack.size() == 0) {
  429. m_error = GL_STACK_UNDERFLOW;
  430. return;
  431. }
  432. m_model_view_matrix = m_model_view_matrix_stack.take_last();
  433. break;
  434. default:
  435. dbgln_if(GL_DEBUG, "glPopMatrix(): Attempt to pop matrix with invalid matrix mode, {}", m_current_matrix_mode);
  436. return;
  437. }
  438. m_error = GL_NO_ERROR;
  439. }
  440. void SoftwareGLContext::gl_rotate(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
  441. {
  442. if (m_in_draw_state) {
  443. m_error = GL_INVALID_OPERATION;
  444. return;
  445. }
  446. FloatVector3 axis = { (float)x, (float)y, (float)z };
  447. axis.normalize();
  448. auto rotation_mat = FloatMatrix4x4::rotate(axis, angle);
  449. if (m_current_matrix_mode == GL_MODELVIEW)
  450. m_model_view_matrix = m_model_view_matrix * rotation_mat;
  451. else if (m_current_matrix_mode == GL_PROJECTION)
  452. m_projection_matrix = m_projection_matrix * rotation_mat;
  453. m_error = GL_NO_ERROR;
  454. }
  455. void SoftwareGLContext::gl_scale(GLdouble x, GLdouble y, GLdouble z)
  456. {
  457. if (m_in_draw_state) {
  458. m_error = GL_INVALID_OPERATION;
  459. return;
  460. }
  461. if (m_current_matrix_mode == GL_MODELVIEW) {
  462. m_model_view_matrix = m_model_view_matrix * FloatMatrix4x4::scale({ static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) });
  463. } else if (m_current_matrix_mode == GL_PROJECTION) {
  464. m_projection_matrix = m_projection_matrix * FloatMatrix4x4::scale({ static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) });
  465. }
  466. m_error = GL_NO_ERROR;
  467. }
  468. void SoftwareGLContext::gl_translate(GLdouble x, GLdouble y, GLdouble z)
  469. {
  470. if (m_in_draw_state) {
  471. m_error = GL_INVALID_OPERATION;
  472. return;
  473. }
  474. if (m_current_matrix_mode == GL_MODELVIEW) {
  475. m_model_view_matrix = m_model_view_matrix * FloatMatrix4x4::translate({ (float)x, (float)y, (float)z });
  476. } else if (m_current_matrix_mode == GL_PROJECTION) {
  477. m_projection_matrix = m_projection_matrix * FloatMatrix4x4::translate({ (float)x, (float)y, (float)z });
  478. }
  479. m_error = GL_NO_ERROR;
  480. }
  481. void SoftwareGLContext::gl_vertex(GLdouble x, GLdouble y, GLdouble z, GLdouble w)
  482. {
  483. GLVertex vertex;
  484. vertex.x = x;
  485. vertex.y = y;
  486. vertex.z = z;
  487. vertex.w = w;
  488. vertex.r = m_current_vertex_color.x();
  489. vertex.g = m_current_vertex_color.y();
  490. vertex.b = m_current_vertex_color.z();
  491. vertex.a = m_current_vertex_color.w();
  492. // FIXME: This is to suppress any -Wunused errors
  493. vertex.w = 0.0f;
  494. vertex.u = 0.0f;
  495. vertex.v = 0.0f;
  496. vertex_list.append(vertex);
  497. m_error = GL_NO_ERROR;
  498. }
  499. void SoftwareGLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height)
  500. {
  501. if (m_in_draw_state) {
  502. m_error = GL_INVALID_OPERATION;
  503. return;
  504. }
  505. (void)(x);
  506. (void)(y);
  507. (void)(width);
  508. (void)(height);
  509. m_error = GL_NO_ERROR;
  510. }
  511. void SoftwareGLContext::gl_enable(GLenum capability)
  512. {
  513. if (m_in_draw_state) {
  514. m_error = GL_INVALID_OPERATION;
  515. return;
  516. }
  517. auto rasterizer_options = m_rasterizer.options();
  518. bool update_rasterizer_options = false;
  519. switch (capability) {
  520. case GL_CULL_FACE:
  521. m_cull_faces = true;
  522. break;
  523. case GL_DEPTH_TEST:
  524. m_depth_test_enabled = true;
  525. rasterizer_options.enable_depth_test = true;
  526. update_rasterizer_options = true;
  527. break;
  528. default:
  529. m_error = GL_INVALID_ENUM;
  530. break;
  531. }
  532. if (update_rasterizer_options)
  533. m_rasterizer.set_options(rasterizer_options);
  534. }
  535. void SoftwareGLContext::gl_disable(GLenum capability)
  536. {
  537. if (m_in_draw_state) {
  538. m_error = GL_INVALID_OPERATION;
  539. return;
  540. }
  541. auto rasterizer_options = m_rasterizer.options();
  542. bool update_rasterizer_options = false;
  543. switch (capability) {
  544. case GL_CULL_FACE:
  545. m_cull_faces = false;
  546. break;
  547. case GL_DEPTH_TEST:
  548. m_depth_test_enabled = false;
  549. rasterizer_options.enable_depth_test = false;
  550. update_rasterizer_options = true;
  551. break;
  552. default:
  553. m_error = GL_INVALID_ENUM;
  554. break;
  555. }
  556. if (update_rasterizer_options)
  557. m_rasterizer.set_options(rasterizer_options);
  558. }
  559. void SoftwareGLContext::gl_front_face(GLenum face)
  560. {
  561. if (face < GL_CW || face > GL_CCW) {
  562. m_error = GL_INVALID_ENUM;
  563. return;
  564. }
  565. m_front_face = face;
  566. }
  567. void SoftwareGLContext::gl_cull_face(GLenum cull_mode)
  568. {
  569. if (cull_mode < GL_FRONT || cull_mode > GL_FRONT_AND_BACK) {
  570. m_error = GL_INVALID_ENUM;
  571. return;
  572. }
  573. m_culled_sides = cull_mode;
  574. }
  575. void SoftwareGLContext::present()
  576. {
  577. m_rasterizer.blit_to(*m_frontbuffer);
  578. }
  579. }