olcPixelGameEngine v2.29
The official distribution of olcPixelGameEngine, a tool used in javidx9's YouTube videos and projects
Loading...
Searching...
No Matches
olcPGEX_Shaders.h
Go to the documentation of this file.
1/*
2 olcPGEX_Shaders.h
3
4 +-------------------------------------------------------------+
5 | OneLoneCoder Pixel Game Engine Extension |
6 | Shaders v1.00 |
7 +-------------------------------------------------------------+
8
9 NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES - VERY UNFINISHED
10 SIMPLY PUT - DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING :P
11
12 What is this?
13 ~~~~~~~~~~~~~
14 This is an "unfinished" extension that allows you to render to decals
15 via a genuine GPU pixel shader. It has all sorts of caveats. Do not use.
16
17 License (OLC-3)
18 ~~~~~~~~~~~~~~~
19
20 Copyright 2018 - 2025 OneLoneCoder.com
21
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions
24 are met:
25
26 1. Redistributions or derivations of source code must retain the above
27 copyright notice, this list of conditions and the following disclaimer.
28
29 2. Redistributions or derivative works in binary form must reproduce
30 the above copyright notice. This list of conditions and the following
31 disclaimer must be reproduced in the documentation and/or other
32 materials provided with the distribution.
33
34 3. Neither the name of the copyright holder nor the names of its
35 contributors may be used to endorse or promote products derived
36 from this software without specific prior written permission.
37
38 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49
50 Links
51 ~~~~~
52 YouTube: https://www.youtube.com/javidx9
53 Discord: https://discord.gg/WhwHUMV
54 Twitter: https://www.twitter.com/javidx9
55 Twitch: https://www.twitch.tv/javidx9
56 GitHub: https://www.github.com/onelonecoder
57 Homepage: https://www.onelonecoder.com
58
59 Author
60 ~~~~~~
61 David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024, 2025
62
63 Revisions:
64 1.00: Initial Release
65
66*/
67
68#pragma once
69#ifndef OLC_PGEX_SHADER_H
70#define OLC_PGEX_SHADER_H
71
72#if !defined(OLC_GFX_OPENGL33)
73#error The olc::Shader Extension requires the OpenGL 3.3 Renderer to be specified!
74#endif
75
76#if !defined(OLC_USING_PGEX_SHADER)
77#define OLC_USING_PGEX_SHADER
78#endif
79
80
81#define OLC_GFX_OPENGL33
82#include "olcPixelGameEngine.h"
83
84namespace olc
85{
87 {
88 const std::string sVertexSource;
89 const std::string sPixelSource;
90 const size_t nInputs;
91 const size_t nOutputs;
92 const std::vector<std::tuple<std::string, std::string, std::string>> vAttributes;
93 };
94
95
96 namespace fx
97 {
98
99#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN)
100#define SHADER_HEADER "#version 300 es \n" \
101 "precision mediump float;\n"
102#else
103#define SHADER_HEADER "#version 330 core \n"
104#endif
105
106
107#define DEFAULT_VS "void main() \n" \
108 "{ \n" \
109 " float p = 1.0 / inPos.z; \n" \
110 " gl_Position = p * vec4(inPos.x, inPos.y, 0.0, 1.0); \n" \
111 " xUV1 = p * inUV1; \n" \
112 " xCol = inCol; \n" \
113 "} \n"
114
115#define DEFAULT_PS "void main() \n" \
116 "{ \n" \
117 " pix_out = texture(tex1, xUV1) * xCol; \n" \
118 "} \n"
119
120 static EffectConfig FX_NORMAL =
121 {
124 1,
125 1
126 };
127
128 static EffectConfig FX_GREYSCALE =
129 {
131 "void main() \n"
132 "{ \n"
133 " vec4 o = texture(tex1, xUV1) * xCol; \n"
134 " float lum = o.r * 0.2126 + o.g * 0.7152 + o.b * 0.0722; \n"
135 " pix_out = vec4(lum, lum, lum, o.a); \n"
136 "} \n",
137 1,
138 1
139 };
140
141 static EffectConfig FX_BOXBLUR =
142 {
144
145 "void main() \n"
146 "{ \n"
147 " vec2 texelSize = 1.0 / vec2(textureSize(tex1, 0)); \n"
148 " vec4 result; \n"
149 " for (int x = -box_width; x < +box_width; ++x) \n"
150 " { \n"
151 " for (int y = -box_width; y < +box_width; ++y) \n"
152 " { \n"
153 " vec2 offset = vec2(float(x), float(y)) * texelSize; \n"
154 " result += texture(tex1, xUV1 + offset); \n"
155 " } \n"
156 " } \n"
157 " pix_out = (result / (4.0 * float(box_width * box_width))) * xCol; \n"
158 "} \n",
159 1,
160 1,
161
162 {
163 {"box_width", "int", "4"},
164 }
165 };
166
167 static EffectConfig FX_THRESHOLD =
168 {
170
171 "void main() \n"
172 "{ \n"
173 " vec4 o = texture(tex1, xUV1) * xCol; \n"
174 " float lum = o.r * 0.2126 + o.g * 0.7152 + o.b * 0.0722; \n"
175 " pix_out = (lum > threshold) ? vec4(1, 1, 1, 1) : vec4(0,0,0,1); \n"
176 "} \n",
177 1,
178 1,
179
180 {
181 {"threshold", "float", "0.5"},
182 }
183 };
184
185
186 static EffectConfig FX_SCANLINE =
187 {
189
190 "void main() \n"
191 "{ \n"
192 " float scanline = sin(xUV1.y * frequency + phase) * intensity; \n"
193 " pix_out = (texture(tex1, xUV1) + vec4(scanline, scanline, scanline, 0.0)) * xCol; \n"
194 "} \n",
195 1,
196 1,
197 {
198 {"frequency", "float", "400.0"},
199 {"intensity", "float","0.4"},
200 {"phase", "float", "0.0"}
201 }
202 };
203
204
205 static EffectConfig FX_SOBEL =
206 {
208
209 "void make_kernel(inout vec4 n[9], sampler2D tex, vec2 coord) \n"
210 "{ \n"
211 " vec2 texel = 1.0 / vec2(textureSize(tex, 0)); \n"
212 " \n"
213 " \n"
214 " n[0] = texture2D(tex, coord + vec2(-texel.x, -texel.y)); \n"
215 " n[1] = texture2D(tex, coord + vec2(0.0, -texel.y)); \n"
216 " n[2] = texture2D(tex, coord + vec2(texel.x, -texel.y)); \n"
217 " n[3] = texture2D(tex, coord + vec2(-texel.x, 0.0)); \n"
218 " n[4] = texture2D(tex, coord); \n"
219 " n[5] = texture2D(tex, coord + vec2(texel.x, 0.0)); \n"
220 " n[6] = texture2D(tex, coord + vec2(-texel.x, texel.y)); \n"
221 " n[7] = texture2D(tex, coord + vec2(0.0, texel.y)); \n"
222 " n[8] = texture2D(tex, coord + vec2(texel.x, texel.y)); \n"
223 "} \n"
224 " \n"
225 "void main(void) \n"
226 "{ \n"
227 " vec4 n[9]; \n"
228 " make_kernel(n, tex1, xUV1); \n"
229 " \n"
230 " vec4 sobel_edge_h = n[2] + (2.0 * n[5]) + n[8] - (n[0] + (2.0 * n[3]) + n[6]); \n"
231 " vec4 sobel_edge_v = n[0] + (2.0 * n[1]) + n[2] - (n[6] + (2.0 * n[7]) + n[8]); \n"
232 " vec4 sobel = sqrt((sobel_edge_h * sobel_edge_h) + (sobel_edge_v * sobel_edge_v)); \n"
233 " \n"
234 " pix_out = vec4(1.0 - sobel.rgb, 1.0); \n"
235 "} \n",
236 1,
237 1,
238 };
239
240
241
242 }
243
244
245 class Effect
246 {
247 public:
248 Effect() = default;
249
250 public:
251 bool IsOK() const;
252 const std::string& GetStatus() const;
253 const uint32_t GetTargetSlots() const;
254 const uint32_t GetInputSlots() const;
255
256 protected:
257 friend class Shade;
258 void AppendStatus(const std::string& sMsg);
259 void SetResourceIDs(const uint32_t id, const uint32_t vsid, const uint32_t psid);
260 void SetSlots(const uint32_t nInput, const uint32_t nTarget);
261
262 protected:
263 std::string m_sStatus;
264 uint32_t m_nPSID = 0;
265 uint32_t m_nVSID = 0;
266 uint32_t m_nID = 0;
267 uint32_t m_nInputSlots = 0;
268 uint32_t m_nTargetSlots = 0;
269 };
270
271 class Shade : public olc::PGEX
272 {
273 friend class olc::Effect;
274
275 public:
277
278 public:
280
281 public:
282 int32_t SetSourceDecal(olc::Decal* pDecal, const uint32_t nSlot = 0, const olc::vf2d& vSourcePos = { 0.0f, 0.0f }, const olc::vf2d& vSourceSize = { 1.0f, 1.0f });
283 int32_t SetTargetDecal(olc::Decal* pDecal, const uint32_t nSlot = 0);
284 int32_t Start(olc::Effect* pEffect);
285 int32_t End();
286
287 public: // Simplified Interface
288 void Clear(const olc::Pixel& p = olc::BLANK);
289 void DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE);
290 void DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
291 void DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
292 void DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& colours);
293
294
295
296 public: // Advanced Interface
297 int32_t DrawQuad(const olc::vf2d& vPos, const olc::vf2d& vSize);
298
299 private:
300
301 struct sResourceSlot
302 {
303 bool bInUse = false;
304 int nTargetResID = 0;
305 olc::vf2d vPos = { 0.0f, 0.0f };
306 olc::vf2d vSize = { 1.0f, 1.0f };
307 olc::vf2d vInvSize = { 1.0f, 1.0f };
308 };
309
310 std::array<sResourceSlot, 8> slotTarget;
311 std::array<sResourceSlot, 8> slotSource;
312
313
314 struct sOmniVertex
315 {
316 float pos[3];
317 olc::Pixel col;
318 olc::vf2d tex[8];
319 };
320
321 uint32_t m_nVB = 0;
322 uint32_t m_nVA = 0;
323
324 sOmniVertex pVertexMem[olc::OLC_MAX_VERTS];
325
326 uint32_t m_nFBO = 0;
327 uint32_t m_nEffectID = 0;
328
329 int32_t RenderDecal();
330
331 void Render(const olc::DecalInstance& decal);
332
333 void RenderPolygon(
334 const std::vector<olc::Decal*>& decals, // Source Textures
335 const std::vector<olc::vf2d>& pos, // Vertex positions
336 const std::vector<olc::vf2d>& uv, // Texture Coords
337 const std::vector<olc::Pixel>& colours, // Vertex Colours
338 const olc::DecalStructure& structure); // Primitive
339
340 void ClearAllSlots();
341
342 olc::Effect ConstructShader(const std::string& sVS, const std::string& sPS);
343
344 private: // Local OpenGL Functions
345 locCreateShader_t* locCreateShader = nullptr;
346 locShaderSource_t* locShaderSource = nullptr;
347 locCompileShader_t* locCompileShader = nullptr;
348 locDeleteShader_t* locDeleteShader = nullptr;
349 locCreateProgram_t* locCreateProgram = nullptr;
350 locDeleteProgram_t* locDeleteProgram = nullptr;
351 locLinkProgram_t* locLinkProgram = nullptr;
352 locAttachShader_t* locAttachShader = nullptr;
353 locBindBuffer_t* locBindBuffer = nullptr;
354 locBufferData_t* locBufferData = nullptr;
355 locGenBuffers_t* locGenBuffers = nullptr;
356 locVertexAttribPointer_t* locVertexAttribPointer = nullptr;
357 locEnableVertexAttribArray_t* locEnableVertexAttribArray = nullptr;
358 locUseProgram_t* locUseProgram = nullptr;
359 locBindVertexArray_t* locBindVertexArray = nullptr;
360 locGenVertexArrays_t* locGenVertexArrays = nullptr;
361 locSwapInterval_t* locSwapInterval = nullptr;
362 locGetShaderInfoLog_t* locGetShaderInfoLog = nullptr;
363 locGetUniformLocation_t* glGetUniformLocation = nullptr;
364 locUniform1f_t* locUniform1f = nullptr;
365 locUniform1i_t* locUniform1i = nullptr;
366 locUniform2fv_t* locUniform2fv = nullptr;
367 locGenFrameBuffers_t* locGenFrameBuffers = nullptr;
368 locBindFrameBuffer_t* locBindFrameBuffer = nullptr;
369 locCheckFrameBufferStatus_t* locCheckFrameBufferStatus = nullptr;
370 locDeleteFrameBuffers_t* locDeleteFrameBuffers = nullptr;
371 locFrameBufferTexture2D_t* locFrameBufferTexture2D = nullptr;
372 locActiveTexture_t* locActiveTexture = nullptr;
373 locDrawBuffers_t* locDrawBuffers = nullptr;
374 locBlendFuncSeparate_t* locBlendFuncSeparate = nullptr;
375
376 olc::Renderable dummyTex;
377
378 protected:
379 void OnBeforeUserCreate() override;
380
381 };
382}
383
384
385#ifdef OLC_PGEX_SHADERS
386#undef OLC_PGEX_SHADERS
387
388namespace olc
389{
390 void Effect::SetSlots(const uint32_t nInput, const uint32_t nTarget)
391 {
392 m_nTargetSlots = nTarget;
393 m_nInputSlots = nInput;
394 }
395
396 const uint32_t Effect::GetTargetSlots() const
397 {
398 return m_nTargetSlots;
399 }
400
401 const uint32_t Effect::GetInputSlots() const
402 {
403 return m_nInputSlots;
404 }
405
406 bool Effect::IsOK() const
407 {
408 return m_sStatus.empty();
409 }
410
411 const std::string& Effect::GetStatus() const
412 {
413 return m_sStatus;
414 }
415
416 void Effect::AppendStatus(const std::string& sMsg)
417 {
418 m_sStatus.append(sMsg);
419 }
420
421 void Effect::SetResourceIDs(const uint32_t id, const uint32_t vsid, const uint32_t psid)
422 {
423 m_nID = id;
424 m_nVSID = vsid;
425 m_nPSID = psid;
426 }
427
428
429 Shade::Shade() : PGEX(true)
430 {
431
432 }
433
434
435 olc::Effect Shade::ConstructShader(const std::string& sVS, const std::string& sPS)
436 {
437 olc::Effect effect;
438
439 char sError[512];
440 GLsizei nLogSize = 0;
441
442 // Vertex Shader
443 GLuint vs_id = locCreateShader(0x8B31);
444 const GLchar* vs_str = sVS.c_str();
445 locShaderSource(vs_id, 1, &vs_str, NULL);
446 locCompileShader(vs_id);
447
448 // Check for errors
449 locGetShaderInfoLog(vs_id, 512, &nLogSize, sError);
450 if (nLogSize > 0)
451 {
452 effect.AppendStatus(std::string(sError, nLogSize));
453 }
454
455 // Pixel Shader
456 GLuint ps_id = locCreateShader(0x8B30);
457 const GLchar* ps_str = sPS.c_str();
458 locShaderSource(ps_id, 1, &ps_str, NULL);
459 locCompileShader(ps_id);
460
461 // Check for errors
462 locGetShaderInfoLog(ps_id, 512, &nLogSize, sError);
463 if (nLogSize > 0)
464 {
465 effect.AppendStatus(std::string(sError, nLogSize));
466 }
467
468 // Combined Shader
469 GLuint sh_id = locCreateProgram();
470 locAttachShader(sh_id, ps_id);
471 locAttachShader(sh_id, vs_id);
472 locLinkProgram(sh_id);
473
474 // Check for errors
475 locGetShaderInfoLog(sh_id, 512, &nLogSize, sError);
476 if (nLogSize > 0)
477 {
478 effect.AppendStatus(std::string(sError, nLogSize));
479 }
480
481 // Store resources in shader object
482 effect.SetResourceIDs(sh_id, vs_id, ps_id);
483 return effect;
484 }
485
486
488 {
489 // Construct Vertex Shader
490 std::string sVertexShader =
492 "layout(location = 0) in vec3 inPos; \n"
493 "layout(location = 1) in vec4 inCol; \n";
494
495 for (size_t i = 0; i < premade.nInputs; i++)
496 {
497 sVertexShader.append("layout(location = " + std::to_string(2 + i) + ") in vec2 inUV" + std::to_string(1 + i) + "; \n");
498 }
499
500 for (size_t i = 0; i < premade.nInputs; i++)
501 {
502 sVertexShader.append("out vec2 xUV" + std::to_string(1 + i) + "; \n");
503 }
504
505 sVertexShader.append("out vec4 xCol; \n");
506 sVertexShader.append(premade.sVertexSource);
507
508
509 // Construct Pixel Shader
510 std::string sPixelShader =
512 "in vec4 xCol; \n";
513
514 for (size_t i = 0; i < premade.nInputs; i++)
515 {
516 sPixelShader.append("in vec2 xUV" + std::to_string(1 + i) + "; \n");
517 }
518
519 for (size_t i = 0; i < premade.nInputs; i++)
520 {
521 sPixelShader.append("uniform sampler2D tex" + std::to_string(1 + i) + ";\n");
522 }
523
524 for (const auto& attribute : premade.vAttributes)
525 {
526 sPixelShader.append("uniform " + std::get<1>(attribute) + " " + std::get<0>(attribute) + " = " + std::get<2>(attribute) + ";\n");
527 }
528
529 sPixelShader.append("out vec4 pix_out;\n");
530 sPixelShader.append(premade.sPixelSource);
531
532 olc::Effect effect = ConstructShader(sVertexShader, sPixelShader);
533 effect.SetSlots(uint32_t(premade.nInputs), uint32_t(premade.nOutputs));
534 return effect;
535 }
536
537
539 {
540 // Load External OpenGL Functions
541 locCreateShader = OGL_LOAD(locCreateShader_t, glCreateShader);
542 locCompileShader = OGL_LOAD(locCompileShader_t, glCompileShader);
543 locShaderSource = OGL_LOAD(locShaderSource_t, glShaderSource);
544 locDeleteShader = OGL_LOAD(locDeleteShader_t, glDeleteShader);
545 locCreateProgram = OGL_LOAD(locCreateProgram_t, glCreateProgram);
546 locDeleteProgram = OGL_LOAD(locDeleteProgram_t, glDeleteProgram);
547 locLinkProgram = OGL_LOAD(locLinkProgram_t, glLinkProgram);
548 locAttachShader = OGL_LOAD(locAttachShader_t, glAttachShader);
549 locBindBuffer = OGL_LOAD(locBindBuffer_t, glBindBuffer);
550 locBufferData = OGL_LOAD(locBufferData_t, glBufferData);
551 locGenBuffers = OGL_LOAD(locGenBuffers_t, glGenBuffers);
552 locVertexAttribPointer = OGL_LOAD(locVertexAttribPointer_t, glVertexAttribPointer);
553 locEnableVertexAttribArray = OGL_LOAD(locEnableVertexAttribArray_t, glEnableVertexAttribArray);
554 locUseProgram = OGL_LOAD(locUseProgram_t, glUseProgram);
555 locGetShaderInfoLog = OGL_LOAD(locGetShaderInfoLog_t, glGetShaderInfoLog);
556
557
558 locGenFrameBuffers = OGL_LOAD(locGenFrameBuffers_t, glGenFramebuffers);
559 locBindFrameBuffer = OGL_LOAD(locBindFrameBuffer_t, glBindFramebuffer);
560 locCheckFrameBufferStatus = OGL_LOAD(locCheckFrameBufferStatus_t, glCheckFramebufferStatus);
561 locDeleteFrameBuffers = OGL_LOAD(locDeleteFrameBuffers_t, glDeleteFramebuffers);
562 locFrameBufferTexture2D = OGL_LOAD(locFrameBufferTexture2D_t, glFramebufferTexture2D);
563 locActiveTexture = OGL_LOAD(locActiveTexture_t, glActiveTexture);
564
565 locBlendFuncSeparate = OGL_LOAD(locBlendFuncSeparate_t, glBlendFuncSeparate);
566
567#if !defined(OLC_PLATFORM_EMSCRIPTEN)
568 locBindVertexArray = OGL_LOAD(locBindVertexArray_t, glBindVertexArray);
569 locGenVertexArrays = OGL_LOAD(locGenVertexArrays_t, glGenVertexArrays);
570 locDrawBuffers = OGL_LOAD(locDrawBuffers_t, glDrawBuffers);
571#else
572 locBindVertexArray = glBindVertexArrayOES;
573 locGenVertexArrays = glGenVertexArraysOES;
574 locDrawBuffers = glDrawBuffersNV;
575#endif
576
577
578
579 // Create a Frame Buffer Object that represents the
580 // offscreen rendering target gubbins
581 locGenFrameBuffers(1, (GLuint*)&m_nFBO);
582
583 // Create a Vertex object to represent polygons
584 locGenBuffers(1, &m_nVB);
585 locGenVertexArrays(1, &m_nVA);
586 locBindVertexArray(m_nVB);
587
588 locBindBuffer(0x8892, m_nVB);
589 sOmniVertex verts[OLC_MAX_VERTS];
590 locBufferData(0x8892, sizeof(sOmniVertex) * OLC_MAX_VERTS, verts, 0x88E0);
591
592 locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(0 * sizeof(float)));
593 locVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(sOmniVertex), (void*)(3 * sizeof(float)));
594 locVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(4 * sizeof(float)));
595 locVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(6 * sizeof(float)));
596 locVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(8 * sizeof(float)));
597 locVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(10 * sizeof(float)));
598 locVertexAttribPointer(6, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(12 * sizeof(float)));
599 locVertexAttribPointer(7, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(14 * sizeof(float)));
600 locVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(16 * sizeof(float)));
601 locVertexAttribPointer(9, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(18 * sizeof(float)));
602
603 locEnableVertexAttribArray(0); // Pos
604 locEnableVertexAttribArray(1); // Colour
605 locEnableVertexAttribArray(2); // Tex 0
606 locEnableVertexAttribArray(3); // Tex 1
607 locEnableVertexAttribArray(4); // Tex 2
608 locEnableVertexAttribArray(5); // Tex 3
609 locEnableVertexAttribArray(6); // Tex 4
610 locEnableVertexAttribArray(7); // Tex 5
611 locEnableVertexAttribArray(8); // Tex 6
612 locEnableVertexAttribArray(9); // Tex 7
613
614 locBindBuffer(0x8892, 0);
615 locBindVertexArray(0);
616
617 dummyTex.Create(1, 1);
618 dummyTex.Sprite()->GetData()[0] = olc::WHITE;
619 dummyTex.Decal()->Update();
620 }
621
622 void Shade::ClearAllSlots()
623 {
624 slotTarget[0] = { false, 0, {0.0f, 0.0f}, {1.0f, 1.0f} };
625 }
626
627 int32_t Shade::SetSourceDecal(olc::Decal* pDecal, const uint32_t nSlot, const olc::vf2d& vSourcePos, const olc::vf2d& vSourceSize)
628 {
629 if (pDecal == nullptr)
630 {
631 slotSource[nSlot] = { false, dummyTex.Decal()->id, {0.0f, 0.0f}, {1.0f, 1.0f} };
632 }
633 else
634 {
635 slotSource[nSlot].bInUse = true;
636 slotSource[nSlot].nTargetResID = pDecal->id;
637 slotSource[nSlot].vPos = vSourcePos;
638 slotSource[nSlot].vSize = vSourceSize;
639 }
640
641 locActiveTexture(0x84C0); // TODO
642 glBindTexture(GL_TEXTURE_2D, slotSource[nSlot].nTargetResID);
643 return 0;
644 }
645
646 int32_t Shade::SetTargetDecal(olc::Decal* pDecal, const uint32_t nSlot)
647 {
648 slotTarget[nSlot].bInUse = true;
649 slotTarget[nSlot].nTargetResID = pDecal->id;
650 slotTarget[nSlot].vSize = olc::vi2d{ pDecal->sprite->width, pDecal->sprite->height };
651 slotTarget[nSlot].vInvSize = 1.0f / slotTarget[nSlot].vSize;
652 return 0;
653 }
654
655 int32_t Shade::Start(olc::Effect* pEffect)
656 {
657 // Reconstruct frame buffer
658 locBindFrameBuffer(36160U, m_nFBO);
659
660 std::array<GLenum, 8> attachments =
661 { { 36064U, 36065U, 36066U, 36067U, 36068U, 36069U, 36070U, 36071U } };
662
663 // Remove existing buffer links
664 for (const auto& a : attachments)
665 {
666 locFrameBufferTexture2D(36160U, a, GL_TEXTURE_2D, 0, 0);
667 }
668
669 // Count Target slots in use from beginning
670 int nTargetSlots = 0;
671 while (slotTarget[nTargetSlots].nTargetResID > 0)
672 nTargetSlots++;
673
674 // Allocate target buffers
675 locDrawBuffers(nTargetSlots, attachments.data());
676
677 // Bind buffers to texture resources
678 for (uint32_t i = 0; i < pEffect->GetTargetSlots(); i++)
679 {
680 locFrameBufferTexture2D(36160U, attachments[i], GL_TEXTURE_2D, slotTarget[i].nTargetResID, 0);
681 }
682
683 // Apply Effect
684 locUseProgram(pEffect->m_nID);
685
686 // Set vertex stream source
687 locBindVertexArray(m_nVA);
688
689 glDisable(GL_DEPTH_TEST);
690 glDisable(GL_CULL_FACE);
691 //glEnable(GL_BLEND);
692 //locBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
693 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
694
695
696#if defined(OLC_PLATFORM_EMSCRIPTEN)
697 locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), 0); locEnableVertexAttribArray(0);
698 locVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(sOmniVertex), (void*)(3 * sizeof(float))); locEnableVertexAttribArray(1);
699 locVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(sOmniVertex), (void*)(5 * sizeof(float))); locEnableVertexAttribArray(2);
700#endif
701
702 glViewport(0, 0, int32_t(slotTarget[0].vSize.x), int32_t(slotTarget[0].vSize.y));
703
704 return 0;
705 }
706
707 int32_t Shade::End()
708 {
709 // Unbind the frame buffer
710 locBindBuffer(0x8892, 0);
711 locBindVertexArray(0);
712 locUseProgram(0);
713 locBindFrameBuffer(36160U, 0);
714 return 0;
715 }
716
717
718 int32_t Shade::DrawQuad(const olc::vf2d& vPos, const olc::vf2d& vSize)
719 {
720 locBindBuffer(0x8892, m_nVB);
721
722 pVertexMem[0].pos[0] = vPos.x;
723 pVertexMem[0].pos[1] = vPos.y;
724 pVertexMem[0].pos[2] = 1.0f;
725 pVertexMem[0].tex[0] = { 0.0f, 0.0f };
726 pVertexMem[0].col = olc::WHITE;
727
728 pVertexMem[1].pos[0] = vPos.x;
729 pVertexMem[1].pos[1] = vPos.y + vSize.y;
730 pVertexMem[1].pos[2] = 1.0f;
731 pVertexMem[1].tex[0] = { 0.0f, 1.0f };
732 pVertexMem[1].col = olc::WHITE;
733
734 pVertexMem[2].pos[0] = vPos.x + vSize.x;
735 pVertexMem[2].pos[1] = vPos.y + vSize.y;
736 pVertexMem[2].pos[2] = 1.0f;
737 pVertexMem[2].tex[0] = { 1.0f, 1.0f };
738 pVertexMem[2].col = olc::WHITE;
739
740 pVertexMem[3].pos[0] = vPos.x + vSize.x;
741 pVertexMem[3].pos[1] = vPos.y;
742 pVertexMem[3].pos[2] = 1.0f;
743 pVertexMem[3].tex[0] = { 1.0f, 0.0f };
744 pVertexMem[3].col = olc::WHITE;
745
746
747 locBufferData(0x8892, sizeof(sOmniVertex) * 4, pVertexMem, 0x88E0);
748
749 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
750
751 return 0;
752 }
753
754
755 void Shade::Clear(const olc::Pixel& p)
756 {
757 glClearColor(float(p.r) / 255.0f, float(p.g) / 255.0f, float(p.b) / 255.0f, float(p.a) / 255.0f);
758 glClear(GL_COLOR_BUFFER_BIT);
759 }
760
761
762
763 void Shade::DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale, const olc::Pixel& tint)
764 {
765 olc::vf2d vScreenSpacePos =
766 {
767 (std::floor(pos.x) * slotTarget[0].vInvSize.x) * 2.0f - 1.0f,
768 ((std::floor(pos.y) * slotTarget[0].vInvSize.y) * 2.0f - 1.0f),
769 };
770
771 olc::vf2d vScreenSpaceDim =
772 {
773 vScreenSpacePos.x + (2.0f * (float(decal->sprite->width) * slotTarget[0].vInvSize.x)) * scale.x,
774 vScreenSpacePos.y + (2.0f * (float(decal->sprite->height) * slotTarget[0].vInvSize.y)) * scale.y
775 };
776
777 SetSourceDecal(decal, 0);
778
779 DecalInstance di;
780 di.decal = decal;
781 di.points = 4;
782 di.tint = { tint, tint, tint, tint };
783 di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
784 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
785 di.w = { 1, 1, 1, 1 };
786 Render(di);
787 }
788
789 void Shade::DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint)
790 {
791 olc::vf2d vScreenSpacePos =
792 {
793 (std::floor(pos.x) * slotTarget[0].vInvSize.x) * 2.0f - 1.0f,
794 ((std::floor(pos.y) * slotTarget[0].vInvSize.y) * 2.0f - 1.0f)
795 };
796
797 olc::vf2d vScreenSpaceDim =
798 {
799 vScreenSpacePos.x + (2.0f * source_size.x * slotTarget[0].vInvSize.x) * scale.x,
800 vScreenSpacePos.y + (2.0f * source_size.y * slotTarget[0].vInvSize.y) * scale.y
801 };
802
803 SetSourceDecal(decal, 0);
804
805 DecalInstance di;
806 di.points = 4;
807 di.decal = decal;
808 di.tint = { tint, tint, tint, tint };
809 di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
810 olc::vf2d uvtl = source_pos * decal->vUVScale;
811 olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale);
812 di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
813 di.w = { 1,1,1,1 };
814 Render(di);
815 }
816
817 void Shade::DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
818 {
819 olc::vf2d vScreenSpacePos =
820 {
821 (std::floor(pos.x) * slotTarget[0].vInvSize.x) * 2.0f - 1.0f,
822 ((std::floor(pos.y) * slotTarget[0].vInvSize.y) * 2.0f - 1.0f)
823 };
824
825 olc::vf2d vScreenSpaceDim =
826 {
827 vScreenSpacePos.x + (2.0f * source_size.x * slotTarget[0].vInvSize.x),
828 vScreenSpacePos.y + (2.0f * source_size.y * slotTarget[0].vInvSize.y)
829 };
830
831 SetSourceDecal(decal, 0);
832
833 DecalInstance di;
834 di.points = 4;
835 di.decal = decal;
836 di.tint = { tint, tint, tint, tint };
837 di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
838 olc::vf2d uvtl = (source_pos)*decal->vUVScale;
839 olc::vf2d uvbr = uvtl + ((source_size)*decal->vUVScale);
840 di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
841 di.w = { 1,1,1,1 };
842 Render(di);
843 }
844
845 void Shade::DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& colours)
846 {
847 // Assumed points are normalised, transform points into target space
848 std::vector<olc::vf2d> vTransformedPos(pos.size());
849 std::transform(pos.begin(), pos.end(), vTransformedPos.begin(),
850 [this](const olc::vf2d& pin)
851 {
852 return (pin);
853 });
854
855 RenderPolygon({ decal }, vTransformedPos, uv, colours, DecalStructure::FAN);
856 }
857
858 void Shade::RenderPolygon(
859 const std::vector<olc::Decal*>& decals, // Source Textures
860 const std::vector<olc::vf2d>& pos, // Vertex positions
861 const std::vector<olc::vf2d>& uv, // Texture Coords
862 const std::vector<olc::Pixel>& colours, // Vertex Colours
863 const olc::DecalStructure& structure) // Primitive
864 {
865 // Setup multi-texture sources
866 for (size_t i = 0; i < decals.size(); i++)
867 SetSourceDecal(decals[i], uint32_t(i));
868
869 // Populate vertex buffer (note for now, texture coords are shared)
870 for (uint32_t i = 0; i < pos.size(); i++)
871 {
872 pVertexMem[i].pos[0] = pos[i].x;
873 pVertexMem[i].pos[1] = pos[i].y;
874 pVertexMem[i].pos[2] = 1.0f;
875 pVertexMem[i].tex[0] = uv[i];
876 pVertexMem[i].col = colours[i];
877 }
878
879 // Bind vertex buffer
880 locBindBuffer(0x8892, m_nVB);
881
882 // Send to GPU
883 locBufferData(0x8892, sizeof(sOmniVertex) * pos.size(), pVertexMem, 0x88E0);
884
885 // Draw!
886 switch (structure)
887 {
889 glDrawArrays(GL_TRIANGLE_FAN, 0, GLsizei(pos.size()));
890 break;
892 glDrawArrays(GL_TRIANGLES, 0, GLsizei(pos.size()));
893 break;
895 glDrawArrays(GL_TRIANGLE_STRIP, 0, GLsizei(pos.size()));
896 break;
897 }
898 }
899
900
901 void Shade::Render(const olc::DecalInstance& decal)
902 {
903 locBindBuffer(0x8892, m_nVB);
904
905 for (uint32_t i = 0; i < decal.points; i++)
906 {
907 pVertexMem[i].pos[0] = decal.pos[i].x;
908 pVertexMem[i].pos[1] = decal.pos[i].y;
909 pVertexMem[i].pos[2] = decal.w[i];
910 pVertexMem[i].tex[0] = { decal.uv[i].x, decal.uv[i].y };
911 pVertexMem[i].col = decal.tint[i];
912 }
913
914
915 locBufferData(0x8892, sizeof(sOmniVertex) * decal.points, pVertexMem, 0x88E0);
916 glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points);
917 }
918}
919
920#endif // OLC_PGEX_SHADER
921#endif // OLC_PGEX_SHADER_H
Definition olcPixelGameEngine.h:1113
int32_t id
Definition olcPixelGameEngine.h:1122
olc::Sprite * sprite
Definition olcPixelGameEngine.h:1123
void Update()
olc::vf2d vUVScale
Definition olcPixelGameEngine.h:1124
Definition olcPGEX_Shaders.h:246
uint32_t m_nInputSlots
Definition olcPGEX_Shaders.h:267
uint32_t m_nPSID
Definition olcPGEX_Shaders.h:264
uint32_t m_nVSID
Definition olcPGEX_Shaders.h:265
uint32_t m_nTargetSlots
Definition olcPGEX_Shaders.h:268
bool IsOK() const
void SetResourceIDs(const uint32_t id, const uint32_t vsid, const uint32_t psid)
Effect()=default
const uint32_t GetTargetSlots() const
const uint32_t GetInputSlots() const
void SetSlots(const uint32_t nInput, const uint32_t nTarget)
const std::string & GetStatus() const
std::string m_sStatus
Definition olcPGEX_Shaders.h:263
void AppendStatus(const std::string &sMsg)
uint32_t m_nID
Definition olcPGEX_Shaders.h:266
Definition olcPixelGameEngine.h:1685
Definition olcPixelGameEngine.h:1149
void Create(uint32_t width, uint32_t height, bool filter=false, bool clamp=true)
olc::Sprite * Sprite() const
olc::Decal * Decal() const
Definition olcPGEX_Shaders.h:272
olc::Effect MakeEffect(const olc::EffectConfig &premade)
void DrawDecal(const olc::vf2d &pos, olc::Decal *decal, const olc::vf2d &scale={ 1.0f, 1.0f }, const olc::Pixel &tint=olc::WHITE)
void DrawPolygonDecal(olc::Decal *decal, const std::vector< olc::vf2d > &pos, const std::vector< olc::vf2d > &uv, const std::vector< olc::Pixel > &colours)
void DrawPartialDecal(const olc::vf2d &pos, const olc::vf2d &size, olc::Decal *decal, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::Pixel &tint=olc::WHITE)
int32_t SetSourceDecal(olc::Decal *pDecal, const uint32_t nSlot=0, const olc::vf2d &vSourcePos={ 0.0f, 0.0f }, const olc::vf2d &vSourceSize={ 1.0f, 1.0f })
void OnBeforeUserCreate() override
void Clear(const olc::Pixel &p=olc::BLANK)
int32_t DrawQuad(const olc::vf2d &vPos, const olc::vf2d &vSize)
int32_t SetTargetDecal(olc::Decal *pDecal, const uint32_t nSlot=0)
int32_t Start(olc::Effect *pEffect)
int32_t End()
void DrawPartialDecal(const olc::vf2d &pos, olc::Decal *decal, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::vf2d &scale={ 1.0f, 1.0f }, const olc::Pixel &tint=olc::WHITE)
Pixel * GetData()
int32_t height
Definition olcPixelGameEngine.h:1084
int32_t width
Definition olcPixelGameEngine.h:1083
Definition olcPixelGameEngine.h:612
DecalStructure
Definition olcPixelGameEngine.h:1138
constexpr size_t OLC_MAX_VERTS
Definition olcPixelGameEngine.h:940
static const Pixel BLANK(0, 0, 0, 0)
static const Pixel WHITE(255, 255, 255)
#define DEFAULT_VS
Definition olcPGEX_Shaders.h:107
#define DEFAULT_PS
Definition olcPGEX_Shaders.h:115
#define SHADER_HEADER
Definition olcPGEX_Shaders.h:103
Definition olcPixelGameEngine.h:1172
std::vector< olc::Pixel > tint
Definition olcPixelGameEngine.h:1178
std::vector< float > w
Definition olcPixelGameEngine.h:1176
std::vector< olc::vf2d > uv
Definition olcPixelGameEngine.h:1175
std::vector< olc::vf2d > pos
Definition olcPixelGameEngine.h:1174
uint32_t points
Definition olcPixelGameEngine.h:1181
Definition olcPGEX_Shaders.h:87
const std::vector< std::tuple< std::string, std::string, std::string > > vAttributes
Definition olcPGEX_Shaders.h:92
const std::string sPixelSource
Definition olcPGEX_Shaders.h:89
const size_t nOutputs
Definition olcPGEX_Shaders.h:91
const std::string sVertexSource
Definition olcPGEX_Shaders.h:88
const size_t nInputs
Definition olcPGEX_Shaders.h:90
Definition olcPixelGameEngine.h:948
uint8_t g
Definition olcPixelGameEngine.h:952
uint8_t a
Definition olcPixelGameEngine.h:952
uint8_t b
Definition olcPixelGameEngine.h:952
uint8_t r
Definition olcPixelGameEngine.h:952
T x
Definition olcPixelGameEngine.h:623
T y
Definition olcPixelGameEngine.h:625