Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update docs #50

Merged
merged 4 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,47 @@ OpenGX is an OpenGL-like wrapper which sits on GX subsystem. It implements the m
TODO list

* Fix lighting transform (which is buggy) and implement spotlights (untested)
* Fix immediate mode to support arbitrary number of glVertex calls
* Add more texture formats and/or add texture format conversion routines
* Add freeglut or some SDL official patch to support context render creation (and remove manual initialization!)
* Fix texture allocation. Now it's mandatory to allocate a texture name using glGen and you can't just bind the texture and use it
* Complete glGet call
* Add support for attribute push/pop
* Add support for glReadPixels and similar calls
* glError ang glGetString: add some error mechanism

List of features (detailed but not exhaustive)

* Texture conversion/compression. Accepts RGB,RGBA,COMPRESSED_RGBA and LUMINANCE_ALPHA.
* Matrix math stuff including glu calls
* Texture mipmapping (and gluBuildMipMaps)
* Ambient and diffuse lighting. Looking forward to enable specular too. But note that 3 modes can't be used at the same time (HW restriction)
* Texture sub-images
* Texture coordinate generation
* Ambient and diffuse, emission and specular lighting
* Indexed and not indexed draw modes
* Blending support
* Blending support
* Alpha compare
* Call lists
* Fog
* Selection mode

There are several limitations on the implementation of many features, mostly
due to the hardware. They are detailed in the PDF documentation, but feel free
to file an issue if unsure.

Design documentation
--------------------

Please see the `opengx.pdf` file which is [automatically generated with each
build](https://github.com/devkitPro/opengx/actions/workflows/docs.yml).


Build instructions
------------------

The project is built with [cmake](https://cmake.org/) and requires the `libogc`
package from [devkitPro](https://devkitpro.org/). Once these dependencies are
installed, build opengx as follows:

# Use GameCube.cmake to build for the GameCube instead
cmake -S. -Bbuild -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake"
cd build
make
# Optional, to install it into devkitPro's portslib:
sudo -E PATH=$PATH make install
42 changes: 36 additions & 6 deletions doc/src/opengx.tex
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
\lstset{language=C}

\title{\textbf{\huge{OpenGX}}}
\author{David Guillen Fandos \\ \small{([email protected])} }
\date{June 18th, 2012}
\author{
David Guillen Fandos \\ \small{([email protected])}
\and
Alberto Mardegan \\ \small{([email protected])}
}
\date{\today}
\usepackage{amsmath}
\usepackage{float}

Expand Down Expand Up @@ -338,7 +342,7 @@ \subsubsection{Unlit and textured render}

\subsubsection{Lit and untextured render}

The light color is calculated using two channel colors. We're going to use channel 0 to emulate ambient lights and channel 1 to emulate diffuse lights. This decision is explained later. So we'll use two TEV stages, the first for rasterizing the channel zero and the second for rasterizing the channel one and combine them.
The light color is calculated using two channel colors. We're going to use channel 0 to emulate ambient and specular lights and channel 1 to emulate diffuse lights. This decision is explained later. So we'll use two TEV stages, the first for rasterizing the channel zero and the second for rasterizing the channel one and combine them.

\begin{figure}[ht]
\centering
Expand All @@ -364,13 +368,16 @@ \subsubsection{Lit and textured render}

OpenGL has support for up to eight lights. Each light has a direction, position, cutoff, etc. depending how the light behaves (it's a point, a light cone, a directional light...). But all the lights have three color components: ambient, diffuse and specular. The ambient component only depends on the distance of the light and the vertex. The diffuse component depends on the distance (just like the ambient) but also depends on the light angle formed by the light and the surface normal. Finally specular lights depend on the distance as well and the angle formed by the light, the vertex and the viewer.

It's important to remember that the diffuse attenuation factor of a light is on a per channel basis instead by light. So we have to use one channel for ambient lights and another one for diffuse lights. We exclude specular lighting because there aren't enough channels to compute the specular component. For those reasons we are limiting the number of active lights to four. We'll use the four first GX lights to emulate ambient lighting and the other four lights to emulate diffuse lighting.
It's important to remember that the diffuse attenuation factor of a light is on a per channel basis instead by light. So we have to use one channel for ambient and specular lights and another one for diffuse lights. We put specular lights in the same channel as the ambient light because ambient lights are not attenuated, so we can set the attenuation function to GX\_AF\_SPEC without affecting them. In the second channel we compute the diffuse lights.

The ambient source for both channel is set to GX\_SRC\_REG, and the register values are the global ambient color for the first channel, and zero (which results in no ambient light addition) for the second one.

As for the materials, while OpenGL allows specifying different material colors for the specular and for the ambient lights, in GX we can specify only one material color per each channel. Since we are using the first channel both for the ambient and the specular lights, we need to make a choice between which material color to use: our choice falls onto the ambient color if ambient lighting is enabled, and set it to the specular color only if we have no ambient light. The reason is that, generally, ambient light has a stronger visual impact on the rendered scene, so we prioritize it. This leads to an issue where, if both ambient and specular lights are enabled, the specular light will be computed using the ambient material color, ignoring whatever the client requested for the specular material color; but in most cases this should not result in a noticeable difference.

The material stuff is done in CPU. We multiply the light color by the material color and use the resulting color as light color. The global ambient light, which is an additive light color without attenuation, is implemented using the ambient color present in the lighting ecuation, although it could be just added after as a constant color in a TEV stage (but this way we save a TEV stage).

\subsection {Texture management}

Only 2D textures are implemented. The formats accepted by the implementation are mainly RGB and RGBA but also other special formats like Luminance and compressed textures. The internal formats accepted by the GPU are shown in Figure~\ref{table:format1}.
Only 2D and 1D textures are implemented. The formats accepted by the implementation are mainly RGB and RGBA but also other special formats like Luminance and compressed textures. The internal formats accepted by the GPU are shown in Figure~\ref{table:format1}.

\begin{figure}[ht]
\centering
Expand All @@ -386,6 +393,10 @@ \subsubsection{Lit and textured render}
GX\_TF\_CMPR & N/A & 1 bit & Yes\\
\hline
GX\_TF\_IA8 & 8 bits & 8 bits & No \\
\hline
GX\_TF\_I8 & 8 bits & No & No \\
\hline
GX\_TF\_A8 & No & 8 bits & No \\
\hline
\end{tabular}
\caption{Texture formats used by OpenGX}
Expand All @@ -399,6 +410,25 @@ \subsubsection{Lit and textured render}
Texture levels (used for mipmapping) are implemented in an efficient way. If the user loads one texture level the implementation reserves memory for that level only. If the user loads more levels the memory is resized to accommodate all the levels. GX allows the programmer to specify a level range for a specific texture, so we can have one level textures and multiple level textures.


\subsection {Call lists}

Call lists are mostly implemented in software, storing the command opcodes and parameters into memory and replaying them later. The notable exception is drawing commands, that are compiled into a GX display list and then stored along with the other operations.

The HANDLE\_CALL\_LIST macro is called at the beginning of those GL functions that can be stored into a call list. It takes care of adding the operation to the active call list (if there's one) minimizing the visual impact of call lists on the code base.


\subsection {Selection mode}

GL selection mode, also known as "picking mode", is typically used in applications to determine which objects are rendered at a certain screen position, in order to implement mouse interactions. When selection mode is active, drawing primitives do not result in any pixels (or even Z-pixels) being drawn, but instead produce a stack containing the names of the object which would have been drawn.

OpenGX implements selection mode by switching of color and alpha updates, but the Z-buffer is still being drawn to in order to have a way to track the objects being drawn: whenever we want to know if a drawing primitive will result in a hit, we clear the GX bounding box before executing the draw commands and examine it afterwards.

When leaving the selection mode we need to restore the Z buffer to its initial state (which we saved using GX\_CopyTex) by rendering it as a Z-texture.

\subsubsection {Limitations}

The hit information recorded during selection mode should also contain the minimum and maximum values of the Z buffer at the moment that a hit was recorded. This is a relatively expensive operation (there's no shortcut around examining all Z pixels one by one) which OpenGX does not currently perform: not only we haven't found an application using this information, but both the AMD and Mesa drivers on the Linux desktop seem to not deliver it and just set both these values to 0.


\pagebreak[4]

Expand Down