diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h index bc9654e54b7..a1acd0c0441 100644 --- a/Userland/Libraries/LibGL/GL/gl.h +++ b/Userland/Libraries/LibGL/GL/gl.h @@ -358,6 +358,7 @@ GLAPI void glTexCoord2f(GLfloat s, GLfloat t); GLAPI void glTexCoord4fv(const GLfloat* v); GLAPI void glTexParameteri(GLenum target, GLenum pname, GLint param); GLAPI void glTexParameterf(GLenum target, GLenum pname, GLfloat param); +GLAPI void glTexEnvf(GLenum target, GLenum pname, GLfloat param); GLAPI void glBindTexture(GLenum target, GLuint texture); GLAPI void glActiveTexture(GLenum texture); GLAPI void glGetFloatv(GLenum pname, GLfloat* params); diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h index b1e869fab0a..6dd6f37a164 100644 --- a/Userland/Libraries/LibGL/GLContext.h +++ b/Userland/Libraries/LibGL/GLContext.h @@ -60,6 +60,7 @@ public: virtual void gl_tex_image_2d(GLenum target, GLint level, GLint internal_format, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* data) = 0; virtual void gl_tex_parameter(GLenum target, GLenum pname, GLfloat param) = 0; virtual void gl_tex_coord(GLfloat s, GLfloat t, GLfloat r, GLfloat q) = 0; + virtual void gl_tex_env(GLenum target, GLenum pname, GLfloat param) = 0; virtual void gl_bind_texture(GLenum target, GLuint texture) = 0; virtual void gl_active_texture(GLenum texture) = 0; virtual void gl_get_floatv(GLenum pname, GLfloat* params) = 0; diff --git a/Userland/Libraries/LibGL/GLTexture.cpp b/Userland/Libraries/LibGL/GLTexture.cpp index 97364df1bfc..03e86d9d6b7 100644 --- a/Userland/Libraries/LibGL/GLTexture.cpp +++ b/Userland/Libraries/LibGL/GLTexture.cpp @@ -46,3 +46,8 @@ void glTexParameterf(GLenum target, GLenum pname, GLfloat param) { g_gl_context->gl_tex_parameter(target, pname, param); } + +void glTexEnvf(GLenum target, GLenum pname, GLfloat param) +{ + g_gl_context->gl_tex_env(target, pname, param); +} diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.cpp b/Userland/Libraries/LibGL/SoftwareGLContext.cpp index 0cc5f507a05..e068bb0edd2 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.cpp +++ b/Userland/Libraries/LibGL/SoftwareGLContext.cpp @@ -1482,6 +1482,36 @@ void SoftwareGLContext::gl_tex_coord_pointer(GLint size, GLenum type, GLsizei st m_client_tex_coord_pointer.pointer = pointer; } +void SoftwareGLContext::gl_tex_env(GLenum target, GLenum pname, GLfloat param) +{ + APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_env, target, pname, param); + RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); + + if (target == GL_TEXTURE_ENV) { + if (pname == GL_TEXTURE_ENV_MODE) { + auto param_enum = static_cast(param); + + switch (param_enum) { + case GL_MODULATE: + case GL_REPLACE: + case GL_DECAL: + m_active_texture_unit->set_env_mode(param_enum); + break; + default: + // FIXME: We currently only support a subset of possible param values. Implement the rest! + RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); + break; + } + } else { + // FIXME: We currently only support a subset of possible pname values. Implement the rest! + RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); + } + } else { + // FIXME: We currently only support a subset of possible target values. Implement the rest! + RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); + } +} + void SoftwareGLContext::gl_draw_arrays(GLenum mode, GLint first, GLsizei count) { APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_arrays, mode, first, count); diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.h b/Userland/Libraries/LibGL/SoftwareGLContext.h index 23ad3e2db9e..92fa1242f8e 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.h +++ b/Userland/Libraries/LibGL/SoftwareGLContext.h @@ -70,6 +70,7 @@ public: virtual void gl_tex_image_2d(GLenum target, GLint level, GLint internal_format, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* data) override; virtual void gl_tex_parameter(GLenum target, GLenum pname, GLfloat param) override; virtual void gl_tex_coord(GLfloat s, GLfloat t, GLfloat r, GLfloat q) override; + virtual void gl_tex_env(GLenum target, GLenum pname, GLfloat param) override; virtual void gl_bind_texture(GLenum target, GLuint texture) override; virtual void gl_active_texture(GLenum texture) override; virtual void gl_get_floatv(GLenum pname, GLfloat* params) override; diff --git a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp index cfd55134760..9c5341f5176 100644 --- a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp +++ b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp @@ -483,9 +483,7 @@ SoftwareRasterizer::SoftwareRasterizer(const Gfx::IntSize& min_size) void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array& texture_units) { rasterize_triangle(m_options, *m_render_target, *m_depth_buffer, triangle, [this, &texture_units](const FloatVector2& uv, const FloatVector4& color, float z) -> FloatVector4 { - // TODO: We'd do some kind of multitexturing/blending here - // Construct a vector for the texel we want to sample - FloatVector4 texel = color; + FloatVector4 fragment = color; for (const auto& texture_unit : texture_units) { @@ -493,8 +491,27 @@ void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array if (!texture_unit.is_bound()) continue; - // FIXME: Don't assume Texture2D, _and_ work out how we blend/do multitexturing properly..... - texel = texel * static_ptr_cast(texture_unit.bound_texture())->sampler().sample(uv); + // FIXME: Don't assume Texture2D + auto texel = texture_unit.bound_texture_2d()->sampler().sample(uv); + + // FIXME: Implement more blend modes + switch (texture_unit.env_mode()) { + case GL_MODULATE: + default: + fragment = fragment * texel; + break; + case GL_REPLACE: + fragment = texel; + break; + case GL_DECAL: { + float src_alpha = fragment.w(); + float one_minus_src_alpha = 1 - src_alpha; + fragment.set_x(texel.x() * src_alpha + fragment.x() * one_minus_src_alpha); + fragment.set_y(texel.y() * src_alpha + fragment.y() * one_minus_src_alpha); + fragment.set_z(texel.z() * src_alpha + fragment.z() * one_minus_src_alpha); + break; + } + } } // Calculate fog @@ -516,10 +533,10 @@ void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array } // Mix texel with fog - texel = mix(m_options.fog_color, texel, factor); + fragment = mix(m_options.fog_color, fragment, factor); } - return texel; + return fragment; }); } diff --git a/Userland/Libraries/LibGL/Tex/TextureUnit.h b/Userland/Libraries/LibGL/Tex/TextureUnit.h index d54341d194a..24330125153 100644 --- a/Userland/Libraries/LibGL/Tex/TextureUnit.h +++ b/Userland/Libraries/LibGL/Tex/TextureUnit.h @@ -24,10 +24,14 @@ public: GLenum currently_bound_target() const { return m_currently_bound_target; } bool is_bound() const { return !m_currently_bound_texture.is_null(); } + void set_env_mode(GLenum mode) { m_env_mode = mode; } + GLenum env_mode() const { return m_env_mode; } + private: mutable RefPtr m_texture_target_2d { nullptr }; mutable RefPtr m_currently_bound_texture { nullptr }; GLenum m_currently_bound_target; + GLenum m_env_mode { GL_MODULATE }; }; }