11#ifndef JAU_GAMP_GRAPH_TESS_GL_GLUTESSELATOR_HPP_
12#define JAU_GAMP_GRAPH_TESS_GL_GLUTESSELATOR_HPP_
17#include <GL/glutess2.h>
71 r.append(
jau::format_string_n(256,
"%sSegment[%zu]: %s\n", pre.c_str(), i++, s.toString().c_str()) );
77 std::string_view type_s;
79 case GL_TRIANGLE_STRIP:
80 type_s =
"triangle_strip";
break;
82 type_s =
"triangle_fan";
break;
84 type_s =
"triangles";
break;
88 return std::string(
"Segment[").append(type_s)
89 .append(
", 1st ").append(std::to_string(
first))
90 .append(
", count ").append(std::to_string(
count)).append(
"]");
97 std::vector<std::shared_ptr<Vertex>> m_vcache;
99 uint32_t m_nextSegment = 0;
100 uint32_t m_curSegment = 0;
105 : m_array(array), m_flags(flags)
123 bool empty() const noexcept {
return m_segments.empty(); }
127 constexpr const std::vector<Segment>&
segments() const noexcept {
return m_segments; }
131 static void cbBeginData( GLenum
type,
void *polygonData ) {
133 os->m_curSegment =
os->m_nextSegment++;
135 os->m_segments.push_back(s);
136 if(
os->verbose() ) {
140 static void cbVertexData(
void *
data,
void *polygonData ) {
143 if(
os->verbose() ) {
146 os->m_array.put3f(v->
coord());
147 if( os->useNormal() ) {
148 os->m_array.put3f(os->m_normal);
151 static void cbEndData(
void *polygonData ) {
153 Segment& s = os->m_segments.at(os->m_segments.size()-1);
155 if( os->verbose() ) {
156 jau::INFO_PRINT(
"GLUtess end %02d, %s", os->m_curSegment, s.toString().c_str());
159 static void cbErrorData( GLenum errnum,
void *polygonData ) {
161 if( os->verbose() ) {
163 jau::INFO_PRINT(
"GLUtess error %02d, errnum 0x%X", os->m_curSegment, errnum);
166 static void cbCombineData( GLUTessFloat coords[3],
void *data[4],
167 GLfloat weight[4],
void **outData,
168 void *polygonData ) {
170 if( os->verbose() ) {
171 jau::INFO_PRINT(
"GLUtess combine %02d, %f, %f, %f", os->m_curSegment, coords[0], coords[1], coords[2]);
174 std::shared_ptr<Vertex> v = std::make_shared<Vertex>((
float)coords[0], (
float)coords[1], (
float)coords[2],
true);
175 os->m_vcache.push_back(v);
176 for (
int i = 0; i < 4; ++i) {
177 Vertex* s = (Vertex*) data[i];
179 for (
int j = 0;
j < 3; ++
j) {
181 v->texCoord()[
j] += (float)( weight[i] * s->
texCoord()[j] );
184 outData[0] = v.get();
194 size_t outlineCount = 0;
195 if( odirty ||
empty() ) {
197 GLUtesselator*
tess = gluNewTess();
198 if( !
tess ) {
return m_segments; }
199 m_normal = outlines.
normal();
203 gluTessNormal(
tess, m_normal.x, m_normal.y, m_normal.z);
204 gluTessCallback(
tess, GLU_TESS_BEGIN_DATA, (_GLUfuncptr)cbBeginData);
205 gluTessCallback(
tess, GLU_TESS_END_DATA, (_GLUfuncptr)cbEndData);
206 gluTessCallback(
tess, GLU_TESS_VERTEX_DATA, (_GLUfuncptr)cbVertexData);
207 gluTessCallback(
tess, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)cbCombineData);
208 gluTessCallback(
tess, GLU_TESS_ERROR_DATA, (_GLUfuncptr)cbErrorData);
210 gluTessBeginPolygon(
tess,
this);
213 jau::INFO_PRINT(
"GLUtess: outline %zu: Vertices %zu, Winding %s", outlineCount, o.vertexCount(),
to_string(o.getWinding()).c_str());
216 gluTessBeginContour(
tess);
217 if constexpr (
sizeof(GLfloat) ==
sizeof(GLUTessFloat) ) {
218 for(
const Vertex& v : o.vertices()) {
219 gluTessVertex(
tess,
const_cast<GLfloat*
>(v.coord().cbegin()), (
void*)&v);
222 for(
const Vertex& v : o.vertices()) {
223 GLUTessFloat coords[] = { v.coord().x, v.coord().y, v.coord().z };
224 gluTessVertex(
tess, coords, (
void*)&v);
227 gluTessEndContour(
tess);
229 gluTessEndPolygon(
tess);
A Generic shape objects which is defined by a list of Outlines.
const OutlineList & outlines() const noexcept
constexpr bool verticesDirty() const noexcept
constexpr const Vec3f & normal() const noexcept
Normal vector, optionally used by tesselator to add (interleaved) normals.
constexpr bool trianglesDirty() const noexcept
Define a single continuous stroke by control vertices.
constexpr const Vec3f & texCoord() const noexcept
constexpr const Vec3f & coord() const noexcept
GLUtilTesselator transform OutlineShapes to triangles using glutess2.
GLUtilTesselator(int flags, GLFloatArrayDataServer &array) noexcept
static constexpr int FLAG_TEXTURE
void clear()
Clears all internal data, not passed array or indices.
constexpr bool verbose() const noexcept
std::vector< Segment > SegmentList
bool empty() const noexcept
Returns true if segments() is empty.
static SegmentList tesselate(int flags, GLFloatArrayDataServer &array, OutlineShape &outlines)
jau::nsize_t elementCount() const noexcept
constexpr bool useColor() const noexcept
const SegmentList & tesselate(OutlineShape &outlines)
constexpr const std::vector< Segment > & segments() const noexcept
constexpr bool useTexture() const noexcept
static constexpr int FLAG_NORMAL
static constexpr int FLAG_COLOR
static constexpr int FLAG_VERBOSE
constexpr bool useNormal() const noexcept
std::string toString() const noexcept
GLArrayDataServer< float > GLFloatArrayDataServer
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...
std::string to_string(const math_error_t v) noexcept
Returns std::string representation of math_error_t.
constexpr std::string format_string_n(const std::size_t maxStrLen, const std::string_view &format, const Args &...args)
Safely returns a (potentially truncated) string according to snprintf() formatting rules and variable...
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2024 Gothel Software e.K.
void INFO_PRINT(const char *format,...) noexcept
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
GLsizei count
number of elements in data-sink for this segment
static std::string toString(const std::string &pre, const SegmentList &segments) noexcept
GLint first
index of first element in data-sink for this segment
GLenum type
render implementation specific triangle type, i.e. triangle-strip, -fan or just triangles.
std::string toString() const