87 constexpr bool usesNormal() const noexcept {
return m_props.m_hasLight0 || m_props.m_hasNormalChannel; }
104 static constexpr std::string_view
source_dir =
"impl/graph/glsl";
105 static constexpr std::string_view
bin_dir =
"impl/graph/glsl/bin";
110 m_pmvMat(
"gcu_PMVMatrix", mat_req),
111 m_light0Pos(
"gcu_Light0Pos", lightPos),
112 m_staticColor(
"gcu_StaticColor",
Vec4f(0, 0, 0, 1)),
115 m_st.manage(m_pmvMat);
116 m_st.manage(m_light0Pos);
117 m_st.manage(m_staticColor);
120 constexpr bool initialized() const noexcept {
return m_initialized; }
126 std::string vertexShaderName, fragmentShaderName;
128 if( m_props.m_isTwoPass ) {
129 vertexShaderName.append(
"-pass").append(m_props.m_pass1 ?
"1":
"2");
131 vertexShaderName.append(
"-single");
137 if( !rsVp || !rsFp ) {
144 if( posVp == std::string::npos || posFp == std::string::npos ) {
156 if( m_props.m_hasDiscard ) {
160 if( m_props.m_hasFrustumClipping ) {
169 if( m_props.m_hasLight0 ) {
173 if( m_props.m_hasColorChannel ) {
177 if( m_props.m_hasColorTexture ) {
187 if( posVp == std::string::npos ) {
195 if( posFp == std::string::npos ) {
200 if( posFp == std::string::npos ) {
205 if( posFp == std::string::npos ) {
209 if( m_props.m_hasColorTexture || m_props.m_hasFrustumClipping ) {
211 if( posFp == std::string::npos ) {
223 std::string passS = m_props.m_pass1 ?
"-pass1-" :
"-pass2-";
226 jau_fprintf_td(stderr,
"RegionRenderer.createShaderProgram.1: segment %s", shaderSegment);
229 if( posFp == std::string::npos ) {
234 if( posFp == std::string::npos ) {
239 if( m_props.m_hasColorTexture ) {
245 if( !sp0->
add(
gl, rsVp,
true) || !sp0->
add(
gl, rsFp,
true) ) {
250 m_st.attachShaderProgram(
gl, sp0,
true);
253 pmv.getP().loadIdentity();
254 pmv.getMv().loadIdentity();
256 m_st.send(
gl, m_pmvMat);
257 m_st.send(
gl, m_light0Pos);
258 m_st.send(
gl, m_staticColor);
260 m_initialized = sp0->
inUse();
261 if( !m_initialized ) {
265 return m_initialized;
269 m_st.destroyShaderProgram(
gl);
273 m_st.useProgram(
gl, on);
277 m_st.send(
gl, m_staticColor);
280 m_st.send(
gl, m_pmvMat);
283 m_st.send(
gl, m_pmvMat);
284 m_st.send(
gl, m_staticColor);
288 const Vec4f&
color() const noexcept {
return m_staticColor.vec4f(); }
301 int m_num_vertices, m_num_indices;
305 : m_renderer(renderer), m_st(st),
307 m_array(
GLFloatArrayDataServer::createGLSLInterleaved(m_renderer.arrayCompsPerElement(), false, 256, GL_STATIC_DRAW)),
309 m_num_vertices(0), m_num_indices(0)
311 m_array->addGLSLSubArray(
"gca_Vertex", 3, GL_ARRAY_BUFFER);
312 m_array->addGLSLSubArray(
"gca_CurveParam", 3, GL_ARRAY_BUFFER);
313 if( m_renderer.usesNormal() ) {
314 m_array->addGLSLSubArray(
"gca_Normal", 3, GL_ARRAY_BUFFER);
316 m_st.manage(m_array);
320 constexpr bool initialized() const noexcept {
return m_initialized; }
323 m_st.destroyAllData(
gl);
325 m_indices->destroy(
gl);
331 if( !m_initialized ) {
334 m_array->seal(
gl, seal_);
335 m_indices->seal(
gl, seal_);
336 m_array->enableBuffer(
gl,
false);
337 m_indices->enableBuffer(
gl,
false);
341 void pushVertex(
const Vertex& v,
const Vec3f& normal) {
343 m_array->put3f(v.
coord());
346 m_array->put3f(normal);
350 void pushIndices(uint32_t i, uint32_t j, uint32_t k) {
352 m_indices->putN(i, j, k);
355 void pushNewVerticesIdx(
const Vertex& vertIn1,
const Vertex& vertIn2,
const Vertex& vertIn3,
const Vec3f& normal) {
356 pushIndices(m_num_vertices, m_num_vertices+1, m_num_vertices+2);
357 pushVertex(vertIn1, normal);
358 pushVertex(vertIn2, normal);
359 pushVertex(vertIn3, normal);
364 if( !m_initialized ) {
368 jau_fprintf_td(stderr,
"add.0 num[vertices %d, indices %d]", m_num_vertices, m_num_indices);
370 jau_fprintf_td(stderr,
"add.0 indices: %s", m_indices->toString());
380 m_array->growIfNeeded(verticeCount * m_array->compsPerElem());
381 m_indices->growIfNeeded(indexCount * m_indices->compsPerElem());
383 uint32_t idxOffset = m_num_vertices;
384 if( vertsIn.
size() >= 3 ) {
388 for(
const Vertex& v : vertsIn) {
389 pushVertex(v, shape.
normal());
391 constexpr static uint32_t max_index = std::numeric_limits<uint32_t>::max() /
sizeof(uint32_t);
398 uint32_t tv0Idx = triInVertices[0].id();
399 if ( max_index - idxOffset > tv0Idx ) {
401 pushIndices(tv0Idx+idxOffset,
402 triInVertices[1].
id()+idxOffset,
403 triInVertices[2].
id()+idxOffset);
406 pushNewVerticesIdx(triInVertices[0], triInVertices[1], triInVertices[2], shape.
normal());
411 jau_fprintf_td(stderr,
"add.x num[vertices %d, indices %d]", m_num_vertices, m_num_indices);
413 jau_fprintf_td(stderr,
"add.x indices: %s", m_indices->toString());
418 if( !m_initialized ) {
421 m_renderer.useProgram(
gl,
true);
423 m_array->enableBuffer(
gl,
true);
424 m_indices->bindBuffer(
gl,
true);
426 ::glEnable(GL_BLEND);
427 ::glBlendEquation(GL_FUNC_ADD);
428 ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
430 ::glDrawElements(GL_TRIANGLES, m_indices->elemCount() * m_indices->compsPerElem(), GL_UNSIGNED_INT,
nullptr);
432 m_indices->bindBuffer(
gl,
false);
433 m_array->enableBuffer(
gl,
false);
450 float m_zOffset = 0.0f;
457 bool iMatIdent =
true;
458 bool iMatDirty =
false;
460 struct Private{
explicit Private() =
default; };
464 : m_st(st), m_oshape(3, 16),
465 m_renderer(renderer), m_region(m_renderer, m_st)
471 return std::make_shared<Shape>(Private(), st, renderer);
475 m_region.destroy(
gl);
481 constexpr const float&
zOffset() const noexcept {
return m_zOffset; }
482 constexpr float&
zOffset() noexcept { iMatDirty=
true;
return m_zOffset; }
490 constexpr const Vec3f&
scale() const noexcept {
return m_scale; }
491 constexpr Vec3f&
scale() noexcept { iMatDirty=
true;
return m_scale; }
500 m_region.addOutlineShape(m_oshape);
501 m_region.seal(
gl,
true);
509 m_renderer.setColor(m_color);
510 m_renderer.updateAll(
gl);
531 void applyMatToMv(
PMVMat4f& pmvMat)
noexcept {
539 void updateMat() noexcept {
540 bool hasPos = !m_position.is_zero();
542 bool hasRotate = !m_rotation.isIdentity();
543 bool hasRotPivot =
false;
544 const Vec3f& ctr = m_oshape.bounds().center();
545 bool sameScaleRotatePivot = hasScale && hasRotate && ( !hasRotPivot || m_rotPivot == ctr );
547 if( sameScaleRotatePivot ) {
549 iMat.setToTranslation(m_position);
551 iMat.translate(
Vec3f(ctr).mul(m_scale));
552 iMat.rotate(m_rotation);
554 iMat.translate(-ctr);
555 }
else if( hasRotate || hasScale ) {
557 iMat.setToTranslation(m_position);
561 iMat.translate(
Vec3f(m_rotPivot).mul(m_scale));
562 iMat.rotate(m_rotation);
563 iMat.translate(
Vec3f(-m_rotPivot).mul(m_scale));
566 iMat.translate(
Vec3f(ctr).mul(m_scale));
567 iMat.rotate(m_rotation);
568 iMat.translate(
Vec3f(-ctr).mul(m_scale));
573 iMat.translate(
Vec3f(ctr).mul(m_scale));
575 iMat.translate(
Vec3f(-ctr).mul(m_scale));
577 }
else if( hasPos ) {
579 iMat.setToTranslation(m_position);
591 constexpr static float zNear= 1.0f;
592 constexpr static float zFar =100.0f;
597 bool m_animating =
true;
598 bool m_oneframe =
false;
601 std::vector<ShapeRef> m_shapes;
607 m_initialized(false),
617 void setOneFrame() noexcept { m_animating=
false; m_oneframe=
true; }
625 if( !m_renderer.init(
gl, when) ) {
631 const float lineWidth = 1/2.5f;
632 const float dz = 0.001f;
635 const float width = 1.5f;
636 const float height = 1.5f;
638 float lwh = lineWidth/2.0f;
640 float twh = width/2.0f;
641 float thh = height/2.0f;
643 float ctrX = 0, ctrY = 0, ctrZ = dz;
645 m_shapes.push_back(frontShape);
648 oshape.
moveTo(ctrX+twh, ctrY-lwh, ctrZ);
649 oshape.
lineTo(ctrX+twh, ctrY+lwh, ctrZ);
650 oshape.
lineTo(ctrX+lwh, ctrY+lwh, ctrZ);
651 oshape.
lineTo(ctrX+lwh, ctrY+thh, ctrZ);
652 oshape.
lineTo(ctrX-lwh, ctrY+thh, ctrZ);
653 oshape.
lineTo(ctrX-lwh, ctrY+lwh, ctrZ);
654 oshape.
lineTo(ctrX-twh, ctrY+lwh, ctrZ);
655 oshape.
lineTo(ctrX-twh, ctrY-lwh, ctrZ);
656 oshape.
lineTo(ctrX-lwh, ctrY-lwh, ctrZ);
657 oshape.
lineTo(ctrX-lwh, ctrY-thh, ctrZ);
658 oshape.
lineTo(ctrX+lwh, ctrY-thh, ctrZ);
659 oshape.
lineTo(ctrX+lwh, ctrY-lwh, ctrZ);
660 oshape.
lineTo(ctrX+twh, ctrY-lwh, ctrZ);
670 m_shapes.push_back(backShape);
679 m_shapes.push_back(frontShape);
682 oshape.
moveTo(0.0f,-10.0f, 0);
683 oshape.
lineTo(15.0f,-10.0f, 0);
684 oshape.
quadTo(10.0f,5.0f,0, 15.0f,10.0f,0);
685 oshape.
cubicTo(6.0f,15.0f,0, 5.0f,8.0f,0, 0.0f,10.0f,0);
688 oshape.
moveTo(5.0f,-5.0f,0);
689 oshape.
quadTo(10.0f,-5.0f,0, 10.0f,0.0f,0);
690 oshape.
quadTo(5.0f,0.0f,0, 5.0f,-5.0f,0);
697 jau_fprintf_td(stderr,
"Special.frontShape.10.winding_area: %s -> %s",
699 jau_fprintf_td(stderr,
"Special.frontShape.11.winding_area: %s -> %s",
706 frontShape->
scale().
x *= 0.1f;
707 frontShape->
scale().
y *= 0.1f;
710 m_shapes.push_back(backShape);
716 backShape->
scale().
x *= 0.1f;
717 backShape->
scale().
y *= 0.1f;
725 m_shapes.push_back(frontShape);
732 frontShape->
scale().
x *= 2.0f;
733 frontShape->
scale().
y *= 2.0f;
736 m_shapes.push_back(backShape);
743 backShape->
scale().
x *= 2.0f;
744 backShape->
scale().
y *= 2.0f;
748 m_shapes.push_back(frontShape);
755 frontShape->
scale().
x *= 2.0f;
756 frontShape->
scale().
y *= 2.0f;
759 m_shapes.push_back(backShape);
766 backShape->
scale().
x *= 2.0f;
767 backShape->
scale().
y *= 2.0f;
770 ::glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
771 ::glEnable(GL_DEPTH_TEST);
773 ::glDisable(GL_CULL_FACE);
775 m_initialized =
true;
776 if( !m_initialized ) {
781 return m_initialized;
790 m_renderer.destroy(
gl);
792 m_initialized =
false;
802 const float aspect = 1.0f;
803 const float fovy_deg=45.0f;
804 const float aspect2 = ( (float) m_viewport.width() / (
float) m_viewport.height() ) / aspect;
809 m_st.useProgram(
gl,
true);
815 if( !m_initialized ) {
819 ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
821 m_st.useProgram(
gl,
true);
825 constexpr double angle_per_sec = 30;
826 const float rad = (float) ( (when - m_tlast).to_double() * angle_per_sec );
843 std::string
toStringImpl() const noexcept
override {
return "GraphShapes01"; }
848 class MyKeyListener :
public KeyListener {
854 void keyPressed(KeyEvent& e,
const KeyboardTracker& kt)
override {
856 if( e.
keySym() == VKeyCode::VK_ESCAPE ) {
861 }
else if( e.
keySym() == VKeyCode::VK_PAUSE || e.
keySym() == VKeyCode::VK_P ) {
862 m_parent.animating() = !m_parent.animating();
863 }
else if( e.
keySym() == VKeyCode::VK_PERIOD ) {
864 m_parent.setOneFrame();
865 }
else if( e.
keySym() == VKeyCode::VK_W ) {
870 void keyReleased(KeyEvent& e,
const KeyboardTracker& kt)
override {
874 typedef std::shared_ptr<MyKeyListener> MyKeyListenerRef;
875 MyKeyListenerRef m_kl;
880 m_kl(
std::make_shared<MyKeyListener>(*this)) { }
895int main(
int argc,
char *argv[])
897 return launch(
"GraphShapes01.cpp",
901 std::make_shared<Example>(), argc, argv);
int launch(std::string_view sfile, GLLaunchProps props, const RenderListenerSRef &demo, int argc, char *argv[])
int main(int argc, char *argv[])
std::shared_ptr< Shape > ShapeRef
bool init(const WindowSRef &win, const jau::fraction_timespec &when) override
Called by the drawable immediately after the render context is initialized.
void dispose(const WindowSRef &win, const jau::fraction_timespec &when) override
Notifies the listener to perform the release of all renderer resources per context,...
static void addShapeToRegion(gamp::graph::OutlineShape &shape)
static void addShapeToRegion(gamp::graph::OutlineShape &shape)
constexpr bool initialized() const noexcept
void addOutlineShape(OutlineShape &shape)
jau::darray< uint32_t, glmemsize_t > u32buffer_t
GraphRegion(GraphRenderer &renderer, ShaderState &st)
void seal(GL &gl, bool seal_)
static constexpr std::string_view GLSL_USE_LIGHT0
ShaderState & st() noexcept
bool init(GL &gl, const jau::fraction_timespec &when)
static constexpr std::string_view GLSL_CONST_SAMPLE_COUNT
static constexpr std::string_view GLSL_USE_COLOR_CHANNEL
static constexpr std::string_view GLSL_USE_DISCARD
const PMVMat4f & pmv() const noexcept
static constexpr std::string_view GLSL_USE_FRUSTUM_CLIPPING
static constexpr std::string_view source_dir
static constexpr std::string_view GLSL_PARAM_COMMENT_END
constexpr GLsizei arrayCompsPerElement() const noexcept
const Vec4f & color() const noexcept
constexpr bool initialized() const noexcept
static constexpr std::string_view shader_basename
static constexpr std::string_view bin_dir
static constexpr std::string_view gcuTexture2D
static constexpr std::string_view GLSL_MAIN_BEGIN
static constexpr std::string_view GLSL_USE_COLOR_TEXTURE
static constexpr std::string_view GLSL_USE_NORMAL_CHANNEL
constexpr bool usesNormal() const noexcept
PMVMat4f & pmv() noexcept
static constexpr std::string_view colTexLookupFuncName
GraphRenderer(ShaderState &st)
void useProgram(GL &gl, bool on)
static constexpr std::string_view GLSL_PARAM_COMMENT_START
static constexpr std::string_view GLSL_DEF_SAMPLE_COUNT
void setColor(const Vec4f &c) noexcept
void setOneFrame() noexcept
bool animating() const noexcept
void display(const WindowSRef &win, const jau::fraction_timespec &when) override
Called by the drawable to initiate rendering by the client.
void reshape(const WindowSRef &win, const jau::math::Recti &viewport, const jau::fraction_timespec &when) override
Called by the drawable during the first repaint after the component has been resized.
std::string toStringImpl() const noexcept override
bool & animating() noexcept
Recti & viewport() noexcept
void dispose(const WindowSRef &win, const jau::fraction_timespec &when) override
Notifies the listener to perform the release of all renderer resources per context,...
bool init(const WindowSRef &win, const jau::fraction_timespec &when) override
Called by the drawable immediately after the render context is initialized.
const Recti & viewport() const noexcept
constexpr const float & zOffset() const noexcept
void setColor(const Vec4f &c) noexcept
constexpr const OutlineShape & outlineShape() const noexcept
constexpr Vec3f & position() noexcept
static ShapeRef createShared(ShaderState &st, GraphRenderer &renderer)
constexpr const Quat4f & rotation() const noexcept
Shape(Private, ShaderState &st, GraphRenderer &renderer)
constexpr OutlineShape & outlineShape() noexcept
constexpr const Vec3f & rotationPivot() const noexcept
constexpr float & zOffset() noexcept
constexpr const Vec3f & position() const noexcept
constexpr Vec3f & scale() noexcept
constexpr Vec3f & rotationPivot() noexcept
const Vec4f & color() const noexcept
constexpr const Vec3f & scale() const noexcept
constexpr Quat4f & rotation() noexcept
A Generic shape objects which is defined by a list of Outlines.
constexpr size_type addedVertexCount() const noexcept
Return the number of newly added vertices during getTriangles(VerticesState) while transforming the o...
const VertexList & getVertices()
Return list of concatenated vertices associated with all Outlines of this object.
void clearCache() noexcept
Clears cached triangulated data, i.e.
void cubicTo(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
Add a cubic Bézier curve segment, intersecting the last point and the second given point x3/y3 (P3).
const OutlineList & outlines() const noexcept
void quadTo(float x1, float y1, float z1, float x2, float y2, float z2)
Add a quadratic curve segment, intersecting the last point and the second given point x2/y2 (P2).
constexpr const Vec3f & normal() const noexcept
Normal vector, optionally used by tesselator to add (interleaved) normals.
void moveTo(float x, float y, float z)
Start a new position for the next line segment at given point x/y (P1).
void closePath()
Closes the current sub-path segment by drawing a straight line back to the coordinates of the last mo...
const TriangleRefList & getTriangles(VertexState destinationType=VertexState::quadratic_nurbs)
Triangulate the OutlineShape generating a list of triangles, while transformOutlines(VerticesState) b...
OutlineShape flipFace(float zoffset=0) const
Returns a copy of this instance with normal() pointing to the opposite direction and all outlines() v...
void lineTo(float x, float y, float z)
Add a line segment, intersecting the last point and the given point x/y (P1).
std::array< Vertex, 3 > trivert_t
constexpr const trivert_t & vertices() const noexcept
Returns array of 3 vertices, denominating the triangle.
constexpr const Vec3f & texCoord() const noexcept
constexpr const Vec3f & coord() const noexcept
Specifies a set of OpenGL capabilities.
constexpr GLCapabilities & setMultiSamplesCount(int v) noexcept
Defaults to 0, i.e.
static GLContext & downcast(RenderContext *rc)
Downcast dereferenced given RenderContext* to GLContext&, throws exception if signature doesn't match...
Specifies the OpenGL profile.
static constexpr std::string_view GLES2
The embedded OpenGL profile ES 2.x, with x >= 0.
size_t replaceInShaderSource(const string_t &oldName, const string_t &newName) noexcept
Replaces oldName with newName in all shader sources.
size_t defaultShaderCustomization(const GL &gl, bool preludeVersion=true, bool addDefaultPrecision=true, bool addDefaultDefines=true)
Default customization of this shader source code.
static ShaderCodeSRef create(GLenum type, size_t count, const source_list_t &sources)
size_t insertShaderSourceFile(size_t shaderIdx, size_t position, const string_t &path) noexcept
Adds shader source located in path, either relative to the location or absolute as-is at position in ...
size_t insertShaderSource(size_t shaderIdx, stringview_t tag, size_t fromIndex, stringview_t data) noexcept
Adds data after the line containing tag.
static ShaderProgramSRef create() noexcept
void destroy(GL &gl) noexcept
Detaches all shader codes and deletes the program.
bool add(const ShaderCodeSRef &shaderCode) noexcept
Adds a new shader to this program.
constexpr bool inUse() const noexcept
ShaderState allows to sharing data between shader programs, while updating the attribute and uniform ...
constexpr RenderListener(Private) noexcept
Private ctor for shared_ptr<RenderListener> instance method w/o public ctor.
std::string toString() const noexcept
const gamp::render::RenderContext * renderContext() const noexcept
void addKeyListener(const KeyListenerSRef &l)
void dispose(const jau::fraction_timespec &when) noexcept override
size_t removeKeyListener(const KeyListenerSRef &l)
std::string toString() const noexcept
std::string toString() const noexcept
constexpr VKeyCode keySym() const noexcept
Returns the virtual key symbol reflecting the current keyboard layout.
virtual const PressedKeyCodes & pressedKeyCodes() const noexcept=0
constexpr const WindowWeakPtr & source() const noexcept
constexpr const jau::fraction_timespec & when() const noexcept
size_type count() const noexcept
Implementation of a dynamic linear array storage, aka vector, including relative positional access.
constexpr size_type size() const noexcept
Like std::vector::size().
constexpr Matrix4 & loadIdentity() noexcept
Set this matrix to identity.
static constexpr const value_type one
constexpr Mat4 & getP() noexcept
Returns the projection matrix (P).
constexpr PMVMatrix4 & translateMv(float x, float y, float z) noexcept
Translate the modelview matrix.
constexpr_cxx20 PMVMatrix4 & popMv() noexcept
Pop the modelview matrix from its stack.
PMVMatrix4 & perspectiveP(const float fovy_rad, const float aspect, const float zNear, const float zFar)
Multiply the projection matrix with the perspective/frustum matrix.
constexpr Mat4 & getMv() noexcept
Returns the modelview matrix (Mv).
constexpr_cxx20 PMVMatrix4 & pushMv() noexcept
Push the modelview matrix to its stack, while preserving its values.
#define jau_fprintf_td(stream, fmt,...)
std::shared_ptr< Shape > ShapeRef
constexpr T adeg_to_rad(const T arc_degree) noexcept
Converts arc-degree to radians.
GLArrayDataServer< float > GLFloatArrayDataServer
GLArrayDataServerSRef< float > GLFloatArrayDataServerSRef
GLsizeiptr glmemsize_t
Compatible with ssize_t.
GLArrayDataServer< uint32_t > GLUIntArrayDataServer
GLArrayDataServerSRef< uint32_t > GLUIntArrayDataServerSRef
std::shared_ptr< ShaderCode > ShaderCodeSRef
std::shared_ptr< ShaderProgram > ShaderProgramSRef
jau::darray< Vertex, uint32_t > VertexList
std::shared_ptr< Triangle > TriangleRef
jau::darray< TriangleRef, uint32_t > TriangleRefList
@ verbose
Verbose operations (debugging).
std::shared_ptr< Window > WindowSRef
PMVData
PMVMatrix4 derived matrices and values.
std::string_view to_string(const math_error_t v) noexcept
Returns std::string_view representation of math_error_t.
Quaternion< float > Quat4f
PMVMatrix4< float > PMVMat4f
@ inv_mv
Bit value for inverse modelview matrix (Mvi), updated via update().
@ inv_proj
Bit value for inverse projection matrix (Pi), updated via update().
@ inv_tps_mv
Bit value for inverse transposed modelview matrix (Mvit), updated via update().
Gamp: Graphics, Audio, Multimedia and Processing Framework (Native C++, WebAssembly,...
ssize_t fprintf_td(const uint64_t elapsed_ms, FILE *stream, std::string_view format, const Args &...args) noexcept
Convenient secure fprintf() invocation, prepending the given elapsed_ms timestamp and using jau:forma...
bool m_hasFrustumClipping
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
constexpr uint64_t to_ms() const noexcept
Returns time in milliseconds.