Add tests
This commit is contained in:
parent
71da98a0cd
commit
8743b0a5b9
@ -420,7 +420,7 @@ static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) {
|
||||
if(src->txr.enable == GPU_TEXTURE_DISABLE) {
|
||||
/* Texturing was disabled so we simulate it with a white texture */
|
||||
if(!DEFAULT_TEXTURE) {
|
||||
DEFAULT_TEXTURE = GPUMemoryAlloc(8 * 8 * 2);
|
||||
DEFAULT_TEXTURE = (uint8_t*) GPUMemoryAlloc(8 * 8 * 2);
|
||||
for(int i = 0; i < 8 * 8 * 2; ++i) {
|
||||
DEFAULT_TEXTURE[i] = 0xff;
|
||||
}
|
||||
|
||||
@ -32,8 +32,10 @@
|
||||
#define VEC3_DOT(x1, y1, z1, x2, y2, z2, d) \
|
||||
d = (x1 * x2) + (y1 * y2) + (z1 * z2)
|
||||
|
||||
#ifndef __cplusplus
|
||||
struct PolyHeader;
|
||||
struct PolyContext;
|
||||
#endif
|
||||
|
||||
void UploadMatrix4x4(const Matrix4x4* mat);
|
||||
void MultiplyMatrix4x4(const Matrix4x4* mat);
|
||||
|
||||
@ -272,7 +272,9 @@ typedef enum {
|
||||
#define G8IDX 2
|
||||
#define B8IDX 3
|
||||
|
||||
#ifndef __cplusplus
|
||||
struct SubmissionTarget;
|
||||
#endif
|
||||
|
||||
PolyList* _glOpaquePolyList();
|
||||
PolyList* _glPunchThruPolyList();
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
#include "../include/GL/gl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
GLboolean _glNearZClippingEnabled();
|
||||
GLboolean _glGPUStateIsDirty();
|
||||
void _glGPUStateMarkClean();
|
||||
@ -14,3 +18,7 @@ float* _glCurrentTexCoord1();
|
||||
|
||||
GLfloat _glGetHalfPointSize();
|
||||
GLfloat _glGetHalfLineWidth();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
576
tests/test_glcolor.h
Normal file
576
tests/test_glcolor.h
Normal file
@ -0,0 +1,576 @@
|
||||
#pragma once
|
||||
|
||||
#include "tools/test.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glkos.h>
|
||||
|
||||
/* Internal headers for direct state inspection */
|
||||
#include "GL/state.h"
|
||||
#include "GL/private.h"
|
||||
|
||||
/* =========================================================================
|
||||
* GlColorTests
|
||||
*
|
||||
* Tests for glColor4f / glColor3f / glColor4ub / glColor3ub and their
|
||||
* vector variants. Each call stores a normalised RGBA colour into the
|
||||
* internal current-colour array in ARGB component order:
|
||||
* index 0 = alpha (A8IDX)
|
||||
* index 1 = red (R8IDX)
|
||||
* index 2 = green (G8IDX)
|
||||
* index 3 = blue (B8IDX)
|
||||
* =========================================================================*/
|
||||
class GlColorTests : public test::TestCase {
|
||||
public:
|
||||
void set_up() {
|
||||
GLdcConfig config;
|
||||
glKosInitConfig(&config);
|
||||
config.texture_twiddle = false;
|
||||
glKosInitEx(&config);
|
||||
/* _glInitContext does not reset current_color, so do it explicitly
|
||||
* here so every test starts from a known white default. */
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void tear_down() {
|
||||
glKosShutdown();
|
||||
}
|
||||
|
||||
/* After set_up the current colour must be white (1,1,1,1). */
|
||||
void test_default_color_is_white() {
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor4f must store each component at its correct ARGB slot. */
|
||||
void test_color4f_sets_rgba() {
|
||||
glColor4f(0.25f, 0.5f, 0.75f, 0.9f);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.25f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.50f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.75f, 0.001f);
|
||||
assert_close(color[A8IDX], 0.90f, 0.001f);
|
||||
}
|
||||
|
||||
/* Sanity check for a pure-red colour. */
|
||||
void test_color4f_pure_red() {
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* Sanity check for a pure-blue colour. */
|
||||
void test_color4f_pure_blue() {
|
||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* The second call must completely overwrite the first. */
|
||||
void test_color4f_overwrites_previous_color() {
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[A8IDX], 0.5f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor3f sets RGB and forces alpha to 1.0. */
|
||||
void test_color3f_sets_rgb_and_forces_alpha_to_one() {
|
||||
glColor3f(0.25f, 0.5f, 0.75f);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.25f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.50f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.75f, 0.001f);
|
||||
assert_close(color[A8IDX], 1.00f, 0.001f);
|
||||
}
|
||||
|
||||
/* After a prior glColor4f with alpha=0, glColor3f must reset alpha to 1. */
|
||||
void test_color3f_resets_alpha_to_one() {
|
||||
glColor4f(0.5f, 0.5f, 0.5f, 0.0f);
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor4ub must convert each byte to a normalised float. */
|
||||
void test_color4ub_converts_bytes_to_normalized_floats() {
|
||||
glColor4ub(255, 128, 64, 192);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 255.0f / 255.0f, 0.005f);
|
||||
assert_close(color[G8IDX], 128.0f / 255.0f, 0.005f);
|
||||
assert_close(color[B8IDX], 64.0f / 255.0f, 0.005f);
|
||||
assert_close(color[A8IDX], 192.0f / 255.0f, 0.005f);
|
||||
}
|
||||
|
||||
/* 255 must map to exactly 1.0. */
|
||||
void test_color4ub_max_values_map_to_one() {
|
||||
glColor4ub(255, 255, 255, 255);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* 0 must map to exactly 0.0. */
|
||||
void test_color4ub_zero_values_map_to_zero() {
|
||||
glColor4ub(0, 0, 0, 0);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[A8IDX], 0.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor3ub sets RGB and forces alpha to 1.0. */
|
||||
void test_color3ub_sets_rgb_and_forces_alpha_to_one() {
|
||||
glColor3ub(255, 128, 64);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 255.0f / 255.0f, 0.005f);
|
||||
assert_close(color[G8IDX], 128.0f / 255.0f, 0.005f);
|
||||
assert_close(color[B8IDX], 64.0f / 255.0f, 0.005f);
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor4fv reads RGBA from array. */
|
||||
void test_color4fv_sets_from_array() {
|
||||
GLfloat c[4] = { 0.1f, 0.2f, 0.3f, 0.4f };
|
||||
glColor4fv(c);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.1f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.2f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.3f, 0.001f);
|
||||
assert_close(color[A8IDX], 0.4f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor3fv reads RGB from array and forces alpha to 1. */
|
||||
void test_color3fv_sets_from_array_and_forces_alpha_to_one() {
|
||||
GLfloat c[3] = { 0.5f, 0.6f, 0.7f };
|
||||
glColor3fv(c);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 0.5f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.6f, 0.001f);
|
||||
assert_close(color[B8IDX], 0.7f, 0.001f);
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor4ubv reads RGBA bytes from array. */
|
||||
void test_color4ubv_sets_from_array() {
|
||||
GLubyte c[4] = { 200, 100, 50, 150 };
|
||||
glColor4ubv(c);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 200.0f / 255.0f, 0.005f);
|
||||
assert_close(color[G8IDX], 100.0f / 255.0f, 0.005f);
|
||||
assert_close(color[B8IDX], 50.0f / 255.0f, 0.005f);
|
||||
assert_close(color[A8IDX], 150.0f / 255.0f, 0.005f);
|
||||
}
|
||||
|
||||
/* glColor3ubv reads RGB bytes and forces alpha to 1. */
|
||||
void test_color3ubv_sets_from_array_and_forces_alpha_to_one() {
|
||||
GLubyte c[3] = { 255, 0, 128 };
|
||||
glColor3ubv(c);
|
||||
float* color = _glCurrentColor();
|
||||
assert_close(color[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(color[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(color[B8IDX], 128.0f / 255.0f, 0.005f);
|
||||
assert_close(color[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* Valid colour calls must not produce a GL error. */
|
||||
void test_color_calls_produce_no_gl_error() {
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
glColor3f(0.5f, 0.5f, 0.5f);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
glColor4ub(128, 128, 128, 255);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
glColor3ub(200, 100, 50);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
* GlColorPointerTests
|
||||
*
|
||||
* Tests for glColorPointer. Verifies that the AttribPointer for colour
|
||||
* (ATTRIB_LIST.colour) stores the correct size, type, stride and data
|
||||
* pointer, that stride=0 triggers the automatic stride calculation, and
|
||||
* that invalid size arguments raise GL_INVALID_VALUE.
|
||||
* =========================================================================*/
|
||||
class GlColorPointerTests : public test::TestCase {
|
||||
public:
|
||||
void set_up() {
|
||||
GLdcConfig config;
|
||||
glKosInitConfig(&config);
|
||||
config.texture_twiddle = false;
|
||||
glKosInitEx(&config);
|
||||
/* Reset enabled flags – _glInitAttributePointers does not do this. */
|
||||
ATTRIB_LIST.enabled = 0;
|
||||
}
|
||||
|
||||
void tear_down() {
|
||||
glKosShutdown();
|
||||
}
|
||||
|
||||
/* size=4, GL_FLOAT: stride auto-calculated to 4*4=16. */
|
||||
void test_colorpointer_size4_float_stores_metadata() {
|
||||
GLfloat colors[12] = {};
|
||||
glColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.colour.size, 4);
|
||||
assert_equal(ATTRIB_LIST.colour.type, (GLenum)GL_FLOAT);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(4 * sizeof(GLfloat)));
|
||||
assert_equal(ATTRIB_LIST.colour.ptr, (const void*)colors);
|
||||
}
|
||||
|
||||
/* size=3, GL_FLOAT: stride auto-calculated to 3*4=12. */
|
||||
void test_colorpointer_size3_float_stores_metadata() {
|
||||
GLfloat colors[9] = {};
|
||||
glColorPointer(3, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.colour.size, 3);
|
||||
assert_equal(ATTRIB_LIST.colour.type, (GLenum)GL_FLOAT);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(3 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
/* size=4, GL_UNSIGNED_BYTE: stride auto-calculated to 4*1=4. */
|
||||
void test_colorpointer_size4_ubyte_stores_metadata() {
|
||||
GLubyte colors[12] = {};
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.colour.size, 4);
|
||||
assert_equal(ATTRIB_LIST.colour.type, (GLenum)GL_UNSIGNED_BYTE);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(4 * sizeof(GLubyte)));
|
||||
}
|
||||
|
||||
/* size=3, GL_UNSIGNED_BYTE: stride auto-calculated to 3*1=3. */
|
||||
void test_colorpointer_size3_ubyte_stores_metadata() {
|
||||
GLubyte colors[9] = {};
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.colour.size, 3);
|
||||
assert_equal(ATTRIB_LIST.colour.type, (GLenum)GL_UNSIGNED_BYTE);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(3 * sizeof(GLubyte)));
|
||||
}
|
||||
|
||||
/* GL_BGRA is a valid size token; stride becomes 4 bytes for UNSIGNED_BYTE. */
|
||||
void test_colorpointer_bgra_ubyte_is_valid() {
|
||||
GLubyte colors[12] = {};
|
||||
glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.colour.size, (GLint)GL_BGRA);
|
||||
assert_equal(ATTRIB_LIST.colour.type, (GLenum)GL_UNSIGNED_BYTE);
|
||||
/* 4 bytes per colour element */
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)4);
|
||||
}
|
||||
|
||||
/* size=1 is not a legal value; GL_INVALID_VALUE must be raised. */
|
||||
void test_colorpointer_size1_raises_invalid_value() {
|
||||
GLfloat colors[4] = {};
|
||||
glColorPointer(1, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
/* size=2 is not a legal value; GL_INVALID_VALUE must be raised. */
|
||||
void test_colorpointer_size2_raises_invalid_value() {
|
||||
GLfloat colors[8] = {};
|
||||
glColorPointer(2, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
/* Automatic stride for float4 = 16 bytes. */
|
||||
void test_colorpointer_auto_stride_float4() {
|
||||
GLfloat colors[12] = {};
|
||||
glColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(4 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
/* Automatic stride for float3 = 12 bytes. */
|
||||
void test_colorpointer_auto_stride_float3() {
|
||||
GLfloat colors[9] = {};
|
||||
glColorPointer(3, GL_FLOAT, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(3 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
/* Automatic stride for ubyte4 = 4 bytes. */
|
||||
void test_colorpointer_auto_stride_ubyte4() {
|
||||
GLubyte colors[12] = {};
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)(4 * sizeof(GLubyte)));
|
||||
}
|
||||
|
||||
/* An explicit non-zero stride must be kept unchanged. */
|
||||
void test_colorpointer_explicit_stride_is_preserved() {
|
||||
GLfloat colors[12] = {};
|
||||
glColorPointer(4, GL_FLOAT, 32, colors);
|
||||
assert_equal(ATTRIB_LIST.colour.stride, (GLsizei)32);
|
||||
}
|
||||
|
||||
/* The data pointer must be stored verbatim. */
|
||||
void test_colorpointer_stores_pointer() {
|
||||
GLfloat colors[12] = {};
|
||||
glColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.colour.ptr, (const void*)colors);
|
||||
}
|
||||
|
||||
/* A NULL pointer is accepted without raising an error. */
|
||||
void test_colorpointer_null_pointer_is_accepted() {
|
||||
glColorPointer(4, GL_FLOAT, 0, NULL);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
}
|
||||
|
||||
/* Calling glColorPointer must mark the colour attribute as dirty.
|
||||
* Uses size=3 to guarantee a state change from the size=4 default
|
||||
* initialised by _glInitAttributePointers, avoiding the
|
||||
* _glStateUnchanged early-return path. */
|
||||
void test_colorpointer_marks_colour_attribute_dirty() {
|
||||
GLfloat colors[9] = {};
|
||||
ATTRIB_LIST.dirty = 0;
|
||||
glColorPointer(3, GL_FLOAT, 0, colors);
|
||||
assert_true(ATTRIB_LIST.dirty & COLOR_ENABLED_FLAG);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
* GlSecondaryColorPointerTests
|
||||
*
|
||||
* Mirrors GlColorPointerTests for the secondary (offset) colour pointer
|
||||
* stored in ATTRIB_LIST.s_color.
|
||||
* =========================================================================*/
|
||||
class GlSecondaryColorPointerTests : public test::TestCase {
|
||||
public:
|
||||
void set_up() {
|
||||
GLdcConfig config;
|
||||
glKosInitConfig(&config);
|
||||
config.texture_twiddle = false;
|
||||
glKosInitEx(&config);
|
||||
ATTRIB_LIST.enabled = 0;
|
||||
}
|
||||
|
||||
void tear_down() {
|
||||
glKosShutdown();
|
||||
}
|
||||
|
||||
/* size=4, GL_FLOAT: basic happy path. */
|
||||
void test_secondary_colorpointer_size4_float_stores_metadata() {
|
||||
GLfloat colors[12] = {};
|
||||
glSecondaryColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.s_color.size, 4);
|
||||
assert_equal(ATTRIB_LIST.s_color.type, (GLenum)GL_FLOAT);
|
||||
assert_equal(ATTRIB_LIST.s_color.stride, (GLsizei)(4 * sizeof(GLfloat)));
|
||||
assert_equal(ATTRIB_LIST.s_color.ptr, (const void*)colors);
|
||||
}
|
||||
|
||||
/* size=3, GL_FLOAT: three-component secondary colour. */
|
||||
void test_secondary_colorpointer_size3_float_stores_metadata() {
|
||||
GLfloat colors[9] = {};
|
||||
glSecondaryColorPointer(3, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.s_color.size, 3);
|
||||
assert_equal(ATTRIB_LIST.s_color.type, (GLenum)GL_FLOAT);
|
||||
assert_equal(ATTRIB_LIST.s_color.stride, (GLsizei)(3 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
/* GL_BGRA is a valid size for secondary colour. */
|
||||
void test_secondary_colorpointer_bgra_ubyte_is_valid() {
|
||||
GLubyte colors[12] = {};
|
||||
glSecondaryColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_NO_ERROR);
|
||||
assert_equal(ATTRIB_LIST.s_color.size, (GLint)GL_BGRA);
|
||||
assert_equal(ATTRIB_LIST.s_color.type, (GLenum)GL_UNSIGNED_BYTE);
|
||||
assert_equal(ATTRIB_LIST.s_color.stride, (GLsizei)4);
|
||||
}
|
||||
|
||||
/* size=1 must raise GL_INVALID_VALUE. */
|
||||
void test_secondary_colorpointer_size1_raises_invalid_value() {
|
||||
GLfloat colors[4] = {};
|
||||
glSecondaryColorPointer(1, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
/* size=2 must raise GL_INVALID_VALUE. */
|
||||
void test_secondary_colorpointer_size2_raises_invalid_value() {
|
||||
GLfloat colors[8] = {};
|
||||
glSecondaryColorPointer(2, GL_FLOAT, 0, colors);
|
||||
assert_equal(glGetError(), (GLenum)GL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
/* Automatic stride for float4. */
|
||||
void test_secondary_colorpointer_auto_stride_float4() {
|
||||
GLfloat colors[12] = {};
|
||||
glSecondaryColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.s_color.stride, (GLsizei)(4 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
/* Automatic stride for ubyte3. */
|
||||
void test_secondary_colorpointer_auto_stride_ubyte3() {
|
||||
GLubyte colors[9] = {};
|
||||
glSecondaryColorPointer(3, GL_UNSIGNED_BYTE, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.s_color.stride, (GLsizei)(3 * sizeof(GLubyte)));
|
||||
}
|
||||
|
||||
/* An explicit stride must be preserved. */
|
||||
void test_secondary_colorpointer_explicit_stride_is_preserved() {
|
||||
GLfloat colors[12] = {};
|
||||
glSecondaryColorPointer(4, GL_FLOAT, 24, colors);
|
||||
assert_equal(ATTRIB_LIST.s_color.stride, (GLsizei)24);
|
||||
}
|
||||
|
||||
/* Data pointer must be stored verbatim. */
|
||||
void test_secondary_colorpointer_stores_pointer() {
|
||||
GLfloat colors[12] = {};
|
||||
glSecondaryColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_equal(ATTRIB_LIST.s_color.ptr, (const void*)colors);
|
||||
}
|
||||
|
||||
/* Calling glSecondaryColorPointer must dirty the s_color attribute.
|
||||
* _glInitAttributePointers does not touch s_color, so its state
|
||||
* persists across tests. Zeroing it here guarantees a state
|
||||
* change so _glStateUnchanged does not short-circuit the call. */
|
||||
void test_secondary_colorpointer_marks_attribute_dirty() {
|
||||
memset(&ATTRIB_LIST.s_color, 0, sizeof(ATTRIB_LIST.s_color));
|
||||
GLfloat colors[12] = {};
|
||||
ATTRIB_LIST.dirty = 0;
|
||||
glSecondaryColorPointer(4, GL_FLOAT, 0, colors);
|
||||
assert_true(ATTRIB_LIST.dirty & S_COLOR_ENABLED_FLAG);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
* GlClientStateTests
|
||||
*
|
||||
* Tests for glEnableClientState / glDisableClientState. Verifies that the
|
||||
* appropriate flag bits in ATTRIB_LIST.enabled are set or cleared, that the
|
||||
* dirty flag is updated, and that invalid enumerants raise GL_INVALID_ENUM.
|
||||
* =========================================================================*/
|
||||
class GlClientStateTests : public test::TestCase {
|
||||
public:
|
||||
void set_up() {
|
||||
GLdcConfig config;
|
||||
glKosInitConfig(&config);
|
||||
config.texture_twiddle = false;
|
||||
glKosInitEx(&config);
|
||||
/* Clear all enabled flags for a clean baseline. */
|
||||
ATTRIB_LIST.enabled = 0;
|
||||
}
|
||||
|
||||
void tear_down() {
|
||||
glKosShutdown();
|
||||
}
|
||||
|
||||
/* Enabling GL_COLOR_ARRAY must set COLOR_ENABLED_FLAG. */
|
||||
void test_enable_color_array_sets_flag() {
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
assert_true(ATTRIB_LIST.enabled & COLOR_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Disabling GL_COLOR_ARRAY must clear COLOR_ENABLED_FLAG. */
|
||||
void test_disable_color_array_clears_flag() {
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
assert_false(ATTRIB_LIST.enabled & COLOR_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Enabling GL_VERTEX_ARRAY must set VERTEX_ENABLED_FLAG. */
|
||||
void test_enable_vertex_array_sets_flag() {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
assert_true(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Disabling GL_VERTEX_ARRAY must clear VERTEX_ENABLED_FLAG. */
|
||||
void test_disable_vertex_array_clears_flag() {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
assert_false(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Enabling GL_NORMAL_ARRAY must set NORMAL_ENABLED_FLAG. */
|
||||
void test_enable_normal_array_sets_flag() {
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
assert_true(ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Disabling GL_NORMAL_ARRAY must clear NORMAL_ENABLED_FLAG. */
|
||||
void test_disable_normal_array_clears_flag() {
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
assert_false(ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* With client texture unit 0, GL_TEXTURE_COORD_ARRAY sets UV_ENABLED_FLAG. */
|
||||
void test_enable_texture_coord_array_sets_uv_flag() {
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
assert_true(ATTRIB_LIST.enabled & UV_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Disabling GL_TEXTURE_COORD_ARRAY clears UV_ENABLED_FLAG. */
|
||||
void test_disable_texture_coord_array_clears_uv_flag() {
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
assert_false(ATTRIB_LIST.enabled & UV_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Multiple arrays can be enabled independently. */
|
||||
void test_multiple_arrays_enabled_simultaneously() {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
assert_true(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG);
|
||||
assert_true(ATTRIB_LIST.enabled & COLOR_ENABLED_FLAG);
|
||||
assert_true(ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Disabling one array must not affect others. */
|
||||
void test_disable_one_array_does_not_affect_others() {
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
assert_true (ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG);
|
||||
assert_false(ATTRIB_LIST.enabled & COLOR_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* An invalid cap must raise GL_INVALID_ENUM. */
|
||||
void test_enable_invalid_cap_raises_invalid_enum() {
|
||||
glEnableClientState(0xDEAD);
|
||||
assert_equal(glGetError(), (GLenum)GL_INVALID_ENUM);
|
||||
}
|
||||
|
||||
/* An invalid cap on disable must raise GL_INVALID_ENUM. */
|
||||
void test_disable_invalid_cap_raises_invalid_enum() {
|
||||
glDisableClientState(0xDEAD);
|
||||
assert_equal(glGetError(), (GLenum)GL_INVALID_ENUM);
|
||||
}
|
||||
|
||||
/* Enabling an array must mark the corresponding dirty bit. */
|
||||
void test_enable_color_array_marks_dirty() {
|
||||
ATTRIB_LIST.dirty = 0;
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
assert_true(ATTRIB_LIST.dirty & COLOR_ENABLED_FLAG);
|
||||
}
|
||||
|
||||
/* Disabling an array must also mark the dirty bit so that the function
|
||||
* pointer is recomputed on the next draw. */
|
||||
void test_disable_color_array_marks_dirty() {
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
ATTRIB_LIST.dirty = 0;
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
assert_true(ATTRIB_LIST.dirty & COLOR_ENABLED_FLAG);
|
||||
}
|
||||
};
|
||||
11
tests/test_nearz_clipping.h
Normal file
11
tests/test_nearz_clipping.h
Normal file
@ -0,0 +1,11 @@
|
||||
#include "tools/test.h"
|
||||
|
||||
|
||||
|
||||
class ZClipTests : public test::TestCase {
|
||||
public:
|
||||
|
||||
void test_case_000() {
|
||||
|
||||
}
|
||||
};
|
||||
522
tests/test_pvr_vertex_submission.h
Normal file
522
tests/test_pvr_vertex_submission.h
Normal file
@ -0,0 +1,522 @@
|
||||
#pragma once
|
||||
|
||||
#include "tools/test.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glkos.h>
|
||||
|
||||
/*
|
||||
* Internal headers needed to inspect the Tile Accelerator (TA) submission
|
||||
* buffers directly after a draw call.
|
||||
*
|
||||
* After glDrawArrays / glEnd, the GL driver fills one of three poly-lists
|
||||
* (OP_LIST / PT_LIST / TR_LIST). Each list is an AlignedVector whose
|
||||
* elements are 64-byte Vertex structs. The first element in the vector
|
||||
* after a draw is a PolyHeader (also 64 bytes), followed by the actual
|
||||
* vertex data.
|
||||
*
|
||||
* This file tests:
|
||||
* - That the expected number of PolyHeader + Vertex entries appear
|
||||
* in OP_LIST after various draw calls.
|
||||
* - That the GPU_CMD_VERTEX / GPU_CMD_VERTEX_EOL flags are set on
|
||||
* the correct vertices.
|
||||
* - That the PolyHeader command word is valid.
|
||||
* - That primary colour set via glColor* or glColorPointer appears
|
||||
* correctly in each submitted vertex's argb[] field.
|
||||
*/
|
||||
#include "GL/private.h"
|
||||
#include "containers/aligned_vector.h"
|
||||
|
||||
|
||||
/* =========================================================================
|
||||
* PVRVertexSubmissionTests
|
||||
* =========================================================================*/
|
||||
class PVRVertexSubmissionTests : public test::TestCase {
|
||||
public:
|
||||
void set_up() {
|
||||
GLdcConfig config;
|
||||
glKosInitConfig(&config);
|
||||
config.texture_twiddle = false;
|
||||
glKosInitEx(&config);
|
||||
|
||||
/* Explicit clean slate for colour and client-state. */
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
ATTRIB_LIST.enabled = 0;
|
||||
}
|
||||
|
||||
void tear_down() {
|
||||
glKosShutdown();
|
||||
}
|
||||
|
||||
/* Convenience: cast element i of a list to Vertex*. */
|
||||
static Vertex* vertex_at(PolyList* list, uint32_t i) {
|
||||
return (Vertex*) aligned_vector_at(&list->vector, i);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Basic list structure
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
/* OP_LIST must be empty before the first draw call. */
|
||||
void test_op_list_is_empty_before_any_draw() {
|
||||
assert_equal(aligned_vector_size(&OP_LIST.vector), 0u);
|
||||
}
|
||||
|
||||
/* Drawing a single triangle via immediate mode must produce exactly
|
||||
* one PolyHeader and three vertices (four elements total). */
|
||||
void test_immediate_triangle_produces_four_list_entries() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
assert_equal(aligned_vector_size(&OP_LIST.vector), 4u);
|
||||
}
|
||||
|
||||
/* A second triangle drawn while GPU state is unchanged must not add
|
||||
* another PolyHeader, yielding 4 + 3 = 7 entries. */
|
||||
void test_second_triangle_without_state_change_shares_header() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-0.5f, -0.5f, 0.5f);
|
||||
glVertex3f( 0.5f, -0.5f, 0.5f);
|
||||
glVertex3f( 0.0f, 0.5f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
/* 1 header + 3 verts + 3 verts = 7 */
|
||||
assert_equal(aligned_vector_size(&OP_LIST.vector), 7u);
|
||||
}
|
||||
|
||||
/* After glKosSwapBuffers the list must be cleared. */
|
||||
void test_op_list_is_empty_after_swap_buffers() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
glKosSwapBuffers();
|
||||
|
||||
assert_equal(aligned_vector_size(&OP_LIST.vector), 0u);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* PolyHeader validation
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
/* The PolyHeader command word must have the polygon-header type bits
|
||||
* set (upper byte = 0x80) as defined by GPU_CMD_POLYHDR = 0x80840000. */
|
||||
void test_poly_header_has_correct_upper_byte() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(0.0f, 0.0f, 0.5f);
|
||||
glVertex3f(1.0f, 0.0f, 0.5f);
|
||||
glVertex3f(0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
PolyHeader* hdr = (PolyHeader*) aligned_vector_at(&OP_LIST.vector, 0);
|
||||
/* Top byte must be 0x80 (polygon-header command). */
|
||||
assert_equal(hdr->cmd & 0xFF000000u, 0x80000000u);
|
||||
}
|
||||
|
||||
/* For the opaque list the blend word in mode2 must encode ONE/ZERO. */
|
||||
void test_opaque_poly_header_blend_is_one_zero() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(0.0f, 0.0f, 0.5f);
|
||||
glVertex3f(1.0f, 0.0f, 0.5f);
|
||||
glVertex3f(0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
PolyHeader* hdr = (PolyHeader*) aligned_vector_at(&OP_LIST.vector, 0);
|
||||
|
||||
/* src blend = GPU_BLEND_ONE (1) in bits 31-29 of mode2 */
|
||||
uint32_t src = (hdr->mode2 >> GPU_TA_PM2_SRCBLEND_SHIFT) & 0x7;
|
||||
/* dst blend = GPU_BLEND_ZERO (0) in bits 28-26 of mode2 */
|
||||
uint32_t dst = (hdr->mode2 >> GPU_TA_PM2_DSTBLEND_SHIFT) & 0x7;
|
||||
|
||||
assert_equal(src, (uint32_t)GPU_BLEND_ONE);
|
||||
assert_equal(dst, (uint32_t)GPU_BLEND_ZERO);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Vertex flag tests
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
/* For GL_TRIANGLES, vertices 0 and 1 of the strip carry GPU_CMD_VERTEX;
|
||||
* vertex 2 (end of triangle) carries GPU_CMD_VERTEX_EOL. */
|
||||
void test_triangle_vertex_flags_are_set_correctly() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
/* Index 0 is the PolyHeader; vertices start at index 1. */
|
||||
Vertex* v0 = vertex_at(&OP_LIST, 1);
|
||||
Vertex* v1 = vertex_at(&OP_LIST, 2);
|
||||
Vertex* v2 = vertex_at(&OP_LIST, 3);
|
||||
|
||||
assert_equal(v0->flags, (uint32_t)GPU_CMD_VERTEX);
|
||||
assert_equal(v1->flags, (uint32_t)GPU_CMD_VERTEX);
|
||||
assert_equal(v2->flags, (uint32_t)GPU_CMD_VERTEX_EOL);
|
||||
}
|
||||
|
||||
/* For two back-to-back GL_TRIANGLES the EOL flag must appear on every
|
||||
* third vertex (indices 3 and 6 within the combined list). */
|
||||
void test_two_triangles_have_eol_on_every_third_vertex() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-0.5f, -0.5f, 0.5f);
|
||||
glVertex3f( 0.5f, -0.5f, 0.5f);
|
||||
glVertex3f( 0.0f, 0.5f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
/* 1 header + 6 vertices (indices 1..6) */
|
||||
assert_equal(vertex_at(&OP_LIST, 1)->flags, (uint32_t)GPU_CMD_VERTEX);
|
||||
assert_equal(vertex_at(&OP_LIST, 2)->flags, (uint32_t)GPU_CMD_VERTEX);
|
||||
assert_equal(vertex_at(&OP_LIST, 3)->flags, (uint32_t)GPU_CMD_VERTEX_EOL);
|
||||
assert_equal(vertex_at(&OP_LIST, 4)->flags, (uint32_t)GPU_CMD_VERTEX);
|
||||
assert_equal(vertex_at(&OP_LIST, 5)->flags, (uint32_t)GPU_CMD_VERTEX);
|
||||
assert_equal(vertex_at(&OP_LIST, 6)->flags, (uint32_t)GPU_CMD_VERTEX_EOL);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Immediate-mode colour tests
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
/* A single colour set before all vertices must appear identically in
|
||||
* every submitted vertex (alpha, red, green, blue in ARGB order). */
|
||||
void test_immediate_single_color_appears_in_all_vertices() {
|
||||
/* Set a distinctive colour: R=1, G=0, B=0, A=1 */
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
for(uint32_t i = 1; i <= 3; ++i) {
|
||||
Vertex* v = vertex_at(&OP_LIST, i);
|
||||
assert_close(v->argb[A8IDX], 1.0f, 0.001f);
|
||||
assert_close(v->argb[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(v->argb[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(v->argb[B8IDX], 0.0f, 0.001f);
|
||||
}
|
||||
}
|
||||
|
||||
/* glColor4ub must also produce the correct normalised float values in
|
||||
* the submitted vertices. */
|
||||
void test_immediate_color4ub_appears_correctly_in_vertex() {
|
||||
glColor4ub(0, 255, 0, 255); /* green */
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
Vertex* v = vertex_at(&OP_LIST, 1);
|
||||
assert_close(v->argb[A8IDX], 1.0f, 0.005f);
|
||||
assert_close(v->argb[R8IDX], 0.0f, 0.005f);
|
||||
assert_close(v->argb[G8IDX], 1.0f, 0.005f);
|
||||
assert_close(v->argb[B8IDX], 0.0f, 0.005f);
|
||||
}
|
||||
|
||||
/* Changing the colour between vertex calls must produce per-vertex
|
||||
* colour variation in the submitted list. */
|
||||
void test_immediate_per_vertex_colors_are_distinct() {
|
||||
glBegin(GL_TRIANGLES);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f); /* red */
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
|
||||
glColor4f(0.0f, 1.0f, 0.0f, 1.0f); /* green */
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
|
||||
glColor4f(0.0f, 0.0f, 1.0f, 1.0f); /* blue */
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
Vertex* v0 = vertex_at(&OP_LIST, 1); /* red */
|
||||
Vertex* v1 = vertex_at(&OP_LIST, 2); /* green */
|
||||
Vertex* v2 = vertex_at(&OP_LIST, 3); /* blue */
|
||||
|
||||
/* v0 = red */
|
||||
assert_close(v0->argb[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(v0->argb[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(v0->argb[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(v0->argb[A8IDX], 1.0f, 0.001f);
|
||||
|
||||
/* v1 = green */
|
||||
assert_close(v1->argb[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(v1->argb[G8IDX], 1.0f, 0.001f);
|
||||
assert_close(v1->argb[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(v1->argb[A8IDX], 1.0f, 0.001f);
|
||||
|
||||
/* v2 = blue */
|
||||
assert_close(v2->argb[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(v2->argb[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(v2->argb[B8IDX], 1.0f, 0.001f);
|
||||
assert_close(v2->argb[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* glColor3f (no alpha) must result in alpha=1 in the submitted vertex. */
|
||||
void test_immediate_color3f_vertex_has_full_alpha() {
|
||||
glColor3f(0.5f, 0.25f, 0.1f);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
Vertex* v = vertex_at(&OP_LIST, 1);
|
||||
assert_close(v->argb[A8IDX], 1.0f, 0.001f);
|
||||
assert_close(v->argb[R8IDX], 0.5f, 0.001f);
|
||||
assert_close(v->argb[G8IDX], 0.25f, 0.001f);
|
||||
assert_close(v->argb[B8IDX], 0.1f, 0.001f);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Vertex-array colour tests (glColorPointer path)
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
/* When no colour array is active the current colour (set via glColor*)
|
||||
* must be used for every submitted vertex. */
|
||||
void test_no_color_pointer_uses_current_color_for_all_vertices() {
|
||||
glColor4f(0.5f, 0.25f, 0.1f, 0.8f);
|
||||
|
||||
GLfloat verts[] = {
|
||||
-1.0f, -1.0f, 0.5f,
|
||||
1.0f, -1.0f, 0.5f,
|
||||
0.0f, 1.0f, 0.5f
|
||||
};
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, verts);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
Vertex* v = vertex_at(&OP_LIST, 1);
|
||||
assert_close(v->argb[R8IDX], 0.5f, 0.001f);
|
||||
assert_close(v->argb[G8IDX], 0.25f, 0.001f);
|
||||
assert_close(v->argb[B8IDX], 0.1f, 0.001f);
|
||||
assert_close(v->argb[A8IDX], 0.8f, 0.001f);
|
||||
}
|
||||
|
||||
/* Colours supplied via glColorPointer (GL_FLOAT, size 4, RGBA order)
|
||||
* must reach the submitted vertices in ARGB layout.
|
||||
*
|
||||
* _readColour4fARGB treats the input as RGBA and writes:
|
||||
* argb[R8IDX] = input[0] argb[G8IDX] = input[1]
|
||||
* argb[B8IDX] = input[2] argb[A8IDX] = input[3]
|
||||
*/
|
||||
void test_color_pointer_float4_rgba_stored_correctly() {
|
||||
GLfloat verts[] = {
|
||||
-1.0f, -1.0f, 0.5f,
|
||||
1.0f, -1.0f, 0.5f,
|
||||
0.0f, 1.0f, 0.5f
|
||||
};
|
||||
/* RGBA float colours: red, green, blue */
|
||||
GLfloat colors[] = {
|
||||
1.0f, 0.0f, 0.0f, 1.0f, /* red */
|
||||
0.0f, 1.0f, 0.0f, 1.0f, /* green */
|
||||
0.0f, 0.0f, 1.0f, 1.0f /* blue */
|
||||
};
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, verts);
|
||||
glColorPointer(4, GL_FLOAT, 0, colors);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
Vertex* v0 = vertex_at(&OP_LIST, 1); /* red */
|
||||
Vertex* v1 = vertex_at(&OP_LIST, 2); /* green */
|
||||
Vertex* v2 = vertex_at(&OP_LIST, 3); /* blue */
|
||||
|
||||
/* v0 = red */
|
||||
assert_close(v0->argb[R8IDX], 1.0f, 0.001f);
|
||||
assert_close(v0->argb[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(v0->argb[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(v0->argb[A8IDX], 1.0f, 0.001f);
|
||||
|
||||
/* v1 = green */
|
||||
assert_close(v1->argb[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(v1->argb[G8IDX], 1.0f, 0.001f);
|
||||
assert_close(v1->argb[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(v1->argb[A8IDX], 1.0f, 0.001f);
|
||||
|
||||
/* v2 = blue */
|
||||
assert_close(v2->argb[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(v2->argb[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(v2->argb[B8IDX], 1.0f, 0.001f);
|
||||
assert_close(v2->argb[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* Same test as above but using GL_UNSIGNED_BYTE colours (RGBA order). */
|
||||
void test_color_pointer_ubyte4_rgba_stored_correctly() {
|
||||
GLfloat verts[] = {
|
||||
-1.0f, -1.0f, 0.5f,
|
||||
1.0f, -1.0f, 0.5f,
|
||||
0.0f, 1.0f, 0.5f
|
||||
};
|
||||
/* RGBA ubyte colours: red, green, blue */
|
||||
GLubyte colors[] = {
|
||||
255, 0, 0, 255, /* red */
|
||||
0, 255, 0, 255, /* green */
|
||||
0, 0, 255, 255 /* blue */
|
||||
};
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, verts);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
Vertex* v0 = vertex_at(&OP_LIST, 1);
|
||||
Vertex* v1 = vertex_at(&OP_LIST, 2);
|
||||
Vertex* v2 = vertex_at(&OP_LIST, 3);
|
||||
|
||||
/* v0 = red */
|
||||
assert_close(v0->argb[R8IDX], 1.0f, 0.005f);
|
||||
assert_close(v0->argb[G8IDX], 0.0f, 0.005f);
|
||||
assert_close(v0->argb[B8IDX], 0.0f, 0.005f);
|
||||
assert_close(v0->argb[A8IDX], 1.0f, 0.005f);
|
||||
|
||||
/* v1 = green */
|
||||
assert_close(v1->argb[R8IDX], 0.0f, 0.005f);
|
||||
assert_close(v1->argb[G8IDX], 1.0f, 0.005f);
|
||||
assert_close(v1->argb[B8IDX], 0.0f, 0.005f);
|
||||
assert_close(v1->argb[A8IDX], 1.0f, 0.005f);
|
||||
|
||||
/* v2 = blue */
|
||||
assert_close(v2->argb[R8IDX], 0.0f, 0.005f);
|
||||
assert_close(v2->argb[G8IDX], 0.0f, 0.005f);
|
||||
assert_close(v2->argb[B8IDX], 1.0f, 0.005f);
|
||||
assert_close(v2->argb[A8IDX], 1.0f, 0.005f);
|
||||
}
|
||||
|
||||
/* Three-component float colour pointer (GL_FLOAT, size 3).
|
||||
* _readColour3fARGB reads RGB and forces alpha to 1.0. */
|
||||
void test_color_pointer_float3_rgb_forces_alpha_to_one() {
|
||||
GLfloat verts[] = {
|
||||
-1.0f, -1.0f, 0.5f,
|
||||
1.0f, -1.0f, 0.5f,
|
||||
0.0f, 1.0f, 0.5f
|
||||
};
|
||||
/* RGB float colours only (no alpha channel) */
|
||||
GLfloat colors[] = {
|
||||
0.5f, 0.0f, 0.0f, /* dark red */
|
||||
0.0f, 0.5f, 0.0f, /* dark green */
|
||||
0.0f, 0.0f, 0.5f /* dark blue */
|
||||
};
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, verts);
|
||||
glColorPointer(3, GL_FLOAT, 0, colors);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
Vertex* v0 = vertex_at(&OP_LIST, 1);
|
||||
/* Alpha must be 1 even though input has no alpha channel. */
|
||||
assert_close(v0->argb[A8IDX], 1.0f, 0.001f);
|
||||
assert_close(v0->argb[R8IDX], 0.5f, 0.001f);
|
||||
assert_close(v0->argb[G8IDX], 0.0f, 0.001f);
|
||||
assert_close(v0->argb[B8IDX], 0.0f, 0.001f);
|
||||
|
||||
Vertex* v1 = vertex_at(&OP_LIST, 2);
|
||||
assert_close(v1->argb[A8IDX], 1.0f, 0.001f);
|
||||
assert_close(v1->argb[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(v1->argb[G8IDX], 0.5f, 0.001f);
|
||||
assert_close(v1->argb[B8IDX], 0.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* Using glDrawElements with an index array must produce the same vertex
|
||||
* colours as the equivalent glDrawArrays call. */
|
||||
void test_draw_elements_colour_matches_draw_arrays() {
|
||||
GLfloat verts[] = {
|
||||
-1.0f, -1.0f, 0.5f, /* 0 */
|
||||
1.0f, -1.0f, 0.5f, /* 1 */
|
||||
0.0f, 1.0f, 0.5f /* 2 */
|
||||
};
|
||||
GLfloat colors[] = {
|
||||
0.2f, 0.4f, 0.6f, 1.0f, /* 0 */
|
||||
0.3f, 0.5f, 0.7f, 1.0f, /* 1 */
|
||||
0.4f, 0.6f, 0.8f, 1.0f /* 2 */
|
||||
};
|
||||
GLubyte indices[] = { 0, 1, 2 };
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, verts);
|
||||
glColorPointer(4, GL_FLOAT, 0, colors);
|
||||
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indices);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
Vertex* v0 = vertex_at(&OP_LIST, 1);
|
||||
assert_close(v0->argb[R8IDX], 0.2f, 0.001f);
|
||||
assert_close(v0->argb[G8IDX], 0.4f, 0.001f);
|
||||
assert_close(v0->argb[B8IDX], 0.6f, 0.001f);
|
||||
assert_close(v0->argb[A8IDX], 1.0f, 0.001f);
|
||||
}
|
||||
|
||||
/* Blending enabled must route geometry to TR_LIST, not OP_LIST. */
|
||||
void test_blended_triangle_goes_to_tr_list() {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
/* Opaque list must remain empty. */
|
||||
assert_equal(aligned_vector_size(&OP_LIST.vector), 0u);
|
||||
/* Transparent list must have 1 header + 3 vertices. */
|
||||
assert_equal(aligned_vector_size(&TR_LIST.vector), 4u);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
/* Colours in the TR_LIST must also reflect what was submitted. */
|
||||
void test_blended_triangle_colour_in_tr_list() {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glColor4f(0.0f, 1.0f, 0.0f, 0.5f); /* semi-transparent green */
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(-1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 1.0f, -1.0f, 0.5f);
|
||||
glVertex3f( 0.0f, 1.0f, 0.5f);
|
||||
glEnd();
|
||||
|
||||
Vertex* v = (Vertex*) aligned_vector_at(&TR_LIST.vector, 1);
|
||||
assert_close(v->argb[R8IDX], 0.0f, 0.001f);
|
||||
assert_close(v->argb[G8IDX], 1.0f, 0.001f);
|
||||
assert_close(v->argb[B8IDX], 0.0f, 0.001f);
|
||||
assert_close(v->argb[A8IDX], 0.5f, 0.001f);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
};
|
||||
@ -26,6 +26,7 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
#define assert_equal(expected, actual) _assert_equal((expected), (actual), __FILE__, __LINE__)
|
||||
#define assert_not_equal(expected, actual) _assert_not_equal((expected), (actual), __FILE__, __LINE__)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user