X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=misc%2Fmediasource%2Fnetradiant-src%2Flibs%2Frender.h;fp=misc%2Fmediasource%2Fnetradiant-src%2Flibs%2Frender.h;h=fb243650a5e1d24b87e18abca04b919e4f794bda;hb=65bc0125990fdbce3dd3232d61f1554cb7e317cb;hp=0000000000000000000000000000000000000000;hpb=4dab6b8497e278118a8237e150d276e91501bfb0;p=voretournament%2Fvoretournament.git diff --git a/misc/mediasource/netradiant-src/libs/render.h b/misc/mediasource/netradiant-src/libs/render.h new file mode 100644 index 00000000..fb243650 --- /dev/null +++ b/misc/mediasource/netradiant-src/libs/render.h @@ -0,0 +1,1372 @@ +/* +Copyright (C) 2001-2006, William Joseph. +All Rights Reserved. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#if !defined(INCLUDED_RENDER_H) +#define INCLUDED_RENDER_H + +/// \file +/// \brief High-level constructs for efficient OpenGL rendering. + +#include "irender.h" +#include "igl.h" + +#include "container/array.h" +#include "math/vector.h" +#include "math/pi.h" + +#include + +typedef unsigned int RenderIndex; +const GLenum RenderIndexTypeID = GL_UNSIGNED_INT; + +/// \brief A resizable buffer of indices. +class IndexBuffer +{ + typedef std::vector Indices; + Indices m_data; +public: + typedef Indices::iterator iterator; + typedef Indices::const_iterator const_iterator; + + iterator begin() + { + return m_data.begin(); + } + const_iterator begin() const + { + return m_data.begin(); + } + iterator end() + { + return m_data.end(); + } + const_iterator end() const + { + return m_data.end(); + } + + bool empty() const + { + return m_data.empty(); + } + std::size_t size() const + { + return m_data.size(); + } + const RenderIndex* data() const + { + return &(*m_data.begin()); + } + RenderIndex& operator[](std::size_t index) + { + return m_data[index]; + } + const RenderIndex& operator[](std::size_t index) const + { + return m_data[index]; + } + void clear() + { + m_data.clear(); + } + void reserve(std::size_t max_indices) + { + m_data.reserve(max_indices); + } + void insert(RenderIndex index) + { + m_data.push_back(index); + } + void swap(IndexBuffer& other) + { + std::swap(m_data, m_data); + } +}; + +namespace std +{ + /// \brief Swaps the values of \p self and \p other. + /// Overloads std::swap. + inline void swap(IndexBuffer& self, IndexBuffer& other) + { + self.swap(other); + } +} + +/// \brief A resizable buffer of vertices. +/// \param Vertex The vertex data type. +template +class VertexBuffer +{ + typedef typename std::vector Vertices; + Vertices m_data; +public: + typedef typename Vertices::iterator iterator; + typedef typename Vertices::const_iterator const_iterator; + + iterator begin() + { + return m_data.begin(); + } + iterator end() + { + return m_data.end(); + } + const_iterator begin() const + { + return m_data.begin(); + } + const_iterator end() const + { + return m_data.end(); + } + + bool empty() const + { + return m_data.empty(); + } + RenderIndex size() const + { + return RenderIndex(m_data.size()); + } + const Vertex* data() const + { + return &(*m_data.begin()); + } + Vertex& operator[](std::size_t index) + { + return m_data[index]; + } + const Vertex& operator[](std::size_t index) const + { + return m_data[index]; + } + + void clear() + { + m_data.clear(); + } + void reserve(std::size_t max_vertices) + { + m_data.reserve(max_vertices); + } + void push_back(const Vertex& vertex) + { + m_data.push_back(vertex); + } +}; + +/// \brief A wrapper around a VertexBuffer which inserts only vertices which have not already been inserted. +/// \param Vertex The vertex data type. Must support operator<, operator== and operator!=. +/// For best performance, quantise vertices before inserting them. +template +class UniqueVertexBuffer +{ + typedef VertexBuffer Vertices; + Vertices& m_data; + + struct bnode + { + bnode() + : m_left(0), m_right(0) + { + } + RenderIndex m_left; + RenderIndex m_right; + }; + + std::vector m_btree; + RenderIndex m_prev0; + RenderIndex m_prev1; + RenderIndex m_prev2; + + const RenderIndex find_or_insert(const Vertex& vertex) + { + RenderIndex index = 0; + + while(1) + { + if(vertex < m_data[index]) + { + bnode& node = m_btree[index]; + if(node.m_left != 0) + { + index = node.m_left; + continue; + } + else + { + node.m_left = RenderIndex(m_btree.size()); + m_btree.push_back(bnode()); + m_data.push_back(vertex); + return RenderIndex(m_btree.size()-1); + } + } + if(m_data[index] < vertex) + { + bnode& node = m_btree[index]; + if(node.m_right != 0) + { + index = node.m_right; + continue; + } + else + { + node.m_right = RenderIndex(m_btree.size()); + m_btree.push_back(bnode()); + m_data.push_back(vertex); + return RenderIndex(m_btree.size()-1); + } + } + + return index; + } + } +public: + UniqueVertexBuffer(Vertices& data) + : m_data(data), m_prev0(0), m_prev1(0), m_prev2(0) + { + } + + typedef typename Vertices::const_iterator iterator; + + iterator begin() const + { + return m_data.begin(); + } + iterator end() const + { + return m_data.end(); + } + + std::size_t size() const + { + return m_data.size(); + } + const Vertex* data() const + { + return &(*m_data.begin()); + } + Vertex& operator[](std::size_t index) + { + return m_data[index]; + } + const Vertex& operator[](std::size_t index) const + { + return m_data[index]; + } + + void clear() + { + m_prev0 = 0; + m_prev1 = 0; + m_prev2 = 0; + m_data.clear(); + m_btree.clear(); + } + void reserve(std::size_t max_vertices) + { + m_data.reserve(max_vertices); + m_btree.reserve(max_vertices); + } + /// \brief Returns the index of the element equal to \p vertex. + RenderIndex insert(const Vertex& vertex) + { + if(m_data.empty()) + { + m_data.push_back(vertex); + m_btree.push_back(bnode()); + return 0; + } + + if(m_data[m_prev0] == vertex) + return m_prev0; + if(m_prev1 != m_prev0 && m_data[m_prev1] == vertex) + return m_prev1; + if(m_prev2 != m_prev0 && m_prev2 != m_prev1 && m_data[m_prev2] == vertex) + return m_prev2; + + m_prev2 = m_prev1; + m_prev1 = m_prev0; + m_prev0 = find_or_insert(vertex); + + return m_prev0; + } +}; + + +/// \brief A 4-byte colour. +struct Colour4b +{ + unsigned char r, g, b, a; + + Colour4b() + { + } + + Colour4b(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a) + : r(_r), g(_g), b(_b), a(_a) + { + } +}; + +const Colour4b colour_vertex(0, 255, 0, 255); +const Colour4b colour_selected(0, 0, 255, 255); + +inline bool operator<(const Colour4b& self, const Colour4b& other) +{ + if(self.r != other.r) + { + return self.r < other.r; + } + if(self.g != other.g) + { + return self.g < other.g; + } + if(self.b != other.b) + { + return self.b < other.b; + } + if(self.a != other.a) + { + return self.a < other.a; + } + return false; +} + +inline bool operator==(const Colour4b& self, const Colour4b& other) +{ + return self.r == other.r && self.g == other.g && self.b == other.b && self.a == other.a; +} + +inline bool operator!=(const Colour4b& self, const Colour4b& other) +{ + return !operator==(self, other); +} + +/// \brief A 3-float vertex. +struct Vertex3f : public Vector3 +{ + Vertex3f() + { + } + + Vertex3f(float _x, float _y, float _z) + : Vector3(_x, _y, _z) + { + } +}; + +inline bool operator<(const Vertex3f& self, const Vertex3f& other) +{ + if(self.x() != other.x()) + { + return self.x() < other.x(); + } + if(self.y() != other.y()) + { + return self.y() < other.y(); + } + if(self.z() != other.z()) + { + return self.z() < other.z(); + } + return false; +} + +inline bool operator==(const Vertex3f& self, const Vertex3f& other) +{ + return self.x() == other.x() && self.y() == other.y() && self.z() == other.z(); +} + +inline bool operator!=(const Vertex3f& self, const Vertex3f& other) +{ + return !operator==(self, other); +} + + +inline Vertex3f vertex3f_from_array(const float* array) +{ + return Vertex3f(array[0], array[1], array[2]); +} + +inline float* vertex3f_to_array(Vertex3f& vertex) +{ + return reinterpret_cast(&vertex); +} + +inline const float* vertex3f_to_array(const Vertex3f& vertex) +{ + return reinterpret_cast(&vertex); +} + +const Vertex3f vertex3f_identity(0, 0, 0); + +inline Vertex3f vertex3f_for_vector3(const Vector3& vector3) +{ + return Vertex3f(vector3.x(), vector3.y(), vector3.z()); +} + +inline const Vector3& vertex3f_to_vector3(const Vertex3f& vertex) +{ + return vertex; +} + +inline Vector3& vertex3f_to_vector3(Vertex3f& vertex) +{ + return vertex; +} + + +/// \brief A 3-float normal. +struct Normal3f : public Vector3 +{ + Normal3f() + { + } + + Normal3f(float _x, float _y, float _z) + : Vector3(_x, _y, _z) + { + } +}; + +inline bool operator<(const Normal3f& self, const Normal3f& other) +{ + if(self.x() != other.x()) + { + return self.x() < other.x(); + } + if(self.y() != other.y()) + { + return self.y() < other.y(); + } + if(self.z() != other.z()) + { + return self.z() < other.z(); + } + return false; +} + +inline bool operator==(const Normal3f& self, const Normal3f& other) +{ + return self.x() == other.x() && self.y() == other.y() && self.z() == other.z(); +} + +inline bool operator!=(const Normal3f& self, const Normal3f& other) +{ + return !operator==(self, other); +} + + +inline Normal3f normal3f_from_array(const float* array) +{ + return Normal3f(array[0], array[1], array[2]); +} + +inline float* normal3f_to_array(Normal3f& normal) +{ + return reinterpret_cast(&normal); +} + +inline const float* normal3f_to_array(const Normal3f& normal) +{ + return reinterpret_cast(&normal); +} + +inline Normal3f normal3f_for_vector3(const Vector3& vector3) +{ + return Normal3f(vector3.x(), vector3.y(), vector3.z()); +} + +inline const Vector3& normal3f_to_vector3(const Normal3f& normal) +{ + return normal; +} + +inline Vector3& normal3f_to_vector3(Normal3f& normal) +{ + return normal; +} + + +/// \brief A 2-float texture-coordinate set. +struct TexCoord2f : public Vector2 +{ + TexCoord2f() + { + } + + TexCoord2f(float _s, float _t) + : Vector2(_s, _t) + { + } + + float& s() + { + return x(); + } + const float& s() const + { + return x(); + } + float& t() + { + return y(); + } + const float& t() const + { + return y(); + } +}; + +inline bool operator<(const TexCoord2f& self, const TexCoord2f& other) +{ + if(self.s() != other.s()) + { + return self.s() < other.s(); + } + if(self.t() != other.t()) + { + return self.t() < other.t(); + } + return false; +} + +inline bool operator==(const TexCoord2f& self, const TexCoord2f& other) +{ + return self.s() == other.s() && self.t() == other.t(); +} + +inline bool operator!=(const TexCoord2f& self, const TexCoord2f& other) +{ + return !operator==(self, other); +} + + +inline float* texcoord2f_to_array(TexCoord2f& texcoord) +{ + return reinterpret_cast(&texcoord); +} + +inline const float* texcoord2f_to_array(const TexCoord2f& texcoord) +{ + return reinterpret_cast(&texcoord); +} + +inline const TexCoord2f& texcoord2f_from_array(const float* array) +{ + return *reinterpret_cast(array); +} + +inline TexCoord2f texcoord2f_for_vector2(const Vector2& vector2) +{ + return TexCoord2f(vector2.x(), vector2.y()); +} + +inline const Vector2& texcoord2f_to_vector2(const TexCoord2f& vertex) +{ + return vertex; +} + +inline Vector2& texcoord2f_to_vector2(TexCoord2f& vertex) +{ + return vertex; +} + +/// \brief Returns \p normal rescaled to be unit-length. +inline Normal3f normal3f_normalised(const Normal3f& normal) +{ + return normal3f_for_vector3(vector3_normalised(normal3f_to_vector3(normal))); +} + +enum UnitSphereOctant +{ + UNITSPHEREOCTANT_000 = 0 << 0 | 0 << 1 | 0 << 2, + UNITSPHEREOCTANT_001 = 0 << 0 | 0 << 1 | 1 << 2, + UNITSPHEREOCTANT_010 = 0 << 0 | 1 << 1 | 0 << 2, + UNITSPHEREOCTANT_011 = 0 << 0 | 1 << 1 | 1 << 2, + UNITSPHEREOCTANT_100 = 1 << 0 | 0 << 1 | 0 << 2, + UNITSPHEREOCTANT_101 = 1 << 0 | 0 << 1 | 1 << 2, + UNITSPHEREOCTANT_110 = 1 << 0 | 1 << 1 | 0 << 2, + UNITSPHEREOCTANT_111 = 1 << 0 | 1 << 1 | 1 << 2, +}; + +/// \brief Returns the octant for \p normal indicating the sign of the region of unit-sphere space it lies within. +inline UnitSphereOctant normal3f_classify_octant(const Normal3f& normal) +{ + return static_cast( + ((normal.x() > 0) << 0) | ((normal.y() > 0) << 1) | ((normal.z() > 0) << 2) + ); +} + +/// \brief Returns \p normal with its components signs made positive based on \p octant. +inline Normal3f normal3f_fold_octant(const Normal3f& normal, UnitSphereOctant octant) +{ + switch(octant) + { + case UNITSPHEREOCTANT_000: + return Normal3f(-normal.x(), -normal.y(), -normal.z()); + case UNITSPHEREOCTANT_001: + return Normal3f(normal.x(), -normal.y(), -normal.z()); + case UNITSPHEREOCTANT_010: + return Normal3f(-normal.x(), normal.y(), -normal.z()); + case UNITSPHEREOCTANT_011: + return Normal3f(normal.x(), normal.y(), -normal.z()); + case UNITSPHEREOCTANT_100: + return Normal3f(-normal.x(), -normal.y(), normal.z()); + case UNITSPHEREOCTANT_101: + return Normal3f(normal.x(), -normal.y(), normal.z()); + case UNITSPHEREOCTANT_110: + return Normal3f(-normal.x(), normal.y(), normal.z()); + case UNITSPHEREOCTANT_111: + return Normal3f(normal.x(), normal.y(), normal.z()); + } + return Normal3f(); +} + +/// \brief Reverses the effect of normal3f_fold_octant() on \p normal with \p octant. +/// \p normal must have been obtained with normal3f_fold_octant(). +/// \p octant must have been obtained with normal3f_classify_octant(). +inline Normal3f normal3f_unfold_octant(const Normal3f& normal, UnitSphereOctant octant) +{ + return normal3f_fold_octant(normal, octant); +} + +enum UnitSphereSextant +{ + UNITSPHERESEXTANT_XYZ = 0, + UNITSPHERESEXTANT_XZY = 1, + UNITSPHERESEXTANT_YXZ = 2, + UNITSPHERESEXTANT_YZX = 3, + UNITSPHERESEXTANT_ZXY = 4, + UNITSPHERESEXTANT_ZYX = 5, +}; + +/// \brief Returns the sextant for \p normal indicating how to sort its components so that x > y > z. +/// All components of \p normal must be positive. +/// \p normal must be normalised. +inline UnitSphereSextant normal3f_classify_sextant(const Normal3f& normal) +{ + return + normal.x() >= normal.y() + ? normal.x() >= normal.z() + ? normal.y() >= normal.z() + ? UNITSPHERESEXTANT_XYZ + : UNITSPHERESEXTANT_XZY + : UNITSPHERESEXTANT_ZXY + : normal.y() >= normal.z() + ? normal.x() >= normal.z() + ? UNITSPHERESEXTANT_YXZ + : UNITSPHERESEXTANT_YZX + : UNITSPHERESEXTANT_ZYX; +} + +/// \brief Returns \p normal with its components sorted so that x > y > z based on \p sextant. +/// All components of \p normal must be positive. +/// \p normal must be normalised. +inline Normal3f normal3f_fold_sextant(const Normal3f& normal, UnitSphereSextant sextant) +{ + switch(sextant) + { + case UNITSPHERESEXTANT_XYZ: + return Normal3f(normal.x(), normal.y(), normal.z()); + case UNITSPHERESEXTANT_XZY: + return Normal3f(normal.x(), normal.z(), normal.y()); + case UNITSPHERESEXTANT_YXZ: + return Normal3f(normal.y(), normal.x(), normal.z()); + case UNITSPHERESEXTANT_YZX: + return Normal3f(normal.y(), normal.z(), normal.x()); + case UNITSPHERESEXTANT_ZXY: + return Normal3f(normal.z(), normal.x(), normal.y()); + case UNITSPHERESEXTANT_ZYX: + return Normal3f(normal.z(), normal.y(), normal.x()); + } + return Normal3f(); +} + +/// \brief Reverses the effect of normal3f_fold_sextant() on \p normal with \p sextant. +/// \p normal must have been obtained with normal3f_fold_sextant(). +/// \p sextant must have been obtained with normal3f_classify_sextant(). +inline Normal3f normal3f_unfold_sextant(const Normal3f& normal, UnitSphereSextant sextant) +{ + return normal3f_fold_sextant(normal, sextant); +} + +const std::size_t c_quantise_normal = 1 << 6; + +/// \brief All the components of \p folded must be positive and sorted so that x > y > z. +inline Normal3f normal3f_folded_quantised(const Normal3f& folded) +{ + // compress + double scale = static_cast(c_quantise_normal) / (folded.x() + folded.y() + folded.z()); + unsigned int zbits = static_cast(folded.z() * scale); + unsigned int ybits = static_cast(folded.y() * scale); + + // decompress + return normal3f_normalised(Normal3f( + static_cast(c_quantise_normal - zbits - ybits), + static_cast(ybits), + static_cast(zbits) + )); +} + +/// \brief Returns \p normal quantised by compressing and then decompressing its representation. +inline Normal3f normal3f_quantised_custom(const Normal3f& normal) +{ + UnitSphereOctant octant = normal3f_classify_octant(normal); + Normal3f folded = normal3f_fold_octant(normal, octant); + UnitSphereSextant sextant = normal3f_classify_sextant(folded); + folded = normal3f_fold_sextant(folded, sextant); + return normal3f_unfold_octant(normal3f_unfold_sextant(normal3f_folded_quantised(folded), sextant), octant); +} + + + +struct spherical_t +{ + double longditude, latitude; + + spherical_t(double _longditude, double _latitude) + : longditude(_longditude), latitude(_latitude) + { + } +}; + +/* +{ + theta = 2pi * U; + phi = acos((2 * V) - 1); + + U = theta / 2pi; + V = (cos(phi) + 1) / 2; +} + +longitude = atan(y / x); +latitude = acos(z); +*/ +struct uniformspherical_t +{ + double U, V; + + uniformspherical_t(double U_, double V_) + : U(U_), V(V_) + { + } +}; + + +inline spherical_t spherical_from_normal3f(const Normal3f& normal) +{ + return spherical_t(normal.x() == 0 ? c_pi / 2 : normal.x() > 0 ? atan(normal.y() / normal.x()) : atan(normal.y() / normal.x()) + c_pi, acos(normal.z())); +} + +inline Normal3f normal3f_from_spherical(const spherical_t& spherical) +{ + return Normal3f( + static_cast(cos(spherical.longditude) * sin(spherical.latitude)), + static_cast(sin(spherical.longditude) * sin(spherical.latitude)), + static_cast(cos(spherical.latitude)) + ); +} + +inline uniformspherical_t uniformspherical_from_spherical(const spherical_t& spherical) +{ + return uniformspherical_t(spherical.longditude * c_inv_2pi, (cos(spherical.latitude) + 1) * 0.5); +} + +inline spherical_t spherical_from_uniformspherical(const uniformspherical_t& uniformspherical) +{ + return spherical_t(c_2pi * uniformspherical.U, acos((2 * uniformspherical.V) - 1)); +} + +inline uniformspherical_t uniformspherical_from_normal3f(const Normal3f& normal) +{ + return uniformspherical_from_spherical(spherical_from_normal3f(normal)); + //return uniformspherical_t(atan2(normal.y / normal.x) * c_inv_2pi, (normal.z + 1) * 0.5); +} + +inline Normal3f normal3f_from_uniformspherical(const uniformspherical_t& uniformspherical) +{ + return normal3f_from_spherical(spherical_from_uniformspherical(uniformspherical)); +} + +/// \brief Returns a single-precision \p component quantised to \p precision. +inline float float_quantise(float component, float precision) +{ + return float_snapped(component, precision); +} + +/// \brief Returns a double-precision \p component quantised to \p precision. +inline double double_quantise(double component, double precision) +{ + return float_snapped(component, precision); +} + +inline spherical_t spherical_quantised(const spherical_t& spherical, float snap) +{ + return spherical_t(double_quantise(spherical.longditude, snap), double_quantise(spherical.latitude, snap)); +} + +inline uniformspherical_t uniformspherical_quantised(const uniformspherical_t& uniformspherical, float snap) +{ + return uniformspherical_t(double_quantise(uniformspherical.U, snap), double_quantise(uniformspherical.V, snap)); +} + +/// \brief Returns a \p vertex quantised to \p precision. +inline Vertex3f vertex3f_quantised(const Vertex3f& vertex, float precision) +{ + return Vertex3f(float_quantise(vertex.x(), precision), float_quantise(vertex.y(), precision), float_quantise(vertex.z(), precision)); +} + +/// \brief Returns a \p normal quantised to a fixed precision. +inline Normal3f normal3f_quantised(const Normal3f& normal) +{ + return normal3f_quantised_custom(normal); + //return normal3f_from_spherical(spherical_quantised(spherical_from_normal3f(normal), snap)); + //return normal3f_from_uniformspherical(uniformspherical_quantised(uniformspherical_from_normal3f(normal), snap)); + // float_quantise(normal.x, snap), float_quantise(normal.y, snap), float_quantise(normal.y, snap)); +} + +/// \brief Returns a \p texcoord quantised to \p precision. +inline TexCoord2f texcoord2f_quantised(const TexCoord2f& texcoord, float precision) +{ + return TexCoord2f(float_quantise(texcoord.s(), precision), float_quantise(texcoord.t(), precision)); +} + +/// \brief Standard vertex type for lines and points. +struct PointVertex +{ + Colour4b colour; + Vertex3f vertex; + + PointVertex() + { + } + PointVertex(Vertex3f _vertex) + : colour(Colour4b(255, 255, 255, 255)), vertex(_vertex) + { + } + PointVertex(Vertex3f _vertex, Colour4b _colour) + : colour(_colour), vertex(_vertex) + { + } +}; + +inline bool operator<(const PointVertex& self, const PointVertex& other) +{ + if(self.vertex != other.vertex) + { + return self.vertex < other.vertex; + } + if(self.colour != other.colour) + { + return self.colour < other.colour; + } + return false; +} + +inline bool operator==(const PointVertex& self, const PointVertex& other) +{ + return self.colour == other.colour && self.vertex == other.vertex; +} + +inline bool operator!=(const PointVertex& self, const PointVertex& other) +{ + return !operator==(self, other); +} + +/// \brief Standard vertex type for lit/textured meshes. +struct ArbitraryMeshVertex +{ + TexCoord2f texcoord; + Normal3f normal; + Vertex3f vertex; + Normal3f tangent; + Normal3f bitangent; + + ArbitraryMeshVertex() : tangent(0, 0, 0), bitangent(0, 0, 0) + { + } + ArbitraryMeshVertex(Vertex3f _vertex, Normal3f _normal, TexCoord2f _texcoord) + : texcoord(_texcoord), normal(_normal), vertex(_vertex), tangent(0, 0, 0), bitangent(0, 0, 0) + { + } +}; + +inline bool operator<(const ArbitraryMeshVertex& self, const ArbitraryMeshVertex& other) +{ + if(self.texcoord != other.texcoord) + { + return self.texcoord < other.texcoord; + } + if(self.normal != other.normal) + { + return self.normal < other.normal; + } + if(self.vertex != other.vertex) + { + return self.vertex < other.vertex; + } + return false; +} + +inline bool operator==(const ArbitraryMeshVertex& self, const ArbitraryMeshVertex& other) +{ + return self.texcoord == other.texcoord && self.normal == other.normal && self.vertex == other.vertex; +} + +inline bool operator!=(const ArbitraryMeshVertex& self, const ArbitraryMeshVertex& other) +{ + return !operator==(self, other); +} + +const float c_quantise_vertex = 1.f / static_cast(1 << 3); + +/// \brief Returns \p v with vertex quantised to a fixed precision. +inline PointVertex pointvertex_quantised(const PointVertex& v) +{ + return PointVertex(vertex3f_quantised(v.vertex, c_quantise_vertex), v.colour); +} + +const float c_quantise_texcoord = 1.f / static_cast(1 << 8); + +/// \brief Returns \p v with vertex, normal and texcoord quantised to a fixed precision. +inline ArbitraryMeshVertex arbitrarymeshvertex_quantised(const ArbitraryMeshVertex& v) +{ + return ArbitraryMeshVertex(vertex3f_quantised(v.vertex, c_quantise_vertex), normal3f_quantised(v.normal), texcoord2f_quantised(v.texcoord, c_quantise_texcoord)); +} + + +/// \brief Sets up the OpenGL colour and vertex arrays for \p array. +inline void pointvertex_gl_array(const PointVertex* array) +{ + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &array->colour); + glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &array->vertex); +} + +class RenderablePointArray : public OpenGLRenderable +{ + const Array& m_array; + const GLenum m_mode; +public: + RenderablePointArray(const Array& array, GLenum mode) + : m_array(array), m_mode(mode) + { + } + void render(RenderStateFlags state) const + { +#define NV_DRIVER_BUG 1 +#if NV_DRIVER_BUG + glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); + glVertexPointer(3, GL_FLOAT, 0, 0); + glDrawArrays(GL_TRIANGLE_FAN, 0, 0); +#endif + pointvertex_gl_array(m_array.data()); + glDrawArrays(m_mode, 0, GLsizei(m_array.size())); + } +}; + +class RenderablePointVector : public OpenGLRenderable +{ + std::vector m_vector; + const GLenum m_mode; +public: + RenderablePointVector(GLenum mode) + : m_mode(mode) + { + } + + void render(RenderStateFlags state) const + { + pointvertex_gl_array(&m_vector.front()); + glDrawArrays(m_mode, 0, GLsizei(m_vector.size())); + } + + std::size_t size() const + { + return m_vector.size(); + } + bool empty() const + { + return m_vector.empty(); + } + void clear() + { + m_vector.clear(); + } + void reserve(std::size_t size) + { + m_vector.reserve(size); + } + void push_back(const PointVertex& point) + { + m_vector.push_back(point); + } +}; + + +class RenderableVertexBuffer : public OpenGLRenderable +{ + const GLenum m_mode; + const VertexBuffer& m_vertices; +public: + RenderableVertexBuffer(GLenum mode, const VertexBuffer& vertices) + : m_mode(mode), m_vertices(vertices) + { + } + + void render(RenderStateFlags state) const + { + pointvertex_gl_array(m_vertices.data()); + glDrawArrays(m_mode, 0, m_vertices.size()); + } +}; + +class RenderableIndexBuffer : public OpenGLRenderable +{ + const GLenum m_mode; + const IndexBuffer& m_indices; + const VertexBuffer& m_vertices; +public: + RenderableIndexBuffer(GLenum mode, const IndexBuffer& indices, const VertexBuffer& vertices) + : m_mode(mode), m_indices(indices), m_vertices(vertices) + { + } + + void render(RenderStateFlags state) const + { +#if 1 + pointvertex_gl_array(m_vertices.data()); + glDrawElements(m_mode, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data()); +#else + glBegin(m_mode); + if(state & RENDER_COLOURARRAY != 0) + { + for(std::size_t i = 0; i < m_indices.size(); ++i) + { + glColor4ubv(&m_vertices[m_indices[i]].colour.r); + glVertex3fv(&m_vertices[m_indices[i]].vertex.x); + } + } + else + { + for(std::size_t i = 0; i < m_indices.size(); ++i) + { + glVertex3fv(&m_vertices[m_indices[i]].vertex.x); + } + } + glEnd(); +#endif + } +}; + + +class RemapXYZ +{ +public: + static void set(Vertex3f& vertex, float x, float y, float z) + { + vertex.x() = x; + vertex.y() = y; + vertex.z() = z; + } +}; + +class RemapYZX +{ +public: + static void set(Vertex3f& vertex, float x, float y, float z) + { + vertex.x() = z; + vertex.y() = x; + vertex.z() = y; + } +}; + +class RemapZXY +{ +public: + static void set(Vertex3f& vertex, float x, float y, float z) + { + vertex.x() = y; + vertex.y() = z; + vertex.z() = x; + } +}; + +template +inline void draw_circle(const std::size_t segments, const float radius, PointVertex* vertices, remap_policy remap) +{ + const double increment = c_pi / double(segments << 2); + + std::size_t count = 0; + float x = radius; + float y = 0; + while(count < segments) + { + PointVertex* i = vertices + count; + PointVertex* j = vertices + ((segments << 1) - (count + 1)); + + PointVertex* k = i + (segments << 1); + PointVertex* l = j + (segments << 1); + + PointVertex* m = i + (segments << 2); + PointVertex* n = j + (segments << 2); + PointVertex* o = k + (segments << 2); + PointVertex* p = l + (segments << 2); + + remap_policy::set(i->vertex, x,-y, 0); + remap_policy::set(k->vertex,-y,-x, 0); + remap_policy::set(m->vertex,-x, y, 0); + remap_policy::set(o->vertex, y, x, 0); + + ++count; + + { + const double theta = increment * count; + x = static_cast(radius * cos(theta)); + y = static_cast(radius * sin(theta)); + } + + remap_policy::set(j->vertex, y,-x, 0); + remap_policy::set(l->vertex,-x,-y, 0); + remap_policy::set(n->vertex,-y, x, 0); + remap_policy::set(p->vertex, x, y, 0); + } +} + +#if 0 +class PointVertexArrayIterator +{ + PointVertex* m_point; +public: + PointVertexArrayIterator(PointVertex* point) + : m_point(point) + { + } + PointVertexArrayIterator& operator++() + { + ++m_point; + return *this; + } + PointVertexArrayIterator operator++(int) + { + PointVertexArrayIterator tmp(*this); + ++m_point; + return tmp; + } + Vertex3f& operator*() + { + return m_point.vertex; + } + Vertex3f* operator->() + { + return &(operator*()); + } +} + +template 0.000001f) + { + s.x() = -cross.y() / cross.x(); + } + + if(fabs(cross.x()) > 0.000001f) + { + t.x() = -cross.z() / cross.x(); + } + } + + { + Vector3 cross( + vector3_cross( + vector3_subtracted( + Vector3(b.vertex.y(), b.texcoord.s(), b.texcoord.t()), + Vector3(a.vertex.y(), a.texcoord.s(), a.texcoord.t()) + ), + vector3_subtracted( + Vector3(c.vertex.y(), c.texcoord.s(), c.texcoord.t()), + Vector3(a.vertex.y(), a.texcoord.s(), a.texcoord.t()) + ) + ) + ); + + if(fabs(cross.x()) > 0.000001f) + { + s.y() = -cross.y() / cross.x(); + } + + if(fabs(cross.x()) > 0.000001f) + { + t.y() = -cross.z() / cross.x(); + } + } + + { + Vector3 cross( + vector3_cross( + vector3_subtracted( + Vector3(b.vertex.z(), b.texcoord.s(), b.texcoord.t()), + Vector3(a.vertex.z(), a.texcoord.s(), a.texcoord.t()) + ), + vector3_subtracted( + Vector3(c.vertex.z(), c.texcoord.s(), c.texcoord.t()), + Vector3(a.vertex.z(), a.texcoord.s(), a.texcoord.t()) + ) + ) + ); + + if(fabs(cross.x()) > 0.000001f) + { + s.z() = -cross.y() / cross.x(); + } + + if(fabs(cross.x()) > 0.000001f) + { + t.z() = -cross.z() / cross.x(); + } + } +} + +inline void ArbitraryMeshTriangle_sumTangents(ArbitraryMeshVertex& a, ArbitraryMeshVertex& b, ArbitraryMeshVertex& c) +{ + Vector3 s, t; + + ArbitraryMeshTriangle_calcTangents(a, b, c, s, t); + + reinterpret_cast(a.tangent) += s; + reinterpret_cast(b.tangent) += s; + reinterpret_cast(c.tangent) += s; + + reinterpret_cast(a.bitangent) += t; + reinterpret_cast(b.bitangent) += t; + reinterpret_cast(c.bitangent) += t; +} + + +#endif