Gamp v0.0.8
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
PrimitivesCobraMK3.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11
12#include <cstdio>
13#include <cmath>
14#include <gamp/graph/Graph.hpp>
19#include <memory>
20#include <string>
21#include <string_view>
22#include <vector>
23
24#include <jau/basic_types.hpp>
25#include <jau/cpp_lang_util.hpp>
26#include <jau/darray.hpp>
27#include <jau/debug.hpp>
28#include <jau/float_math.hpp>
29#include <jau/float_types.hpp>
30#include <jau/fraction_type.hpp>
31#include <jau/io/file_util.hpp>
34#include <jau/math/vec3f.hpp>
35#include <jau/math/vec4f.hpp>
36#include <jau/math/vec4f.hpp>
41
42#include <gamp/Gamp.hpp>
47
49
51
53
55
56#include <cstdio>
57#include <cmath>
60#include <memory>
61#include <vector>
62
63#include <jau/basic_types.hpp>
64#include <jau/darray.hpp>
65#include <jau/float_math.hpp>
66#include <jau/float_types.hpp>
67#include <jau/fraction_type.hpp>
68#include <jau/io/file_util.hpp>
69#include <jau/math/vec3f.hpp>
70#include <jau/math/vec4f.hpp>
71#include <jau/math/vec4f.hpp>
76
77#include <gamp/Gamp.hpp>
82
85#include "model_cobramk3.hpp"
86
88
89using namespace jau::math;
90using namespace jau::math::util;
91using namespace jau::math::geom;
92
93using namespace gamp;
94using namespace gamp::wt;
95using namespace gamp::wt::event;
96
97using namespace gamp::graph;
98using namespace gamp::render::gl::glsl;
99using namespace gamp::render::gl::data;
100
101using namespace gamp::graph::tess;
102
103#if 0
104static void printOutlineShape(const std::string &tag, const OutlineShape& o, size_t idx=0) {
105 size_t o_idx=0;
106 printf("- %s: OutlineShape [%2zu]: %u outlines: %s\n", tag, idx, o.outlines().size(), o.toString());
107 for(const Outline& ol : o.outlines()){
108 printf(" - Outline [%2zu][%2zu]:\n", idx, o_idx);
109 for(const Vertex& v : ol.vertices()){
110 printf(" - V[%2zu][%2zu]: %s\n", idx, o_idx, v.coord().toString());
111 }
112 ++o_idx;
113 }
114}
115
116static void printOutlineShapes(const std::string &tag, const std::vector<OutlineShape>& oshapes) {
117 printf("%s: %zu OutlineShapes\n", tag, oshapes.size());
118 size_t os_idx=0;
119 for( const OutlineShape& o : oshapes ) {
120 printOutlineShape(tag, o, os_idx);
121 ++os_idx;
122 }
123}
124#endif
125
126class GraphRenderer {
127 public:
128 struct GraphRendererProps {
129 bool m_isTwoPass = false;
130 bool m_pass1 = true;
131 bool m_hasFrustumClipping = false;
132 bool m_hasNormalChannel = false;
133 bool m_hasLight0 = true;
134 bool m_hasColorChannel = false;
135 bool m_hasColorTexture = false;
136 bool m_hasDiscard = true;
137 };
138 private:
139 constexpr static PMVData mat_req = PMVData::inv_proj | PMVData::inv_mv | PMVData::inv_tps_mv;
140 constexpr static jau::math::Vec3f lightPos = jau::math::Vec3f(2.0f, 2.0f, 5.0f);
141 GraphRendererProps m_props;
142 ShaderState& m_st;
143 GLUniformSyncPMVMat4f m_pmvMat;
144 GLUniformVec3f m_light0Pos;
145 GLUniformVec4f m_staticColor;
146 bool m_initialized;
147
148 public:
149 constexpr bool usesNormal() const noexcept { return m_props.m_hasLight0 || m_props.m_hasNormalChannel; }
150 constexpr GLsizei arrayCompsPerElement() const noexcept { return usesNormal()? 2*3 : 1*3; }
151
152 public:
154 : m_st(st),
155 m_pmvMat("gcu_PMVMatrix", mat_req), // P, Mv, Mvi and Mvit
156 m_light0Pos("gcu_Light0Pos", lightPos),
157 m_staticColor("gcu_StaticColor", Vec4f(0, 0, 0, 1)),
158 m_initialized(false)
159 {
160 m_st.manage(m_pmvMat);
161 m_st.manage(m_light0Pos);
162 m_st.manage(m_staticColor);
163 }
164
165 constexpr bool initialized() const noexcept { return m_initialized; }
166
167 bool init(GL& gl, const jau::fraction_timespec& when) {
168 // ShaderCode::DEBUG_CODE = true;
169 // ShaderState::VERBOSE_STATE = true;
170
171 ShaderCodeSRef rsVp = ShaderCode::create(gl, GL_VERTEX_SHADER, "demos/glsl",
172 "demos/glsl/bin", "SingleLight0");
173 ShaderCodeSRef rsFp = ShaderCode::create(gl, GL_FRAGMENT_SHADER, "demos/glsl",
174 "demos/glsl/bin", "SingleLight0");
175 if( !rsVp || !rsFp ) {
176 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d\n", E_FILE_LINE);
177 return false;
178 }
179 {
180 std::string custom = "#define MAX_TEXTURE_UNITS 0\n";
181 size_t vsPos = rsVp->defaultShaderCustomization(gl, true, true);
182 size_t fsPos = rsFp->defaultShaderCustomization(gl, true, true);
183 rsVp->insertShaderSource(0, vsPos, custom);
184 rsFp->insertShaderSource(0, fsPos, custom);
185 }
187 if( !sp0->add(gl, rsVp, true) || !sp0->add(gl, rsFp, true) ) {
188 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d\n", E_FILE_LINE);
189 sp0->destroy(gl);
190 return false;
191 }
192 m_st.attachShaderProgram(gl, sp0, true);
193
194 PMVMat4f& pmv = m_pmvMat.pmv();
195 pmv.getP().loadIdentity();
196 pmv.getMv().loadIdentity();
197
198 m_st.send(gl, m_pmvMat);
199 m_st.send(gl, m_light0Pos);
200 m_st.send(gl, m_staticColor);
201
202 m_initialized = sp0->inUse();
203 if( !m_initialized ) {
204 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d\n", E_FILE_LINE);
205 m_st.destroy(gl);
206 }
207 return m_initialized;
208 }
209
210 void destroy(GL& gl) {
211 m_st.destroyShaderProgram(gl);
212 }
213
214 void useProgram(GL& gl, bool on) {
215 m_st.useProgram(gl, on);
216 }
217
219 m_st.send(gl, m_staticColor);
220 }
221 void updatePMV(GL& gl) {
222 m_st.send(gl, m_pmvMat);
223 }
224 void updateAll(GL& gl) {
225 m_st.send(gl, m_pmvMat);
226 m_st.send(gl, m_staticColor);
227 }
228 PMVMat4f& pmv() noexcept { return m_pmvMat.pmv(); }
229 const PMVMat4f& pmv() const noexcept { return m_pmvMat.pmv(); }
230 const Vec4f& color() const noexcept { return m_staticColor.vec4f(); }
231 void setColor(const Vec4f& c) noexcept { m_staticColor.vec4f()=c; }
232 ShaderState& st() noexcept { return m_st; }
233 const ShaderState& st() const noexcept { return m_st; }
234 GLUniformVec3f& lightPosition() noexcept { return m_light0Pos; }
235 const GLUniformVec3f& lightPosition() const noexcept { return m_light0Pos; }
236};
237
238class GraphRegion {
239 public:
241 private:
242 GraphRenderer& m_renderer;
245
246 public:
248 : m_renderer(renderer),
249 m_array(GLFloatArrayDataServer::createGLSLInterleaved(m_renderer.arrayCompsPerElement(), false, 256, GL_STATIC_DRAW)) {
250 m_array->addGLSLSubArray("gca_Vertex", 3, GL_ARRAY_BUFFER);
251 if( m_renderer.usesNormal() ) {
252 m_array->addGLSLSubArray("gca_Normal", 3, GL_ARRAY_BUFFER);
253 }
254 m_renderer.st().manage(m_array);
255 // m_st.manage(m_indices);
256 }
257
258 constexpr bool initialized() const noexcept { return m_renderer.initialized(); }
259
260 void destroy(GL& gl) {
261 m_renderer.st().destroyAllData(gl);
262 // m_array->destroy(gl); // owned by m_st
263 }
264
265 void seal(GL& gl, bool seal_) {
266 if( !initialized() ) {
267 return;
268 }
269 m_array->seal(gl, seal_);
270 m_array->enableBuffer(gl, false);
271 }
272
273 public:
274 void clear(GL &gl) {
275 m_array->clear(gl);
276 m_segments.clear();
277 }
279 if( !initialized() ) {
280 return;
281 }
282 if( Graph::DEBUG_MODE ) {
283 jau_PLAIN_PRINT(true, "add.0 array: %s", m_array->toString());
284 jau_PLAIN_PRINT(true, "add.0 segments:\n%s", GLUtilTesselator::Segment::toString("- ", m_segments) );
285 }
286 // TODO use a GLUtilTesselator instance to be reused (perf)?
287 // - Keep native tesselator instance in GLUtilTesselator, callback setup and etc
288 {
289 GLUtilTesselator glutess(/*GLUtilTesselator::FLAG_VERBOSE | */ GLUtilTesselator::FLAG_NORMAL, *m_array);
290 GLUtilTesselator::SegmentList segs = glutess.tesselate(shape);
291 m_segments.insert(m_segments.cend(), segs.cbegin(), segs.cend());
292 }
293
294 if( Graph::DEBUG_MODE ) {
295 jau_PLAIN_PRINT(true, "add.x array: %s", m_array->toString());
296 jau_PLAIN_PRINT(true, "add.x segments:\n%s", GLUtilTesselator::Segment::toString("- ", m_segments) );
297 }
298 }
299
300 void draw(GL &gl) {
301 static bool once = true;
302 if (once) {
303 jau::fprintf_td(stdout, "Region::draw: m_initialized %s, array %s\n", initialized(), m_array->toString());
304 // jau::fprintf_td(stdout, "Region::draw: segments:\n%s", GLUtilTesselator::Segment::toString("- ", m_segments) );
305 once = false;
306 }
307 if( !initialized() ) {
308 return;
309 }
310 m_renderer.useProgram(gl, true);
311
312 m_array->enableBuffer(gl, true);
313
314 ::glEnable(GL_BLEND);
315 ::glBlendEquation(GL_FUNC_ADD); // default
316 ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
317
318 for(const GLUtilTesselator::Segment& s : m_segments ) {
319 ::glDrawArrays(s.type, s.first, s.count);
320 }
321
322 m_array->enableBuffer(gl, false);
323 // m_renderer.useProgram(gl, false);
324 }
325};
326
328 private:
329 Vec3f m_position;
330 Quat4f m_rotation;
331 Vec3f m_rotPivot;
332 Vec3f m_scale = Vec3f(1, 1, 1);
333 float m_zOffset = 0.0f;
334
335 public:
336 SpatialState() noexcept = default;
337 SpatialState(const SpatialState&) noexcept = default;
338 SpatialState& operator=(const SpatialState&) noexcept = default;
339
340 constexpr const Vec3f& position() const noexcept { return m_position; }
341 constexpr Vec3f& position() noexcept { return m_position; }
342 constexpr void set_position(Vec3f new_pos) noexcept { m_position = new_pos; }
343
344 constexpr const float& zOffset() const noexcept { return m_zOffset; }
345 constexpr float& zOffset() noexcept { return m_zOffset; }
346
347 constexpr const Quat4f& rotation() const noexcept { return m_rotation; }
348 constexpr Quat4f& rotation() noexcept { return m_rotation; }
349
350 constexpr const Vec3f& rotationPivot() const noexcept { return m_rotPivot; }
351 constexpr Vec3f& rotationPivot() noexcept { return m_rotPivot; }
352
353 constexpr const Vec3f& scale() const noexcept { return m_scale; }
354 constexpr Vec3f& scale() noexcept { return m_scale; }
355
356 void updateMat(const Vec3f& ctr, Mat4f &iMat, bool &iMatIdent) const noexcept {
357 bool hasPos = !m_position.is_zero();
358 bool hasScale = m_scale != Vec3f::one;
359 bool hasRotate = !m_rotation.isIdentity();
360 bool hasRotPivot = false; // null != rotPivot;
361 {
362 bool sameScaleRotatePivot = hasScale && hasRotate && ( !hasRotPivot || m_rotPivot == ctr );
363
364 if( sameScaleRotatePivot ) {
365 iMatIdent = false;
366 iMat.setToTranslation(m_position); // identity + translate, scaled
367 // Scale shape from its center position and rotate around its center
368 iMat.translate(Vec3f(ctr).mul(m_scale)); // add-back center, scaled
369 iMat.rotate(m_rotation);
370 iMat.scale(m_scale);
371 iMat.translate(-ctr); // move to center
372 } else if( hasRotate || hasScale ) {
373 iMatIdent = false;
374 iMat.setToTranslation(m_position); // identity + translate, scaled
375 if( hasRotate ) {
376 if( hasRotPivot ) {
377 // Rotate shape around its scaled pivot
378 iMat.translate(Vec3f(m_rotPivot).mul(m_scale)); // pivot back from rot-pivot, scaled
379 iMat.rotate(m_rotation);
380 iMat.translate(Vec3f(-m_rotPivot).mul(m_scale)); // pivot to rot-pivot, scaled
381 } else {
382 // Rotate shape around its scaled center
383 iMat.translate(Vec3f(ctr).mul(m_scale)); // pivot back from center-pivot, scaled
384 iMat.rotate(m_rotation);
385 iMat.translate(Vec3f(-ctr).mul(m_scale)); // pivot to center-pivot, scaled
386 }
387 }
388 if( hasScale ) {
389 // Scale shape from its center position
390 iMat.translate(Vec3f(ctr).mul(m_scale)); // add-back center, scaled
391 iMat.scale(m_scale);
392 iMat.translate(Vec3f(-ctr).mul(m_scale)); // move to center
393 }
394 } else if( hasPos ) {
395 iMatIdent = false;
396 iMat.setToTranslation(m_position); // identity + translate, scaled
397
398 } else {
399 iMatIdent = true;
400 iMat.loadIdentity();
401 }
402 }
403 }
404};
405
406class Shape;
407typedef std::shared_ptr<Shape> ShapeRef;
408
409class Ship;
410typedef std::shared_ptr<Ship> ShipRef;
411
412class Shape {
413 private:
414 std::vector<OutlineShape> m_oshapes;
415 AABBox3f m_bounds;
416
417 SpatialState m_sstate;
418 SpatialState m_sstateOrigin;
419 Vec4f m_color = Vec4f(0, 0, 0, 1);
420 GraphRenderer& m_renderer;
421 GraphRegion m_region;
422
423 protected:
424 Mat4f iMat;
425 Mat4f tmpMat;
426 bool iMatIdent = true;
427 bool iMatDirty = false;
428
429 struct Private{ explicit Private() = default; };
430
431 void resetSpatial() noexcept {
432 iMatDirty = true;
433 m_sstate = m_sstateOrigin;
434 }
435
436 public:
437 Shape(Private, GraphRenderer &renderer)
438 : m_renderer(renderer), m_region(m_renderer)
439 { }
440 virtual ~Shape() noexcept = default;
441
443 return std::make_shared<Shape>(Private(), renderer);
444 }
445
446 virtual void destroy(GL& gl) {
447 m_region.destroy(gl);
448 }
449 virtual void clear(GL& gl) {
450 m_bounds.reset();
451 m_region.clear(gl);
452 iMatDirty = false;
453 m_sstate = SpatialState();
454 }
455
456 const SpatialState& spatialState() const noexcept { return m_sstate; }
457 SpatialState& spatialState() noexcept { return m_sstate; }
458 const AABBox3f& bounds() const noexcept { return m_bounds; }
459
460 constexpr const Vec3f& position() const noexcept { return m_sstate.position(); }
461 constexpr Vec3f& position() noexcept { iMatDirty=true; return m_sstate.position(); }
462 constexpr void set_position(Vec3f new_pos) noexcept { m_sstate.position() = new_pos; }
463
464 constexpr const float& zOffset() const noexcept { return m_sstate.zOffset(); }
465 constexpr float& zOffset() noexcept { iMatDirty=true; return m_sstate.zOffset(); }
466
467 constexpr const Quat4f& rotation() const noexcept { return m_sstate.rotation(); }
468 constexpr Quat4f& rotation() noexcept { iMatDirty=true; return m_sstate.rotation(); }
469
470 constexpr const Vec3f& rotationPivot() const noexcept { return m_sstate.rotationPivot(); }
471 constexpr Vec3f& rotationPivot() noexcept { iMatDirty=true; return m_sstate.rotationPivot(); }
472
473 constexpr const Vec3f& scale() const noexcept { return m_sstate.scale(); }
474 constexpr Vec3f& scale() noexcept { iMatDirty=true; return m_sstate.scale(); }
475
476 constexpr const std::vector<OutlineShape>& outlineShapes() const noexcept { return m_oshapes; }
477 constexpr std::vector<OutlineShape>& outlineShapes() noexcept { return m_oshapes; }
478
479 const Vec4f& color() const noexcept { return m_color; }
480 void setColor(const Vec4f& c) noexcept { m_color = c; }
481
482 void update(GL& gl) {
483 m_bounds.reset();
484 m_region.clear(gl);
485 for(OutlineShape& o : m_oshapes){
486 m_region.addOutlineShape(o);
487 m_bounds.resize(o.bounds());
488 }
489 m_region.seal(gl, true);
490 m_sstateOrigin = m_sstate;
491 }
492
493 void draw(GL &gl) {
494 PMVMat4f& pmv = m_renderer.pmv();
495 pmv.pushMv();
496 applyMatToMv(pmv);
497
498 m_renderer.setColor(m_color);
499 m_renderer.updateAll(gl); // PMV + Color
500
501 m_region.draw(gl);
502 pmv.popMv();
503 }
504 virtual void tick(float /*dt*/) { }
505
506 private:
507 /**
508 * Applies the internal {@link Matrix4f} to the given {@link PMVMatrix4f#getMv() modelview matrix},
509 * i.e. {@code pmv.mulMv( getMat() )}.
510 * <p>
511 * Calls {@link #updateMat()} if dirty.
512 * </p>
513 * In case {@link #isMatIdentity()} is {@code true}, implementation is a no-operation.
514 * </p>
515 * @param pmv the matrix
516 * @see #isMatIdentity()
517 * @see #updateMat()
518 * @see #getMat()
519 * @see PMVMatrix4f#mulMv(Matrix4f)
520 */
521 void applyMatToMv(PMVMat4f& pmvMat) noexcept {
522 if( iMatDirty ) {
523 m_sstate.updateMat(m_bounds.center(), iMat, iMatIdent);
524 iMatDirty = false;
525 }
526 if( !iMatIdent ) {
527 pmvMat.mulMv(iMat);
528 }
529 }
530};
531
532struct VeloEasy {
533 private:
534 float m_velo; // m/s
535
536 public:
537 constexpr float veloScalar() const noexcept { return m_velo; }
538 const Vec3f velo(const Vec3f& dir) const noexcept { return dir * m_velo; }
539
540 void setVelo(float v) noexcept { m_velo = v; }
541 void addVelo(float v) noexcept { m_velo += v; }
542};
543
545 private:
546 Vec3f m_velo; // m/s
547
548 public:
549 constexpr float veloScalar() const noexcept { return m_velo.length(); }
550 const Vec3f& velo() const noexcept { return m_velo; }
551
552 void setVelo(Vec3f dir, float v) noexcept {
553 m_velo = dir * v;
554 }
555 void addVelo(Vec3f dir, float v) noexcept {
556 m_velo += dir * v;
557 }
558};
559
560class Ship : public Shape {
561 private:
562 float m_zAxisDirRotationOffset = 0;
563 VeloEasy m_velo; // m/s
564
565 public:
566 Ship(Shape::Private, GraphRenderer &renderer)
567 : Shape(Shape::Private(), renderer)
568 { }
569
571 return std::make_shared<Ship>(Shape::Private(), renderer);
572 }
573
574 void destroy(GL& gl) override {
576 }
577 void clear(GL& gl) override {
579 m_velo = VeloEasy();
580 }
581
582 /// Set z-axis rotation offset of movement orientation
583 void setOriginZRotation(float v) noexcept { m_zAxisDirRotationOffset = v; }
584
585 void reset() noexcept {
587 m_velo = VeloEasy();
588 }
589
590 Vec3f getDir() const noexcept {
592 orientation.rotateByAngleZ(m_zAxisDirRotationOffset);
593 return orientation.rotateVector(Vec3f(1, 0, 0));
594 }
595 Vec3f velo() const noexcept { return m_velo.velo(getDir()); }
596 void setVelo(float v) noexcept { m_velo.setVelo(v); }
597 void addVelo(float v) noexcept { m_velo.addVelo(v); }
598 void tick(float dt) override {
599 if( !velo().is_zero() ) {
600 iMatDirty = true;
601 position() += velo() * dt;
602 }
603 }
604};
605
606class Game : public RenderListener {
607 private:
608 constexpr static float zNear= 1.0f;
609 constexpr static float zFar =100.0f;
610
611 ShaderState m_st;
612 Recti m_viewport;
613 bool m_initialized;
614 bool m_animating = true;
616 GraphRenderer m_renderer;
617 ShipRef m_ship1;
618 std::vector<ShapeRef> m_shapes;
619 bool m_once = true;
620 GLUniformSyncPMVMat4f m_pmvMat;
621 GLUniformVec3f m_light0Pos;
622 GLUniformVec4f m_staticColor;
623
624 public:
627 m_initialized(false),
628 m_renderer(m_st),
629 m_ship1(Ship::createShared(m_renderer)),
630 m_pmvMat("gcu_PMVMatrix", PMVData::inv_proj | PMVData::inv_mv | PMVData::inv_tps_mv), // P, Mv, Mvi and Mvit
631 m_light0Pos("gcu_Light0Pos", m_renderer.lightPosition().vec3f()),
632 m_staticColor("gcu_StaticColor", Vec4f(0.05f, 0.05f, 0.5f, 1))
633 {
634 m_st.manage(m_pmvMat);
635 m_st.manage(m_light0Pos);
636 m_st.manage(m_staticColor);
637 }
638
639 Recti& viewport() noexcept { return m_viewport; }
640 const Recti& viewport() const noexcept { return m_viewport; }
641 std::vector<ShapeRef>& shapes() noexcept { return m_shapes; }
642 ShipRef& ship1() noexcept { return m_ship1; }
643
644 bool animating() const noexcept { return m_animating; }
645 bool& animating() noexcept { return m_animating; }
646
647 bool init(const WindowSRef& win, const jau::fraction_timespec& when) override {
648 jau::fprintf_td(when.to_ms(), stdout, "RL::init: %s\n", toString());
649 m_tlast = when;
650
651 GL& gl = GL::downcast(win->renderContext());
652
653 if( !m_renderer.init(gl, when) ) {
654 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString());
655 win->dispose(when);
656 return false;
657 }
658
659 m_ship1->clear(gl);
660 models::appendCobraMkIII(m_ship1->outlineShapes());
661 m_ship1->setColor(Vec4f(0.05f, 0.05f, 0.5f, 1.0f));
662 m_ship1->rotation().rotateByAngleX(-jau::PI_4<float>);
663 m_ship1->setOriginZRotation(jau::PI_2<float>);
664 m_ship1->update(gl);
665 m_shapes.push_back(m_ship1);
666
667 if ( false ) {
668 ShapeRef frontShape = Shape::createShared(m_renderer);
669 m_shapes.push_back(frontShape);
670 std::vector<OutlineShape>& oshapes = frontShape->outlineShapes();
671 for(OutlineShape& o : oshapes){
673
674 OutlineShape back = o.flipFace(); // -dz);
675 oshapes.push_back(back);
676 }
677 frontShape->update(gl);
678 frontShape->setColor(Vec4f(0.05f, 0.5f, 0.05f, 1));
679 frontShape->position().x = 1.5f;
680 frontShape->position().y = 0.5f;
681 frontShape->scale().x *= 2.0f;
682 frontShape->scale().y *= 2.0f;
683 }
684 //::glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
685 ::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
686 ::glEnable(GL_DEPTH_TEST);
687 // ::glEnable(GL_CULL_FACE);
688 ::glDisable(GL_CULL_FACE);
689
690 m_initialized = true;
691 if( !m_initialized ) {
692 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString());
693 m_st.destroy(gl);
694 win->dispose(when);
695 }
696 return m_initialized;
697 }
698
699 void dispose(const WindowSRef& win, const jau::fraction_timespec& when) override {
700 GL& gl = GL::downcast(win->renderContext());
701 jau::fprintf_td(when.to_ms(), stdout, "RL::dispose: %s\n", toString());
702 for(ShapeRef& s : m_shapes) {
703 s->destroy(gl);
704 }
705 m_ship1 = nullptr;
706 m_renderer.destroy(gl);
707 m_st.destroy(GL::downcast(win->renderContext()));
708 m_initialized = false;
709 }
710
711 void reshape(const WindowSRef& win, const jau::math::Recti& viewport, const jau::fraction_timespec& when) override {
712 GL& gl = GL::downcast(win->renderContext());
713 jau::fprintf_td(when.to_ms(), stdout, "RL::reshape: %s\n", toString());
714 m_viewport = viewport;
715
716 PMVMat4f& pmv = m_renderer.pmv();
717 pmv.getP().loadIdentity();
718 const float aspect = 1.0f;
719 const float fovy_deg=45.0f;
720 const float aspect2 = ( (float) m_viewport.width() / (float) m_viewport.height() ) / aspect;
721 pmv.perspectiveP(jau::adeg_to_rad(fovy_deg), aspect2, zNear, zFar);
722 pmv.getMv().loadIdentity();
723 pmv.translateMv(0, 0, -5);
724
725 m_st.useProgram(gl, true);
726 // m_st.useProgram(gl, false);
727 }
728
729 void display(const WindowSRef& win, const jau::fraction_timespec& when) override {
730 static bool once = true;
731 if (once) {
732 jau_fprintf_td2(when.to_ms(), stdout, "RL::display: %s, initialized %s, shapes %zu, %s\n", toString(), m_initialized, m_shapes.size(), win->toString());
733 once = false;
734 }
735 if( !m_initialized ) {
736 return;
737 }
738 GL& gl = GL::downcast(win->renderContext());
739 ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
740
741 m_st.useProgram(gl, true);
742
743 const float dt = float( (when - m_tlast).to_double() );
744 for(const ShapeRef& s : m_shapes) {
745 if( m_animating ) {
746 s->tick(dt);
747 }
748 s->draw(gl);
749 }
750
751 if( m_once ) {
752 m_once = false;
753 // std::cerr << "XXX draw " << m_st << "\n";
754 }
755
756 // m_st.useProgram(gl, false);
757
758 m_tlast = when;
759 }
760
761 std::string toStringImpl() const noexcept override { return "GraphShapes01"; }
762};
763
764class Example : public Game {
765 private:
766 class MyKeyListener : public KeyListener {
767 private:
768 Game& m_parent;
769 public:
770 MyKeyListener(Game& p) : m_parent(p) {}
771
772 void keyPressed(KeyEvent& e, [[maybe_unused]] const KeyboardTracker& kt) override {
773 if( e.keySym() == VKeyCode::VK_ESCAPE ) {
774 jau::fprintf_td(e.when().to_ms(), stdout, "EXIT: %s; keys %zu\n", e.toString(), kt.pressedKeyCodes().count());
775 WindowSRef win = e.source().lock();
776 if( win ) {
777 win->dispose(e.when());
778 }
779 } else if( e.keySym() == VKeyCode::VK_R) {
780 jau::fprintf_td(e.when().to_ms(), stdout, "RESET: %s; keys %zu\n", e.toString(), kt.pressedKeyCodes().count());
781 m_parent.ship1()->reset();
782 } else if( e.keySym() == VKeyCode::VK_PAUSE || e.keySym() == VKeyCode::VK_P ) {
783 jau::fprintf_td(e.when().to_ms(), stdout, "PAUSE: %s; keys %zu\n", e.toString(), kt.pressedKeyCodes().count());
784 m_parent.animating() = !m_parent.animating();
785 } else if( e.keySym() == VKeyCode::VK_W ) {
786 WindowSRef win = e.source().lock();
787 jau::fprintf_td(e.when().to_ms(), stdout, "Source: %s\n", win ? win->toString() : "null");
788 } else if( e.keySym() == VKeyCode::VK_UP ) {
789 m_parent.ship1()->rotation().rotateByAngleX(-jau::PI<float> / 50);
790 } else if( e.keySym() == VKeyCode::VK_DOWN ) {
791 m_parent.ship1()->rotation().rotateByAngleX( jau::PI<float> / 50);
792 } else if( e.keySym() == VKeyCode::VK_RIGHT) {
793 m_parent.ship1()->rotation().rotateByAngleY( jau::PI<float> / 50);
794 } else if( e.keySym() == VKeyCode::VK_LEFT ) {
795 m_parent.ship1()->rotation().rotateByAngleY(-jau::PI<float> / 50);
796 } else if( e.keySym() == VKeyCode::VK_A ) {
797 m_parent.ship1()->addVelo(0.1f);
798 } else if( e.keySym() == VKeyCode::VK_S ) {
799 m_parent.ship1()->addVelo(-0.1f);
800 // m_parent.ship1()->velo() = std::max(m_parent.ship1()->velo() - 0.1f, 0.0f);
801 }
802 }
803 void keyReleased([[maybe_unused]] KeyEvent& e, [[maybe_unused]] const KeyboardTracker& kt) override {
804 // jau::fprintf_td(e.when().to_ms(), stdout, "KeyRelease: %s; keys %zu\n", e.toString(), kt.pressedKeyCodes().count());
805 }
806 };
807 typedef std::shared_ptr<MyKeyListener> MyKeyListenerRef;
808 MyKeyListenerRef m_kl;
809
810 public:
812 : Game(),
813 m_kl(std::make_shared<MyKeyListener>(*this)) { }
814
815 bool init(const WindowSRef& win, const jau::fraction_timespec& when) override {
816 if( !Game::init(win, when) ) {
817 return false;
818 }
819 win->addKeyListener(m_kl);
820 return true;
821 }
822 void dispose(const WindowSRef& win, const jau::fraction_timespec& when) override {
823 win->removeKeyListener(m_kl);
824 Game::dispose(win, when);
825 }
826};
827
828int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape)
829{
830 return launch("PrimitivesCobraMK3.cpp",
832 .contextFlags=gamp::render::RenderContextFlags::verbose, // | gamp::render::RenderContextFlags::debug,
833 .requestedCaps=GLCapabilities()},
834 std::make_shared<Example>(), argc, argv);
835}
int launch(std::string_view sfile, GLLaunchProps props, const RenderListenerSRef &demo, int argc, char *argv[])
std::shared_ptr< Shape > ShapeRef
int main(int argc, char *argv[])
std::shared_ptr< Ship > ShipRef
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,...
Recti & viewport() noexcept
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,...
ShipRef & ship1() noexcept
std::vector< ShapeRef > & shapes() noexcept
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.
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.
bool & animating() noexcept
const Recti & viewport() const noexcept
std::string toStringImpl() const noexcept override
static void addShapeToRegion(gamp::graph::OutlineShape &shape)
void destroy(GL &gl)
constexpr bool initialized() const noexcept
void addOutlineShape(OutlineShape &shape)
GraphRegion(GraphRenderer &renderer)
jau::darray< uint32_t, glmemsize_t > u32buffer_t
void seal(GL &gl, bool seal_)
ShaderState & st() noexcept
bool init(GL &gl, const jau::fraction_timespec &when)
const PMVMat4f & pmv() const noexcept
GLUniformVec3f & lightPosition() noexcept
constexpr GLsizei arrayCompsPerElement() const noexcept
const Vec4f & color() const noexcept
constexpr bool initialized() const noexcept
constexpr bool usesNormal() const noexcept
const ShaderState & st() const noexcept
const GLUniformVec3f & lightPosition() const noexcept
void updateColor(GL &gl)
PMVMat4f & pmv() noexcept
GraphRenderer(ShaderState &st)
void useProgram(GL &gl, bool on)
void setColor(const Vec4f &c) noexcept
constexpr const float & zOffset() const noexcept
void setColor(const Vec4f &c) noexcept
void resetSpatial() noexcept
Shape(Private, GraphRenderer &renderer)
constexpr Vec3f & position() noexcept
constexpr std::vector< OutlineShape > & outlineShapes() noexcept
static ShapeRef createShared(ShaderState &st, GraphRenderer &renderer)
void draw(GL &gl)
void update(GL &gl)
virtual void destroy(GL &gl)
constexpr const std::vector< OutlineShape > & outlineShapes() const noexcept
constexpr const Quat4f & rotation() const noexcept
constexpr void set_position(Vec3f new_pos) noexcept
const AABBox3f & bounds() const noexcept
Shape(Private, ShaderState &st, GraphRenderer &renderer)
void destroy(GL &gl)
constexpr const Vec3f & rotationPivot() const noexcept
virtual void clear(GL &gl)
constexpr float & zOffset() noexcept
SpatialState & spatialState() noexcept
constexpr const Vec3f & position() const noexcept
constexpr Vec3f & scale() noexcept
virtual void tick(float)
constexpr Vec3f & rotationPivot() noexcept
const Vec4f & color() const noexcept
constexpr const Vec3f & scale() const noexcept
const SpatialState & spatialState() const noexcept
virtual ~Shape() noexcept=default
constexpr Quat4f & rotation() noexcept
Vec3f getDir() const noexcept
void reset() noexcept
void setVelo(float v) noexcept
Vec3f velo() const noexcept
Ship(Shape::Private, GraphRenderer &renderer)
void destroy(GL &gl) override
static ShipRef createShared(GraphRenderer &renderer)
void tick(float dt) override
void addVelo(float v) noexcept
void setOriginZRotation(float v) noexcept
Set z-axis rotation offset of movement orientation.
void clear(GL &gl) override
static bool DEBUG_MODE
Definition Graph.hpp:24
A Generic shape objects which is defined by a list of Outlines.
const AABBox3f & bounds() const noexcept
const OutlineList & outlines() const noexcept
std::string toString() const noexcept
OutlineShape flipFace(float zoffset=0) const
Returns a copy of this instance with normal() pointing to the opposite direction and all outlines() v...
Define a single continuous stroke by control vertices.
Definition Outline.hpp:51
GLUtilTesselator transform OutlineShapes to triangles using glutess2.
static SegmentList tesselate(int flags, GLFloatArrayDataServer &array, OutlineShape &outlines)
Specifies a set of OpenGL capabilities.
static GLContext & downcast(RenderContext *rc)
Downcast dereferenced given RenderContext* to GLContext&, throws exception if signature doesn't match...
Specifies the OpenGL profile.
Definition GLContext.hpp:42
static constexpr std::string_view GLES2
The embedded OpenGL profile ES 2.x, with x >= 0.
Definition GLContext.hpp:65
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 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.
Definition Window.hpp:60
std::string toString() const noexcept
Definition Window.hpp:112
const gamp::render::RenderContext * renderContext() const noexcept
Definition Surface.hpp:131
void addKeyListener(const KeyListenerSRef &l)
Definition Window.hpp:310
void dispose(const jau::fraction_timespec &when) noexcept override
Definition Window.hpp:355
size_t removeKeyListener(const KeyListenerSRef &l)
Definition Window.hpp:311
std::string toString() const noexcept
Definition gamp_wt.cpp:145
std::string toString() const noexcept
Definition KeyEvent.hpp:855
constexpr VKeyCode keySym() const noexcept
Returns the virtual key symbol reflecting the current keyboard layout.
Definition KeyEvent.hpp:798
constexpr const WindowWeakPtr & source() const noexcept
Definition Event.hpp:85
constexpr const jau::fraction_timespec & when() const noexcept
Definition Event.hpp:84
Implementation of a dynamic linear array storage, aka vector, including relative positional access.
Definition darray.hpp:154
constexpr size_type size() const noexcept
Like std::vector::size().
Definition darray.hpp:1116
constexpr Matrix4 & loadIdentity() noexcept
Set this matrix to identity.
Definition mat4f.hpp:239
value_type x
Definition vec3f.hpp:66
value_type y
Definition vec3f.hpp:67
constexpr Vector3F & scale(const value_type s) noexcept
this = this * s, component wise.
Definition vec3f.hpp:169
static constexpr const value_type one
Definition vec3f.hpp:64
Axis Aligned Bounding Box.
Definition aabbox3f.hpp:43
constexpr const Point3f & center() const noexcept
Returns computed center of this aabbox3f of low() and high().
Definition aabbox3f.hpp:105
constexpr Mat4 & getP() noexcept
Returns the projection matrix (P).
Definition pmvmat4.hpp:263
constexpr PMVMatrix4 & translateMv(float x, float y, float z) noexcept
Translate the modelview matrix.
Definition pmvmat4.hpp:641
constexpr_cxx20 PMVMatrix4 & popMv() noexcept
Pop the modelview matrix from its stack.
Definition pmvmat4.hpp:795
PMVMatrix4 & perspectiveP(const float fovy_rad, const float aspect, const float zNear, const float zFar)
Multiply the projection matrix with the perspective/frustum matrix.
Definition pmvmat4.hpp:885
constexpr Mat4 & getMv() noexcept
Returns the modelview matrix (Mv).
Definition pmvmat4.hpp:275
constexpr_cxx20 PMVMatrix4 & pushMv() noexcept
Push the modelview matrix to its stack, while preserving its values.
Definition pmvmat4.hpp:813
#define jau_PLAIN_PRINT(printPrefix, fmt,...)
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
Definition debug.hpp:171
#define jau_fprintf_td2(elapsed_ms, stream, fmt,...)
Definition debug.hpp:245
std::shared_ptr< Shape > ShapeRef
#define E_FILE_LINE
constexpr T PI
Alias for π or half-circle radians (180 degrees), i.e. std::numbers::pi_v<T>
constexpr T PI_4
Alias for π/4 or half right-angle radians (45 degrees), i.e. std::numbers::pi_v<T>/T(4)
constexpr T adeg_to_rad(const T arc_degree) noexcept
Converts arc-degree to radians.
constexpr T PI_2
Alias for π/2 or right-angle radians (90 degrees), i.e. std::numbers::pi_v<T>/T(2)
constexpr bool is_zero(const T &a, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if the given value is less than epsilon, w/ epsilon > 0.
GLArrayDataServer< float > GLFloatArrayDataServer
GLArrayDataServerSRef< float > GLFloatArrayDataServerSRef
std::shared_ptr< ShaderCode > ShaderCodeSRef
std::shared_ptr< ShaderProgram > ShaderProgramSRef
@ verbose
Verbose operations (debugging).
std::shared_ptr< Window > WindowSRef
Definition Event.hpp:36
Matrix4< float > Mat4f
Definition mat4f.hpp:1968
constexpr orientation_t orientation(const Point2f &a, const Point2f &b, const Point2f &c) noexcept
Return the orientation of the given point triplet a, b and c using triArea()
Definition geom2f.hpp:49
Vector4F< float > Vec4f
Definition vec4f.hpp:360
PMVData
PMVMatrix4 derived matrices and values.
Definition pmvmat4.hpp:57
Quaternion< float > Quat4f
RectI< int > Recti
Definition recti.hpp:146
Vector3F< float > Vec3f
Definition vec3f.hpp:422
PMVMatrix4< float > PMVMat4f
Definition pmvmat4.hpp:1463
@ inv_mv
Bit value for inverse modelview matrix (Mvi), updated via update().
Definition pmvmat4.hpp:60
@ inv_proj
Bit value for inverse projection matrix (Pi), updated via update().
Definition pmvmat4.hpp:64
@ inv_tps_mv
Bit value for inverse transposed modelview matrix (Mvit), updated via update().
Definition pmvmat4.hpp:62
Gamp: Graphics, Audio, Multimedia and Processing Framework (Native C++, WebAssembly,...
Definition PTS.hpp:24
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...
Definition debug.hpp:188
void appendCobraMkIII(std::vector< OutlineShape > &oshapes, const float height=1.0f, const float width=2.0f, const float deep=0.3f)
STL namespace.
constexpr const float & zOffset() const noexcept
SpatialState() noexcept=default
constexpr float & zOffset() noexcept
constexpr Quat4f & rotation() noexcept
constexpr const Quat4f & rotation() const noexcept
constexpr Vec3f & rotationPivot() noexcept
constexpr const Vec3f & position() const noexcept
void updateMat(const Vec3f &ctr, Mat4f &iMat, bool &iMatIdent) const noexcept
constexpr Vec3f & scale() noexcept
constexpr Vec3f & position() noexcept
constexpr void set_position(Vec3f new_pos) noexcept
constexpr const Vec3f & rotationPivot() const noexcept
constexpr const Vec3f & scale() const noexcept
void setVelo(float v) noexcept
const Vec3f velo(const Vec3f &dir) const noexcept
constexpr float veloScalar() const noexcept
void addVelo(float v) noexcept
void addVelo(Vec3f dir, float v) noexcept
void setVelo(Vec3f dir, float v) noexcept
const Vec3f & velo() const noexcept
constexpr float veloScalar() const noexcept
static std::string toString(const std::string &pre, const SegmentList &segments) noexcept
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.
int printf(const char *format,...)
Operating Systems predefined macros.