Gamp v0.0.8
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
Primitives01.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 <memory>
15
16#include <jau/basic_types.hpp>
17#include <jau/darray.hpp>
18#include <jau/float_math.hpp>
19#include <jau/float_types.hpp>
20#include <jau/fraction_type.hpp>
21#include <jau/io/file_util.hpp>
24#include <jau/math/vec3f.hpp>
25#include <jau/math/vec4f.hpp>
26#include <jau/math/vec4f.hpp>
28
29#include <gamp/Gamp.hpp>
34
36
37using namespace jau::math;
38using namespace jau::math::util;
39using namespace jau::math::geom;
40
41using namespace gamp::wt;
42using namespace gamp::wt::event;
43
44using namespace gamp::render::gl::glsl;
45using namespace gamp::render::gl::data;
46
47class Shape {
48 private:
49 Vec3f m_position;
50 Quat4f m_rotation;
51 Vec4f m_color = Vec4f(1, 0, 0, 1);
52
53 GLenum m_type;
54 ShaderState& m_st;
55 GLUniformSyncPMVMat4f& m_pmvMatUni;
56 GLUniformVec4f& m_staticColor;
58
59 public:
61 : m_type(type), m_st(st), m_pmvMatUni(pmvMatU), m_staticColor(color),
62 m_array( GLFloatArrayDataServer::createGLSLInterleaved(2*3, false, 4, GL_STATIC_DRAW) )
63 {
64 m_array->addGLSLSubArray("gca_Vertex", 3, GL_ARRAY_BUFFER);
65 m_array->addGLSLSubArray("gca_Normal", 3, GL_ARRAY_BUFFER);
66 m_st.manage(m_array);
67 }
68
69 constexpr const Vec3f& position() const noexcept { return m_position; }
70 constexpr Vec3f& position() noexcept { return m_position; }
71
72 constexpr const Quat4f& rotation() const noexcept { return m_rotation; }
73 constexpr Quat4f& rotation() noexcept { return m_rotation; }
74
75 constexpr const GLFloatArrayDataServerSRef& vertices() const noexcept { return m_array; }
76 constexpr GLFloatArrayDataServerSRef& vertices() noexcept { return m_array; }
77
78 const Vec4f& color() const noexcept { return m_color; }
79 void setColor(const Vec4f& c) noexcept { m_color=c; }
80
81 void seal(GL&gl, bool seal) {
82 m_array->seal(gl, seal);
83 }
84 void draw(GL &gl) {
85 m_pmvMatUni.pmv().pushMv();
86 m_pmvMatUni.pmv().translateMv(m_position); // identity + translate, scaled
87 // Rotate shape around its scaled center
88 m_pmvMatUni.pmv().rotateMv(m_rotation);
89 m_st.send(gl, m_pmvMatUni); // automatic sync + update of Mvi + Mvit
90
91 m_staticColor.vec4f() = m_color;
92 m_st.send(gl, m_staticColor);
93
94 m_array->enableBuffer(gl, true);
95 ::glDrawArrays(m_type, 0, m_array->elemCount());
96 m_array->enableBuffer(gl, false);
97 m_pmvMatUni.pmv().popMv();
98 }
99
100};
101
103 private:
104 constexpr static jau::math::Vec3f lightPos = jau::math::Vec3f(0.0f, 5.0f, 10.0f);
105 constexpr static float half = 0.5f;
106 constexpr static float qter = 0.25f;
107 constexpr static float zNear= 1.0f;
108 constexpr static float zFar =100.0f;
109
110 ShaderState m_st;
111 Recti m_viewport;
112 bool m_initialized;
113 bool m_animating = true;
115 Vec4f mgl_ColorStatic = Vec4f(0, 0, 0, 1);
116 GLUniformSyncPMVMat4f m_pmvMatUni;
117 GLUniformVec4f m_staticColor;
118 GLUniformVec3f m_light0Pos;
119 Shape m_shape1, m_shape2;
120 bool m_once = true;
121
122
123 public:
126 m_initialized(false),
127 m_pmvMatUni("gcu_PMVMatrix", PMVData::inv_proj | PMVData::inv_mv | PMVData::inv_tps_mv), // P, Mv, Mvi and Mvit
128 m_staticColor("gcu_StaticColor", Vec4f(1, 0, 0, 1)),
129 m_light0Pos("gcu_Light0Pos", lightPos),
130 m_shape1(GL_TRIANGLE_STRIP, m_st, m_pmvMatUni, m_staticColor),
131 m_shape2(GL_LINE_STRIP, m_st, m_pmvMatUni, m_staticColor)
132 {
133 m_st.manage(m_pmvMatUni);
134 m_st.manage(m_staticColor);
135 m_st.manage(m_light0Pos);
136 }
137
138 Recti& viewport() noexcept { return m_viewport; }
139 const Recti& viewport() const noexcept { return m_viewport; }
140
141 PMVMat4f& pmv() noexcept { return m_pmvMatUni.pmv(); }
142 const PMVMat4f& pmv() const noexcept { return m_pmvMatUni.pmv(); }
143 bool animating() const noexcept { return m_animating; }
144 bool& animating() noexcept { return m_animating; }
145
146 bool init(const WindowSRef& win, const jau::fraction_timespec& when) override {
147 jau::fprintf_td(when.to_ms(), stdout, "RL::init: %s\n", toString().c_str());
148 m_tlast = when;
149
150 GL& gl = GL::downcast(win->renderContext());
151 ShaderCodeSRef vp0 = ShaderCode::create(gl, GL_VERTEX_SHADER, "demos/glsl",
152 "demos/glsl/bin", "SingleLight0");
153 ShaderCodeSRef fp0 = ShaderCode::create(gl, GL_FRAGMENT_SHADER, "demos/glsl",
154 "demos/glsl/bin", "SingleLight0");
155 if( !vp0 || !fp0 ) {
156 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString().c_str());
157 win->dispose(when);
158 return false;
159 }
160 {
161 std::string custom = "#define MAX_TEXTURE_UNITS 0\n";
162 size_t vsPos = vp0->defaultShaderCustomization(gl, true, true);
163 size_t fsPos = fp0->defaultShaderCustomization(gl, true, true);
164 vp0->insertShaderSource(0, vsPos, custom);
165 fp0->insertShaderSource(0, fsPos, custom);
166 }
167
169 if( !sp0->add(gl, vp0, true) || !sp0->add(gl, fp0, true) ) {
170 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString().c_str());
171 sp0->destroy(gl);
172 win->dispose(when);
173 return false;
174 }
175 m_st.attachShaderProgram(gl, sp0, true);
176
177 // setup mgl_PMVMatrix
178 m_pmvMatUni.pmv().getP().loadIdentity();
179 m_pmvMatUni.pmv().getMv().loadIdentity();
180
181 const Vec3f frontNormal(0, 0, 1);
182 const Vec3f backNormal(0, 0, -1);
183 {
184 GLFloatArrayDataServerSRef& v = m_shape1.vertices();
185 float dz = 0.001f;
186 v->put3f(-half, half, dz); v->put3f(frontNormal);
187 v->put3f( half, half, dz); v->put3f(frontNormal);
188 v->put3f(-half, -half, dz); v->put3f(frontNormal);
189 v->put3f( half, -half, dz); v->put3f(frontNormal);
190
191 dz = -0.001f;
192 v->put3f(-half, half, dz); v->put3f(backNormal);
193 v->put3f( half, half, dz); v->put3f(backNormal);
194 v->put3f(-half, -half, dz); v->put3f(backNormal);
195 v->put3f( half, -half, dz); v->put3f(backNormal);
196 m_shape1.seal(gl, true);
197 m_shape1.setColor(Vec4f(0, 1, 0, 1));
198 m_shape1.position().x = 1.5f;
199 }
200 {
201 const float lineWidth = 1/10.0f;
202 const float tw = 1.0f;
203 const float th = 1.0f;
204
205 float lwh = lineWidth/2.0f;
206
207 float twh = tw/2.0f;
208 float thh = th/2.0f;
209
210 float ctrX = 0, ctrY = 0;
211 float ctrZ = 0;
212
213 GLFloatArrayDataServerSRef& v = m_shape2.vertices();
214 // CCW
215 v->put3f(ctrX-lwh, ctrY+thh, ctrZ); v->put3f(frontNormal); // vert: left-top
216 v->put3f(ctrX-lwh, ctrY+lwh, ctrZ); v->put3f(frontNormal);
217 v->put3f(ctrX-twh, ctrY+lwh, ctrZ); v->put3f(frontNormal); // horz: left-top
218 v->put3f(ctrX-twh, ctrY-lwh, ctrZ); v->put3f(frontNormal); // horz: left-bottom
219 v->put3f(ctrX-lwh, ctrY-lwh, ctrZ); v->put3f(frontNormal);
220 v->put3f(ctrX-lwh, ctrY-thh, ctrZ); v->put3f(frontNormal); // vert: left-bottom
221 v->put3f(ctrX+lwh, ctrY-thh, ctrZ); v->put3f(frontNormal); // vert: right-bottom
222 v->put3f(ctrX+lwh, ctrY-lwh, ctrZ); v->put3f(frontNormal);
223 v->put3f(ctrX+twh, ctrY-lwh, ctrZ); v->put3f(frontNormal); // horz: right-bottom
224 v->put3f(ctrX+twh, ctrY+lwh, ctrZ); v->put3f(frontNormal); // horz: right-top
225 v->put3f(ctrX+lwh, ctrY+lwh, ctrZ); v->put3f(frontNormal);
226 v->put3f(ctrX+lwh, ctrY+thh, ctrZ); v->put3f(frontNormal); // vert: right-top
227 v->put3f(ctrX-lwh, ctrY+thh, ctrZ); v->put3f(frontNormal); // vert: left-top
228 m_shape2.seal(gl, true);
229 m_shape2.setColor(Vec4f(0, 0, 1, 1));
230 m_shape2.position().x = -1.5f;
231 }
232
233 ::glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
234 ::glEnable(GL_DEPTH_TEST);
235
236 m_initialized = sp0->inUse();
237 if( !m_initialized ) {
238 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString().c_str());
239 m_st.destroy(gl);
240 win->dispose(when);
241 }
242 return m_initialized;
243 }
244
245 void dispose(const WindowSRef& win, const jau::fraction_timespec& when) override {
246 jau::fprintf_td(when.to_ms(), stdout, "RL::dispose: %s\n", toString().c_str());
247 m_st.destroy(GL::downcast(win->renderContext()));
248 m_initialized = false;
249 }
250
251 void reshape(const WindowSRef& win, const jau::math::Recti& viewport, const jau::fraction_timespec& when) override {
252 GL& gl = GL::downcast(win->renderContext());
253 jau::fprintf_td(when.to_ms(), stdout, "RL::reshape: %s\n", toString().c_str());
254 m_viewport = viewport;
255
256 m_pmvMatUni.pmv().getP().loadIdentity();
257 const float aspect = 1.0f;
258 const float fovy_deg=45.0f;
259 const float aspect2 = ( (float) m_viewport.width() / (float) m_viewport.height() ) / aspect;
260 m_pmvMatUni.pmv().perspectiveP(jau::adeg_to_rad(fovy_deg), aspect2, zNear, zFar);
261 m_st.useProgram(gl, true);
262 m_st.send(gl, m_pmvMatUni); // automatic sync + update of Mvi + Mvit
263 m_st.useProgram(gl, true);
264 }
265
266 void display(const WindowSRef& win, const jau::fraction_timespec& when) override {
267 // jau::fprintf_td(when.to_ms(), stdout, "RL::display: %s, %s\n", toString().c_str(), win->toString().c_str());
268 if( !m_initialized ) {
269 return;
270 }
271 GL& gl = GL::downcast(win->renderContext());
272 ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
273
274 m_st.useProgram(gl, true);
275 m_pmvMatUni.pmv().getMv().loadIdentity();
276 m_pmvMatUni.pmv().translateMv(0, 0, -5);
277
278 if( animating() ) {
279 constexpr double angle_per_sec = 30;
280 const float rad = (float) ( (when - m_tlast).to_double() * angle_per_sec );
281 m_shape1.rotation().rotateByAngleY(jau::adeg_to_rad( rad ));
282 m_shape2.rotation().rotateByAngleY(jau::adeg_to_rad( -rad ));
283 }
284 m_shape1.draw(gl);
285 m_shape2.draw(gl);
286
287 if( m_once ) {
288 m_once = false;
289 std::cerr << "XXX draw " << m_st << "\n";
290 }
291
292 m_st.useProgram(gl, false);
293
294 m_tlast = when;
295 }
296
297 std::string toStringImpl() const noexcept override { return "Primitives01"; }
298};
299
300class Example : public Primitives01 {
301 private:
302 class MyKeyListener : public KeyListener {
303 private:
304 Primitives01& m_parent;
305 public:
306 MyKeyListener(Primitives01& p) : m_parent(p) {}
307
308 void keyPressed(KeyEvent& e, const KeyboardTracker& kt) override {
309 jau::fprintf_td(e.when().to_ms(), stdout, "KeyPressed: %s; keys %zu\n", e.toString().c_str(), kt.pressedKeyCodes().count());
310 if( e.keySym() == VKeyCode::VK_ESCAPE ) {
311 WindowSRef win = e.source().lock();
312 if( win ) {
313 win->dispose(e.when());
314 }
315 } else if( e.keySym() == VKeyCode::VK_PAUSE || e.keySym() == VKeyCode::VK_P ) {
316 m_parent.animating() = !m_parent.animating();
317 } else if( e.keySym() == VKeyCode::VK_W ) {
318 WindowSRef win = e.source().lock();
319 jau::fprintf_td(e.when().to_ms(), stdout, "Source: %s\n", win ? win->toString().c_str() : "null");
320 }
321 }
322 void keyReleased(KeyEvent& e, const KeyboardTracker& kt) override {
323 jau::fprintf_td(e.when().to_ms(), stdout, "KeyRelease: %s; keys %zu\n", e.toString().c_str(), kt.pressedKeyCodes().count());
324 }
325 };
326 typedef std::shared_ptr<MyKeyListener> MyKeyListenerRef;
327 MyKeyListenerRef m_kl;
328
329 public:
331 : Primitives01(),
332 m_kl(std::make_shared<MyKeyListener>(*this)) { }
333
334 bool init(const WindowSRef& win, const jau::fraction_timespec& when) override {
335 if( !Primitives01::init(win, when) ) {
336 return false;
337 }
338 win->addKeyListener(m_kl);
339 return true;
340 }
341 void dispose(const WindowSRef& win, const jau::fraction_timespec& when) override {
342 win->removeKeyListener(m_kl);
343 Primitives01::dispose(win, when);
344 }
345};
346
347int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape)
348{
350
351 return launch("Primitives01.cpp",
353 std::make_shared<Example>(), argc, argv);
354}
int launch(std::string_view sfile, GLLaunchProps props, const RenderListenerSRef &demo, int argc, char *argv[])
int main(int argc, char *argv[])
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,...
PMVMat4f & pmv() 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.
void display(const WindowSRef &win, const jau::fraction_timespec &when) override
Called by the drawable to initiate rendering by the client.
void dispose(const WindowSRef &win, const jau::fraction_timespec &when) override
Notifies the listener to perform the release of all renderer resources per context,...
std::string toStringImpl() const noexcept override
bool init(const WindowSRef &win, const jau::fraction_timespec &when) override
Called by the drawable immediately after the render context is initialized.
const PMVMat4f & pmv() const noexcept
bool animating() const noexcept
const Recti & viewport() const noexcept
bool & animating() noexcept
Recti & viewport() noexcept
void setColor(const Vec4f &c) noexcept
constexpr Vec3f & position() noexcept
void draw(GL &gl)
constexpr const Quat4f & rotation() const noexcept
constexpr GLFloatArrayDataServerSRef & vertices() noexcept
Shape(GLenum type, ShaderState &st, GLUniformSyncPMVMat4f &pmvMatU, GLUniformVec4f &color)
constexpr const GLFloatArrayDataServerSRef & vertices() const noexcept
constexpr const Vec3f & position() const noexcept
const Vec4f & color() const noexcept
void seal(GL &gl, bool seal)
constexpr Quat4f & rotation() noexcept
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
virtual const PressedKeyCodes & pressedKeyCodes() const noexcept=0
constexpr const WindowWeakPtr & source() const noexcept
Definition Event.hpp:85
constexpr const jau::fraction_timespec & when() const noexcept
Definition Event.hpp:84
size_type count() const noexcept
Definition bitfield.hpp:368
#define E_FILE_LINE
constexpr T adeg_to_rad(const T arc_degree) noexcept
Converts arc-degree to radians.
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
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
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
STL namespace.
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.