The Quake 3 port makes use of this extension to determine a more
efficient multitexturing strategy. Since LibSoftGPU supports it, let's
report the extension in LibGL. :^)
In OpenGL this is called the (base) internal format which is an
expectation expressed by the client for the minimum supported texel
storage format in the GPU for textures.
Since we store everything as RGBA in a `FloatVector4`, the only thing
we do in this patch is remember the expected internal format, and when
we write new texels we fixate the value for the alpha channel to 1 for
two formats that require it.
`PixelConverter` has learned how to transform pixels during transfer to
support this.
A GPU (driver) is now responsible for reading and writing pixels from
and to user data. The client (LibGL) is responsible for specifying how
the user data must be interpreted or written to.
This allows us to centralize all pixel format conversion in one class,
`LibSoftGPU::PixelConverter`. For both the input and output image, it
takes a specification containing the image dimensions, the pixel type
and the selection (basically a clipping rect), and converts the pixels
from the input image to the output image.
Effectively this means we now support almost all OpenGL 1.5 formats,
and all custom logic has disappeared from:
- `glDrawPixels`
- `glReadPixels`
- `glTexImage2D`
- `glTexSubImage2D`
The new logic is still unoptimized, but on my machine I experienced no
noticeable slowdown. :^)
Also skip the test for the `::Always` alpha test function in the hot
loop. This test function is very unlikely to be set, so leave that up
to `::test_alpha()`.
This commit implements glClipPlane and its supporting calls, backed
by new support for user-defined clip planes in the software GPU clipper.
This fixes some visual bugs seen in the Quake III port, in which mirrors
would only reflect correctly from close distances.
According to the OpenGL spec, we're expected to clamp the fragment
depth values to the range `0.f - 1.f` for all polygons.
This fixes Z-fighting issues with the sky in Quake 3.
This implements the depth offset factor that you can set through e.g.
OpenGL's `glPolygonOffset`. Without it, triangles might start to Z-
fight amongst each other.
This fixes the floor decals in Quake 3.
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
Our move to floating point precision has eradicated the pixel artifacts
in Quake 1, but introduced new and not so subtle rendering glitches in
games like Tux Racer. This commit changes three things to get the best
of both worlds:
1. Subpixel logic based on `i32` types was reintroduced, the number of
bits is set to 6. This reintroduces the artifacts in Quake 1 but
fixes rendering of Tux Racer.
2. Before triangle culling, subpixel coordinates are calculated and
stored in `Triangle`. These coordinates are rounded, which fixes the
Quake 1 artifacts. Tux Racer is unaffected.
3. The triangle area (actually parallelogram area) is also stored in
`Triangle` so we don't need to recalculate it later on. In our
previous subpixel code, there was a subtle disconnect between the
two calculations (one with and one without subpixel precision) which
resulted in triangles incorrectly being culled. This fixes some
remaining Quake 1 artifacts.
If a triangle edge is completely horizontal and moving in a positive X
direction, we were erroneously treating it as a top edge. This adds
a better check that accounts for those edges. :^)
We sat on a throne of lies: our `edge_function()` returned positive
values for _clockwise_ vertex rotation instead of _counter-clockwise_,
which was hidden by the fact that we were forcing everything into CW
rotation by an erroneous area comparison (`> 0` instead of `< 0`).
This simplifies our culling code significantly.
This introduces a new device independent base class for Images in LibGPU
that also keeps track of the device from which it was created in order
to prevent assigning images across devices.
This introduces a new abstraction layer, LibGPU, that serves as the
usermode interface to GPU devices. To get started we just move the
DeviceConfig there and make sure everything still works :^)
We now support generating top-left submatrices from a `Gfx::Matrix`
and we move the normal transformation calculation into
`SoftGPU::Device`. No functional changes.
We were transforming the vertices' normals twice (bug 1) and
normalizing them after lighting (bug 2). In the lighting code, we were
then diverting from the spec to deal with the normal situation, which
is now no longer needed.
This fixes the lighting of Tux in Tux Racer.
This replaces the fixed point subpixel precision logic.
GLQuake now effectively renders artifact-free. Previously white/gray
pixels would sometimes be visible at triangle edges, caused by slightly
misaligned triangle edges as a result of converting the vertex window
coordinates to `int`. These artifacts were reduced by the introduction
of subpixel precision, but not completely eliminated.
Some interesting changes in this commit:
* Applying the top-left rule for our counter-clockwise vertices is now
done with simpler conditions: every vertex that has a Y coordinate
lower than or equal to the previous vertex' Y coordinate is counted
as a top or left edge. A float epsilon is used to emulate a switch
between `> 0` and `>= 0` comparisons.
* Fog depth calculation into a `f32x4` is now done once per triangle
instead of once per fragment, and only if fog is enabled.
* The `one_over_area` value was previously calculated as `1.0f / area`,
where `area` was an `int`. This resulted in a lower quality
reciprocal value whereas we can now retain floating point precision.
The effect of this can be seen in Tux Racer, where the ice reflection
is noticeably smoother.
There were some issues with the old code: we were saving the length of
the light vector but not actually using it anywhere, if we were dealing
with a zero-vector this could potentially divide by zero resulting in a
black fragment color, and we were erroneously using P2's length instead
of P1's length when P1's W coordinate is zero in the SGI arrow
operation.
This fixes some lighting bugs in Grim Fandango, but this probably
affects all lighting as well.
This fixes the issue where e.g. `299.97` would be cast to an integer
value of `299`, whereas the pixel's center would lie at `299.5` and
would then erroneously be excluded.
Currently, LibSoftGPU is still OpenGL-minded in that it uses a
coordinate system with the origin of `(0, 0)` at the lower-left of
textures, buffers and window coordinates. Because we are blitting to a
`Gfx::Bitmap` that has the origin at the top-left, we need to flip the
Y-coordinates somewhere in the rasterization logic.
We used to do this during conversion of NDC-coordinates to window
coordinates. This resulted in some incorrect behavior when
rasterization did not pass through the vertex transformation logic,
e.g. when calling `glDrawPixels`.
This changes the coordinate system to OpenGL's throughout, only to blit
the final color buffer upside down to the target bitmap. This fixes
drawing to the depth buffer directly resulting in upside down images.