#pragma once #include "tools/test.h" #include "tools/gl_test.h" #include #include #include #include #include #include "GL/private.h" #include "GL/state.h" #include "containers/aligned_vector.h" /* ========================================================================= * TexCoordFormatTests * * Coverage for the texture-coordinate attribute readers (GL/attributes.c). * The supported glTexCoordPointer types each normalise differently: * GL_FLOAT / GL_DOUBLE - passed through * GL_UNSIGNED_BYTE - divided by 255 * GL_SHORT - divided by SHRT_MAX (32767) * GL_INT - passed through (raw) * Each is compared against an equivalent GL_FLOAT draw so the per-type scaling * is pinned down. Immediate-mode glTexCoord2f and the disabled-array (zeroed) * case are covered too. * =========================================================================*/ class TexCoordFormatTests : public GLTestCase { public: void set_up() { GLTestCase::set_up(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } static void reset_list() { aligned_vector_clear(&OP_LIST.vector); _glGPUStateMarkDirty(); } static std::vector captured() { std::vector out; uint32_t n = aligned_vector_size(&OP_LIST.vector); for(uint32_t i = 0; i < n; ++i) { Vertex* v = (Vertex*) aligned_vector_at(&OP_LIST.vector, i); if(v->flags == GPU_CMD_VERTEX || v->flags == GPU_CMD_VERTEX_EOL) { out.push_back(*v); } } return out; } void assert_uvs_match(const std::vector& a, const std::vector& b) { assert_equal(a.size(), b.size()); for(size_t i = 0; i < a.size(); ++i) { assert_close(a[i].uv[0], b[i].uv[0], 0.0005f); assert_close(a[i].uv[1], b[i].uv[1], 0.0005f); } } /* A fixed triangle for the position data. */ static const GLfloat* positions() { static const GLfloat verts[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, }; return verts; } std::vector draw_with_float_uv(const GLfloat* uv) { reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glTexCoordPointer(2, GL_FLOAT, 0, uv); glDrawArrays(GL_TRIANGLES, 0, 3); return captured(); } /* --------------------------------------------------------- float basic */ void test_float_uv_passthrough() { GLfloat uv[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f }; std::vector v = draw_with_float_uv(uv); assert_equal(v.size(), (size_t) 3); assert_close(v[0].uv[0], 0.0f, 0.0005f); assert_close(v[1].uv[0], 1.0f, 0.0005f); assert_close(v[2].uv[1], 1.0f, 0.0005f); } /* --------------------------------------------------------- short / 32767 */ void test_short_uv_is_scaled_by_shrt_max() { GLshort suv[] = { 0, 0, SHRT_MAX, 0, SHRT_MAX / 2, SHRT_MAX, }; GLfloat fuv[] = { 0.0f, 0.0f, (float) SHRT_MAX / SHRT_MAX, 0.0f, (float)(SHRT_MAX / 2) / SHRT_MAX, (float) SHRT_MAX / SHRT_MAX, }; std::vector fref = draw_with_float_uv(fuv); reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glTexCoordPointer(2, GL_SHORT, 0, suv); glDrawArrays(GL_TRIANGLES, 0, 3); std::vector sres = captured(); assert_uvs_match(fref, sres); } /* --------------------------------------------------------- ubyte / 255 */ void test_ubyte_uv_is_scaled_by_255() { GLubyte buv[] = { 0, 0, 255, 0, 128, 255 }; GLfloat fuv[] = { 0.0f, 0.0f, 255.0f/255.0f, 0.0f, 128.0f/255.0f, 255.0f/255.0f, }; std::vector fref = draw_with_float_uv(fuv); reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glTexCoordPointer(2, GL_UNSIGNED_BYTE, 0, buv); glDrawArrays(GL_TRIANGLES, 0, 3); std::vector bres = captured(); assert_uvs_match(fref, bres); } /* --------------------------------------------------------- int raw */ void test_int_uv_is_raw() { GLint iuv[] = { 0, 0, 1, 0, 0, 1 }; GLfloat fuv[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; std::vector fref = draw_with_float_uv(fuv); reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glTexCoordPointer(2, GL_INT, 0, iuv); glDrawArrays(GL_TRIANGLES, 0, 3); std::vector ires = captured(); assert_uvs_match(fref, ires); } /* --------------------------------------------------------- double */ void test_double_uv_passthrough() { GLdouble duv[] = { 0.0, 0.0, 1.0, 0.0, 0.5, 1.0 }; GLfloat fuv[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f }; std::vector fref = draw_with_float_uv(fuv); reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glTexCoordPointer(2, GL_DOUBLE, 0, duv); glDrawArrays(GL_TRIANGLES, 0, 3); std::vector dres = captured(); assert_uvs_match(fref, dres); } /* --------------------------------------------------------- stride */ void test_uv_stride_is_respected() { GLfloat tight[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f }; GLfloat padded[] = { 0.0f, 0.0f, 77.0f, 1.0f, 0.0f, 77.0f, 0.5f, 1.0f, 77.0f, }; std::vector rt = draw_with_float_uv(tight); reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glTexCoordPointer(2, GL_FLOAT, 3 * sizeof(GLfloat), padded); glDrawArrays(GL_TRIANGLES, 0, 3); std::vector rp = captured(); assert_uvs_match(rt, rp); } /* --------------------------------------------------------- disabled */ /* With the texture-coordinate array disabled, every vertex takes the * current texture coordinate (set via glTexCoord), matching fixed-function * GL semantics. */ void test_disabled_coord_array_uses_current_texcoord() { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoord2f(0.25f, 0.75f); reset_list(); glVertexPointer(3, GL_FLOAT, 0, positions()); glDrawArrays(GL_TRIANGLES, 0, 3); std::vector v = captured(); assert_equal(v.size(), (size_t) 3); for(size_t i = 0; i < v.size(); ++i) { assert_close(v[i].uv[0], 0.25f, 0.0005f); assert_close(v[i].uv[1], 0.75f, 0.0005f); } } /* --------------------------------------------------------- immediate */ void test_immediate_texcoord2f_reaches_vertex() { reset_list(); glBegin(GL_TRIANGLES); glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f, 0.0f); glTexCoord2f(0.5f, 1.0f); glVertex3f( 0.0f, 0.5f, 0.0f); glEnd(); std::vector v = captured(); assert_equal(v.size(), (size_t) 3); assert_close(v[0].uv[0], 0.0f, 0.0005f); assert_close(v[0].uv[1], 0.0f, 0.0005f); assert_close(v[1].uv[0], 1.0f, 0.0005f); assert_close(v[2].uv[0], 0.5f, 0.0005f); assert_close(v[2].uv[1], 1.0f, 0.0005f); } /* Immediate texcoords must match the equivalent vertex-array draw. */ void test_immediate_texcoord_matches_array() { GLfloat uv[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 1.0f }; std::vector arr = draw_with_float_uv(uv); reset_list(); glBegin(GL_TRIANGLES); glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f, 0.0f); glTexCoord2f(0.5f, 1.0f); glVertex3f( 0.0f, 0.5f, 0.0f); glEnd(); std::vector imm = captured(); assert_uvs_match(arr, imm); } };