1+ /*
2+ Example file for olcPGEX_Shaders.h
3+
4+ License (OLC-3)
5+ ~~~~~~~~~~~~~~~
6+
7+ Copyright 2018 - 2025 OneLoneCoder.com
8+
9+ Redistribution and use in source and binary forms, with or without
10+ modification, are permitted provided that the following conditions
11+ are met:
12+
13+ 1. Redistributions or derivations of source code must retain the above
14+ copyright notice, this list of conditions and the following disclaimer.
15+
16+ 2. Redistributions or derivative works in binary form must reproduce
17+ the above copyright notice. This list of conditions and the following
18+ disclaimer must be reproduced in the documentation and/or other
19+ materials provided with the distribution.
20+
21+ 3. Neither the name of the copyright holder nor the names of its
22+ contributors may be used to endorse or promote products derived
23+ from this software without specific prior written permission.
24+
25+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36+
37+ Links
38+ ~~~~~
39+ YouTube: https://www.youtube.com/javidx9
40+ Discord: https://discord.gg/WhwHUMV
41+ Twitter: https://www.twitter.com/javidx9
42+ Twitch: https://www.twitch.tv/javidx9
43+ GitHub: https://www.github.com/onelonecoder
44+ Homepage: https://www.onelonecoder.com
45+
46+ Author
47+ ~~~~~~
48+ David Barr, aka javidx9
49+ ©OneLoneCoder 2019, 2020, 2021, 2022, 2022, 2023, 2024, 2025
50+
51+ */
52+
53+ #define OLC_PGE_APPLICATION
54+ #define OLC_GFX_OPENGL33
55+ #include " olcPixelGameEngine.h"
56+
57+ #define OLC_PGEX_SHADERS
58+ #include " extensions/olcPGEX_Shaders.h"
59+
60+ #define OLC_PGEX_TRANSFORMEDVIEW
61+ #include " extensions/olcPGEX_TransformedView.h"
62+
63+ class Example : public olc ::PixelGameEngine
64+ {
65+ public:
66+ Example ()
67+ {
68+ // Name your application
69+ sAppName = " Example" ;
70+ }
71+
72+ /*
73+
74+ PLEASE NOTE! This is all an ill-thought through idea. I do not recommend you actually use this.
75+
76+ */
77+
78+ // You need an instance of a shader object to apply pixel shading
79+ olc::Shade shader;
80+
81+ // Effects are the pixel shaders. They can be custom, or selected from a built in library
82+ olc::Effect fxScanlines;
83+ olc::Effect fxNormal;
84+ olc::Effect fxBoxblur;
85+ olc::Effect fxGreyscale;
86+ olc::Effect fxThreshold;
87+ olc::Effect fxSobel;
88+
89+ // Pixel shading is all done in Decal land, so for this demo we render to several decals with
90+ // different shading, and composite the result
91+ olc::Renderable gfxNormalBouncers;
92+ olc::Renderable gfxShadedBouncers;
93+ olc::Renderable gfxTexture1;
94+ olc::Renderable gfxTexture2;
95+
96+ olc::Renderable gfxEffect1;
97+ olc::Renderable gfxEffect2;
98+ olc::Renderable gfxEffect3;
99+ olc::Renderable gfxEffect4;
100+ olc::Renderable gfxEffect5;
101+
102+
103+ size_t nBouncers = 50 ;
104+ std::vector<std::pair<olc::vf2d, olc::vf2d>> vBouncers;
105+
106+ olc::TransformedView tv;
107+
108+
109+ public:
110+ bool OnUserCreate () override
111+ {
112+ // Transformed view is for panning and zooming
113+ tv.Initialise ({ ScreenWidth (), ScreenHeight () }, { 1 .0f , 1 .0f });
114+
115+ // These are decals, but created manually rather than from a file
116+ gfxNormalBouncers.Create (ScreenWidth (), ScreenHeight ());
117+ gfxShadedBouncers.Create (ScreenWidth (), ScreenHeight ());
118+ gfxEffect1.Create (200 , 200 );
119+ gfxEffect2.Create (200 , 200 );
120+ gfxEffect3.Create (200 , 200 );
121+ gfxEffect4.Create (200 , 200 );
122+ gfxEffect5.Create (200 , 200 );
123+
124+ // This decal uses a graphic - you'll need your own
125+ gfxTexture2.Load (" E:\\ work\\ repos\\ OneLoneCoder\\ olcProjects2\\ DEMO_Quad3D\\ assets\\ Baby.png" );
126+
127+ // All of these effects "pixel shaders" are built-in. You can easily define your own EffectConfig
128+ fxScanlines = shader.MakeEffect (olc::fx::FX_SCANLINE );
129+ fxNormal = shader.MakeEffect (olc::fx::FX_NORMAL );
130+ fxBoxblur = shader.MakeEffect (olc::fx::FX_BOXBLUR );
131+ fxGreyscale = shader.MakeEffect (olc::fx::FX_GREYSCALE );
132+ fxThreshold = shader.MakeEffect (olc::fx::FX_THRESHOLD );
133+ fxSobel = shader.MakeEffect (olc::fx::FX_SOBEL );
134+
135+
136+
137+
138+
139+ vBouncers.resize (nBouncers);
140+ for (size_t i = 0 ; i < nBouncers; i++)
141+ {
142+ float a = (float (rand ()) / float (RAND_MAX )) * 2 .0f * 3 .14159f ;
143+
144+ vBouncers[i] =
145+ std::make_pair<olc::vf2d, olc::vf2d>(
146+ { float (rand () % (ScreenWidth () - gfxTexture2.Sprite ()->width )) + 100 , float (rand () % (ScreenHeight () - gfxTexture2.Sprite ()->height )) + 100 },
147+ { cos (a), sin (a) });
148+ }
149+
150+ return true ;
151+ }
152+
153+ bool OnUserUpdate (float fElapsedTime ) override
154+ {
155+ // Handle Pan & Zoom
156+ if (GetMouse (2 ).bPressed ) tv.StartPan (GetMousePos ());
157+ if (GetMouse (2 ).bHeld ) tv.UpdatePan (GetMousePos ());
158+ if (GetMouse (2 ).bReleased ) tv.EndPan (GetMousePos ());
159+ if (GetMouseWheel () > 0 ) tv.ZoomAtScreenPos (2 .0f , GetMousePos ());
160+ if (GetMouseWheel () < 0 ) tv.ZoomAtScreenPos (0 .5f , GetMousePos ());
161+
162+
163+ // Stage 1) Just draw the bouncers normally into the NormalBouncers decal
164+ // This uses the "pass-thru" effect, i.e. nothing
165+
166+ // Set the target decal
167+ shader.SetTargetDecal (gfxNormalBouncers.Decal (), 0 );
168+ // Tell the shading system to use a shader
169+ shader.Start (&fxNormal);
170+ // Several PGE-like drawing commands are available. Here we clear the decal
171+ shader.Clear ();
172+
173+ // Update Locations & Render "Stock" Bouncers
174+ for (auto & bouncer : vBouncers)
175+ {
176+ bouncer.first += bouncer.second * fElapsedTime * 100 .0f ;
177+
178+ if (bouncer.first .x < 0 .0f )
179+ {
180+ bouncer.first .x = 0 .0f ; bouncer.second .x *= -1 .0f ;
181+ }
182+ if (bouncer.first .x + gfxTexture2.Sprite ()->width > ScreenWidth ())
183+ {
184+ bouncer.first .x = float (ScreenWidth () - gfxTexture2.Sprite ()->width ); bouncer.second .x *= -1 .0f ;
185+ }
186+
187+ if (bouncer.first .y < 0 .0f )
188+ {
189+ bouncer.first .y = 0 .0f ; bouncer.second .y *= -1 .0f ;
190+ }
191+ if (bouncer.first .y + gfxTexture2.Sprite ()->height > ScreenHeight ())
192+ {
193+ bouncer.first .y = float (ScreenHeight () - gfxTexture2.Sprite ()->height ); bouncer.second .y *= -1 .0f ;
194+ }
195+
196+ // Using the transformed view, draw the bouncer using the pass-thru shader
197+ tv.DrawDecal (shader, bouncer.first , gfxTexture2.Decal (), { 1 .0f , 1 .0f }, olc::WHITE );
198+ }
199+
200+ // Stop shading
201+ shader.End ();
202+
203+ // Stage 2) A selection of different effects are demonstrated. For each one, we "cut" out of normal bouncers
204+ // a small region, then draw it into its own decal just for that effect. The cut is done with DrawPartialDecal()
205+
206+ shader.SetTargetDecal (gfxEffect1.Decal (), 0 );
207+ shader.Start (&fxBoxblur);
208+ shader.Clear (olc::WHITE );
209+ shader.DrawPartialDecal ({ 0 .0f , 0 .0f }, gfxNormalBouncers.Decal (), { 50 .0f , 50 .0f }, { 200 .0f , 200 .0f });
210+ shader.End ();
211+
212+ shader.SetTargetDecal (gfxEffect2.Decal (), 0 );
213+ shader.Start (&fxScanlines);
214+ shader.Clear (olc::WHITE );
215+ shader.DrawPartialDecal ({ 0 .0f , 0 .0f }, gfxNormalBouncers.Decal (), { 300 .0f , 50 .0f }, { 200 .0f , 200 .0f });
216+ shader.End ();
217+
218+ shader.SetTargetDecal (gfxEffect3.Decal (), 0 );
219+ shader.Start (&fxGreyscale);
220+ shader.Clear (olc::WHITE );
221+ shader.DrawPartialDecal ({ 0 .0f , 0 .0f }, gfxNormalBouncers.Decal (), { 550 .0f , 50 .0f }, { 200 .0f , 200 .0f });
222+ shader.End ();
223+
224+ shader.SetTargetDecal (gfxEffect4.Decal (), 0 );
225+ shader.Start (&fxThreshold);
226+ shader.Clear (olc::WHITE );
227+ shader.DrawPartialDecal ({ 0 .0f , 0 .0f }, gfxNormalBouncers.Decal (), { 800 .0f , 50 .0f }, { 200 .0f , 200 .0f });
228+ shader.End ();
229+
230+ shader.SetTargetDecal (gfxEffect5.Decal (), 0 );
231+ shader.Start (&fxSobel);
232+ shader.Clear (olc::WHITE );
233+ shader.DrawPartialDecal ({ 0 .0f , 0 .0f }, gfxNormalBouncers.Decal (), { 1050 .0f , 50 .0f }, { 200 .0f , 200 .0f });
234+ shader.End ();
235+
236+ // Stage 3) Composite final display - NOT USING SHADERS NOW
237+
238+ Clear (olc::WHITE );
239+ DrawDecal ({ 0 ,0 }, gfxNormalBouncers.Decal ());
240+
241+ FillRectDecal ({ 48 .0f , 48 .0f }, { 204 .0f , 204 .0f }, olc::BLUE );
242+ DrawDecal ({ 50 .0f , 50 .0f }, gfxEffect1.Decal ());
243+
244+ FillRectDecal ({ 298 .0f , 48 .0f }, { 204 .0f , 204 .0f }, olc::BLUE );
245+ DrawDecal ({ 300 .0f , 50 .0f }, gfxEffect2.Decal ());
246+
247+ FillRectDecal ({ 548 .0f , 48 .0f }, { 204 .0f , 204 .0f }, olc::BLUE );
248+ DrawDecal ({ 550 .0f , 50 .0f }, gfxEffect3.Decal ());
249+
250+ FillRectDecal ({ 798 .0f , 48 .0f }, { 204 .0f , 204 .0f }, olc::BLUE );
251+ DrawDecal ({ 800 .0f , 50 .0f }, gfxEffect4.Decal ());
252+
253+ FillRectDecal ({ 1048 .0f , 48 .0f }, { 204 .0f , 204 .0f }, olc::BLUE );
254+ DrawDecal ({ 1050 .0f , 50 .0f }, gfxEffect5.Decal ());
255+
256+
257+ return true ;
258+ }
259+ };
260+
261+ int main ()
262+ {
263+ Example demo;
264+ if (demo.Construct (1280 , 720 , 1 , 1 , false , false ))
265+ demo.Start ();
266+ return 0 ;
267+ }
0 commit comments