diff --git a/README.md b/README.md index 25b197f..300a7b0 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/doc/src/opengx.tex b/doc/src/opengx.tex index 3401bdd..2deaeb1 100644 --- a/doc/src/opengx.tex +++ b/doc/src/opengx.tex @@ -9,8 +9,12 @@ \lstset{language=C} \title{\textbf{\huge{OpenGX}}} -\author{David Guillen Fandos \\ \small{(david@davidgf.net)} } -\date{June 18th, 2012} +\author{ + David Guillen Fandos \\ \small{(david@davidgf.net)} + \and + Alberto Mardegan \\ \small{(info@mardy.it)} +} +\date{\today} \usepackage{amsmath} \usepackage{float} @@ -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 @@ -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 @@ -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} @@ -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]