Gamp v0.0.7-54-gccdc599
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
50
53 u( GLUniformSyncMatrices4f::create("gcu_PMVMatrix", m.makeSyncPMvMviMvit()) ) // P, Mv, Mvi and Mvit
54 {}
55};
56
57class Shape {
58 private:
59 GLenum m_type;
60 ShaderState& m_st;
61 PMVMat4fUniform& m_pmvMatUni;
63
64 Vec3f m_position;
65 Quat4f m_rotation;
66 Vec4f m_color = Vec4f(1, 0, 0, 1);
67 GLUniformVec4fRef m_uColor;
68
69 public:
70 Shape(GLenum type, ShaderState &st, PMVMat4fUniform& pmvMatU)
71 : m_type(type), m_st(st), m_pmvMatUni(pmvMatU), m_array( GLFloatArrayDataServer::createGLSLInterleaved(2*3, false, 4, GL_STATIC_DRAW) )
72 {
73 m_array->addGLSLSubArray("gca_Vertex", 3, GL_ARRAY_BUFFER);
74 m_array->addGLSLSubArray("gca_Normal", 3, GL_ARRAY_BUFFER);
75 m_st.ownAttribute(m_array, true);
76
77 m_uColor = GLUniformVec4f::create("gcu_StaticColor", Vec4f(1, 0, 0, 1));
78 m_st.ownUniform(m_uColor, true);
79 }
80
81 constexpr const Vec3f& position() const noexcept { return m_position; }
82 constexpr Vec3f& position() noexcept { return m_position; }
83
84 constexpr const Quat4f& rotation() const noexcept { return m_rotation; }
85 constexpr Quat4f& rotation() noexcept { return m_rotation; }
86
87 constexpr const GLFloatArrayDataServerRef& vertices() const noexcept { return m_array; }
88 constexpr GLFloatArrayDataServerRef& vertices() noexcept { return m_array; }
89
90 const Vec4f& color() const noexcept { return m_uColor->vec4f(); }
91 void setColor(const Vec4f& c) noexcept { m_uColor->vec4f()=c; }
92
93 void seal(GL&gl, bool seal) {
94 m_array->seal(gl, seal);
95 }
96 void draw(GL &gl) {
97 m_pmvMatUni.m.pushMv();
98 m_pmvMatUni.m.translateMv(m_position); // identity + translate, scaled
99 // Rotate shape around its scaled center
100 m_pmvMatUni.m.rotateMv(m_rotation);
101 m_st.pushUniform(gl, m_pmvMatUni.u); // automatic sync + update of Mvi + Mvit
102
103 m_st.pushUniform(gl, m_uColor);
104
105 m_array->enableBuffer(gl, true);
106 ::glDrawArrays(m_type, 0, m_array->elemCount());
107 m_array->enableBuffer(gl, false);
108 m_pmvMatUni.m.popMv();
109 }
110
111};
112
114 private:
115 constexpr static jau::math::Vec3f lightPos = jau::math::Vec3f(0.0f, 5.0f, 10.0f);
116 constexpr static float half = 0.5f;
117 constexpr static float qter = 0.25f;
118 constexpr static float zNear= 1.0f;
119 constexpr static float zFar =100.0f;
120
121 ShaderState m_st;
122 Recti m_viewport;
123 bool m_initialized;
124 bool m_animating = true;
126 PMVMat4fUniform m_pmvMat;
127 Vec4f mgl_ColorStatic = Vec4f(0, 0, 0, 1);
128 Shape m_shape1, m_shape2;
129
130 public:
133 m_initialized(false),
134 m_shape1(GL_TRIANGLE_STRIP, m_st, m_pmvMat), m_shape2(GL_LINE_STRIP, m_st, m_pmvMat) { }
135
136 Recti& viewport() noexcept { return m_viewport; }
137 const Recti& viewport() const noexcept { return m_viewport; }
138
139 PMVMat4f& pmv() noexcept { return m_pmvMat.m; }
140 const PMVMat4f& pmv() const noexcept { return m_pmvMat.m; }
141 bool animating() const noexcept { return m_animating; }
142 bool& animating() noexcept { return m_animating; }
143
144 bool init(const WindowRef& win, const jau::fraction_timespec& when) override {
145 jau::fprintf_td(when.to_ms(), stdout, "RL::init: %s\n", toString().c_str());
146 m_tlast = when;
147
148 GL& gl = GL::downcast(win->renderContext());
149 ShaderCodeRef vp0 = ShaderCode::create(gl, GL_VERTEX_SHADER, "demos/glsl",
150 "demos/glsl/bin", "SingleLight0");
151 ShaderCodeRef fp0 = ShaderCode::create(gl, GL_FRAGMENT_SHADER, "demos/glsl",
152 "demos/glsl/bin", "SingleLight0");
153 if( !vp0 || !fp0 ) {
154 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString().c_str());
155 win->dispose(when);
156 return false;
157 }
158 {
159 std::string custom = "#define MAX_TEXTURE_UNITS 0\n";
160 size_t vsPos = vp0->defaultShaderCustomization(gl, true, true);
161 size_t fsPos = fp0->defaultShaderCustomization(gl, true, true);
162 vp0->insertShaderSource(0, vsPos, custom);
163 fp0->insertShaderSource(0, fsPos, custom);
164 }
165
167 if( !sp0->add(gl, vp0, true) || !sp0->add(gl, fp0, true) ) {
168 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString().c_str());
169 sp0->destroy(gl);
170 win->dispose(when);
171 return false;
172 }
173 m_st.attachShaderProgram(gl, sp0, true);
174
175 // setup mgl_PMVMatrix
176 m_pmvMat.m.getP().loadIdentity();
177 m_pmvMat.m.getMv().loadIdentity();
178 m_st.ownUniform(m_pmvMat.u, true);
179
180 GLUniformVec3fRef lightU = GLUniformVec3f::create("gcu_Light0Pos", lightPos);
181 m_st.ownUniform(lightU, true);
182
183 m_st.pushAllUniforms(gl);
184
185 const Vec3f frontNormal(0, 0, 1);
186 const Vec3f backNormal(0, 0, -1);
187 {
188 GLFloatArrayDataServerRef& v = m_shape1.vertices();
189 float dz = 0.001f;
190 v->put3f(-half, half, dz); v->put3f(frontNormal);
191 v->put3f( half, half, dz); v->put3f(frontNormal);
192 v->put3f(-half, -half, dz); v->put3f(frontNormal);
193 v->put3f( half, -half, dz); v->put3f(frontNormal);
194
195 dz = -0.001f;
196 v->put3f(-half, half, dz); v->put3f(backNormal);
197 v->put3f( half, half, dz); v->put3f(backNormal);
198 v->put3f(-half, -half, dz); v->put3f(backNormal);
199 v->put3f( half, -half, dz); v->put3f(backNormal);
200 m_shape1.seal(gl, true);
201 m_shape1.setColor(Vec4f(0, 1, 0, 1));
202 m_shape1.position().x = 1.5f;
203 }
204 {
205 const float lineWidth = 1/10.0f;
206 const float tw = 1.0f;
207 const float th = 1.0f;
208
209 float lwh = lineWidth/2.0f;
210
211 float twh = tw/2.0f;
212 float thh = th/2.0f;
213
214 float ctrX = 0, ctrY = 0;
215 float ctrZ = 0;
216
217 GLFloatArrayDataServerRef& v = m_shape2.vertices();
218 // CCW
219 v->put3f(ctrX-lwh, ctrY+thh, ctrZ); v->put3f(frontNormal); // vert: left-top
220 v->put3f(ctrX-lwh, ctrY+lwh, ctrZ); v->put3f(frontNormal);
221 v->put3f(ctrX-twh, ctrY+lwh, ctrZ); v->put3f(frontNormal); // horz: left-top
222 v->put3f(ctrX-twh, ctrY-lwh, ctrZ); v->put3f(frontNormal); // horz: left-bottom
223 v->put3f(ctrX-lwh, ctrY-lwh, ctrZ); v->put3f(frontNormal);
224 v->put3f(ctrX-lwh, ctrY-thh, ctrZ); v->put3f(frontNormal); // vert: left-bottom
225 v->put3f(ctrX+lwh, ctrY-thh, ctrZ); v->put3f(frontNormal); // vert: right-bottom
226 v->put3f(ctrX+lwh, ctrY-lwh, ctrZ); v->put3f(frontNormal);
227 v->put3f(ctrX+twh, ctrY-lwh, ctrZ); v->put3f(frontNormal); // horz: right-bottom
228 v->put3f(ctrX+twh, ctrY+lwh, ctrZ); v->put3f(frontNormal); // horz: right-top
229 v->put3f(ctrX+lwh, ctrY+lwh, ctrZ); v->put3f(frontNormal);
230 v->put3f(ctrX+lwh, ctrY+thh, ctrZ); v->put3f(frontNormal); // vert: right-top
231 v->put3f(ctrX-lwh, ctrY+thh, ctrZ); v->put3f(frontNormal); // vert: left-top
232 m_shape2.seal(gl, true);
233 m_shape2.setColor(Vec4f(0, 0, 1, 1));
234 m_shape2.position().x = -1.5f;
235 }
236
237 ::glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
238 ::glEnable(GL_DEPTH_TEST);
239
240 m_initialized = sp0->inUse();
241 if( !m_initialized ) {
242 jau::fprintf_td(when.to_ms(), stdout, "ERROR %s:%d: %s\n", E_FILE_LINE, toString().c_str());
243 m_st.destroy(gl);
244 win->dispose(when);
245 }
246 return m_initialized;
247 }
248
249 void dispose(const WindowRef& win, const jau::fraction_timespec& when) override {
250 jau::fprintf_td(when.to_ms(), stdout, "RL::dispose: %s\n", toString().c_str());
251 m_st.destroy(GL::downcast(win->renderContext()));
252 m_initialized = false;
253 }
254
255 void reshape(const WindowRef& win, const jau::math::Recti& viewport, const jau::fraction_timespec& when) override {
256 GL& gl = GL::downcast(win->renderContext());
257 jau::fprintf_td(when.to_ms(), stdout, "RL::reshape: %s\n", toString().c_str());
258 m_viewport = viewport;
259
260 m_pmvMat.m.getP().loadIdentity();
261 const float aspect = 1.0f;
262 const float fovy_deg=45.0f;
263 const float aspect2 = ( (float) m_viewport.width() / (float) m_viewport.height() ) / aspect;
264 m_pmvMat.m.perspectiveP(jau::adeg_to_rad(fovy_deg), aspect2, zNear, zFar);
265 m_st.useProgram(gl, true);
266 m_st.pushUniform(gl, m_pmvMat.u); // automatic sync + update of Mvi + Mvit
267 m_st.useProgram(gl, true);
268 }
269
270 void display(const WindowRef& win, const jau::fraction_timespec& when) override {
271 // jau::fprintf_td(when.to_ms(), stdout, "RL::display: %s, %s\n", toString().c_str(), win->toString().c_str());
272 if( !m_initialized ) {
273 return;
274 }
275 GL& gl = GL::downcast(win->renderContext());
276 ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
277
278 m_st.useProgram(gl, true);
279 m_pmvMat.m.getMv().loadIdentity();
280 m_pmvMat.m.translateMv(0, 0, -5);
281
282 if( animating() ) {
283 constexpr double angle_per_sec = 30;
284 const float rad = (float) ( (when - m_tlast).to_double() * angle_per_sec );
285 m_shape1.rotation().rotateByAngleY(jau::adeg_to_rad( rad ));
286 m_shape2.rotation().rotateByAngleY(jau::adeg_to_rad( -rad ));
287 }
288 m_shape1.draw(gl);
289 m_shape2.draw(gl);
290
291 m_st.useProgram(gl, false);
292
293 m_tlast = when;
294 }
295
296 std::string toStringImpl() const noexcept override { return "Primitives01"; }
297};
298
299class Example : public Primitives01 {
300 private:
301 class MyKeyListener : public KeyListener {
302 private:
303 Primitives01& m_parent;
304 public:
305 MyKeyListener(Primitives01& p) : m_parent(p) {}
306
307 void keyPressed(KeyEvent& e, const KeyboardTracker& kt) override {
308 jau::fprintf_td(e.when().to_ms(), stdout, "KeyPressed: %s; keys %zu\n", e.toString().c_str(), kt.pressedKeyCodes().count());
309 if( e.keySym() == VKeyCode::VK_ESCAPE ) {
310 WindowRef win = e.source().lock();
311 if( win ) {
312 win->dispose(e.when());
313 }
314 } else if( e.keySym() == VKeyCode::VK_PAUSE || e.keySym() == VKeyCode::VK_P ) {
315 m_parent.animating() = !m_parent.animating();
316 } else if( e.keySym() == VKeyCode::VK_W ) {
317 WindowRef win = e.source().lock();
318 jau::fprintf_td(e.when().to_ms(), stdout, "Source: %s\n", win ? win->toString().c_str() : "null");
319 }
320 }
321 void keyReleased(KeyEvent& e, const KeyboardTracker& kt) override {
322 jau::fprintf_td(e.when().to_ms(), stdout, "KeyRelease: %s; keys %zu\n", e.toString().c_str(), kt.pressedKeyCodes().count());
323 }
324 };
325 typedef std::shared_ptr<MyKeyListener> MyKeyListenerRef;
326 MyKeyListenerRef m_kl;
327
328 public:
330 : Primitives01(),
331 m_kl(std::make_shared<MyKeyListener>(*this)) { }
332
333 bool init(const WindowRef& win, const jau::fraction_timespec& when) override {
334 if( !Primitives01::init(win, when) ) {
335 return false;
336 }
337 win->addKeyListener(m_kl);
338 return true;
339 }
340 void dispose(const WindowRef& win, const jau::fraction_timespec& when) override {
341 win->removeKeyListener(m_kl);
342 Primitives01::dispose(win, when);
343 }
344};
345
346int main(int argc, char *argv[]) // NOLINT(bugprone-exception-escape)
347{
349
350 return launch("Primitives01.cpp",
352 std::make_shared<Example>(), argc, argv);
353}
int launch(std::string_view sfile, GLLaunchProps props, const RenderListenerRef &demo, int argc, char *argv[])
int main(int argc, char *argv[])
#define E_FILE_LINE
bool init(const WindowRef &win, const jau::fraction_timespec &when) override
Called by the drawable immediately after the render context is initialized.
void dispose(const WindowRef &win, const jau::fraction_timespec &when) override
Notifies the listener to perform the release of all renderer resources per context,...
void reshape(const WindowRef &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.
PMVMat4f & pmv() noexcept
std::string toStringImpl() const noexcept override
const PMVMat4f & pmv() const noexcept
bool animating() const noexcept
void display(const WindowRef &win, const jau::fraction_timespec &when) override
Called by the drawable to initiate rendering by the client.
const Recti & viewport() const noexcept
bool init(const WindowRef &win, const jau::fraction_timespec &when) override
Called by the drawable immediately after the render context is initialized.
bool & animating() noexcept
Recti & viewport() noexcept
void dispose(const WindowRef &win, const jau::fraction_timespec &when) override
Notifies the listener to perform the release of all renderer resources per context,...
void setColor(const Vec4f &c) noexcept
constexpr const GLFloatArrayDataServerRef & vertices() const noexcept
constexpr Vec3f & position() noexcept
void draw(GL &gl)
constexpr const Quat4f & rotation() const noexcept
Shape(GLenum type, ShaderState &st, PMVMat4fUniform &pmvMatU)
constexpr const Vec3f & position() const noexcept
constexpr GLFloatArrayDataServerRef & vertices() noexcept
const Vec4f & color() const noexcept
void seal(GL &gl, bool seal)
constexpr Quat4f & rotation() noexcept
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
static std::shared_ptr< GLUniformVec3f > create(stringview_t name, const jau::math::Vec3f &v)
static std::shared_ptr< GLUniformVec4f > create(stringview_t name, const jau::math::Vec4f &v)
size_t defaultShaderCustomization(const GL &gl, bool preludeVersion=true, bool addDefaultPrecision=true, bool addDefaultDefines=true)
Default customization of this shader source code.
static ShaderCodeRef create(GLenum type, size_t count, const source_list_t &sources) noexcept
size_t insertShaderSource(size_t shaderIdx, stringview_t tag, size_t fromIndex, stringview_t data) noexcept
Adds data after the line containing tag.
void destroy(GL &gl) noexcept
Detaches all shader codes and deletes the program.
static ShaderProgramRef create() noexcept
bool add(const ShaderCodeRef &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:129
size_t removeKeyListener(const KeyListenerRef &l)
Definition Window.hpp:311
void dispose(const jau::fraction_timespec &when) noexcept override
Definition Window.hpp:355
std::string toString() const noexcept
Definition gamp_wt.cpp:145
void addKeyListener(const KeyListenerRef &l)
Definition Window.hpp:310
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:359
constexpr T adeg_to_rad(const T arc_degree) noexcept
Converts arc-degree to radians.
GLArrayDataServer< float > GLFloatArrayDataServer
GLArrayDataServerRef< float > GLFloatArrayDataServerRef
std::shared_ptr< GLUniformData > GLUniformDataRef
std::shared_ptr< GLUniformVec4f > GLUniformVec4fRef
std::shared_ptr< GLUniformVec3f > GLUniformVec3fRef
std::shared_ptr< ShaderProgram > ShaderProgramRef
std::shared_ptr< ShaderCode > ShaderCodeRef
@ verbose
Verbose operations (debugging).
std::shared_ptr< Window > WindowRef
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
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
Definition debug.cpp:276
STL namespace.
GLUniformDataRef u
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.