Skip to content

Commit 66e5982

Browse files
authored
Merge pull request #395 from OneLoneCoder/develop
v2.29 push to main
2 parents 110f50e + e46ecb8 commit 66e5982

File tree

7 files changed

+4505
-1013
lines changed

7 files changed

+4505
-1013
lines changed

examples/TEST_Hardware3D.cpp

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/*
2+
Example file for olcUTIL_Hardware3D.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, ©OneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024, 2025
49+
50+
*/
51+
52+
53+
#define OLC_PGE_APPLICATION
54+
//#define OLC_GFX_OPENGL33
55+
#include <utilities/olcUTIL_Hardware3D.h>
56+
#include <olcPixelGameEngine.h>
57+
58+
59+
60+
class Quad3D : public olc::PixelGameEngine
61+
{
62+
public:
63+
Quad3D()
64+
{
65+
sAppName = "Hardware3D Assetless Demo";
66+
}
67+
68+
olc::mf4d matWorld;
69+
olc::mf4d matView;
70+
olc::mf4d matProject;
71+
72+
olc::Renderable texCube;
73+
olc::utils::hw3d::mesh meshCube;
74+
olc::utils::hw3d::mesh meshLightCube;
75+
76+
std::array<olc::vf3d, 64> cubes;
77+
std::array<olc::vf3d, 3> lights;
78+
79+
public:
80+
bool OnUserCreate() override
81+
{
82+
float fAspect = float(GetScreenSize().y) / float(GetScreenSize().x);
83+
float S = 1.0f / (tan(3.14159f * 0.25f));
84+
float f = 1000.0f;
85+
float n = 0.1f;
86+
87+
matProject(0, 0) = fAspect; matProject(0, 1) = 0.0f; matProject(0, 2) = 0.0f; matProject(0, 3) = 0.0f;
88+
matProject(1, 0) = 0.0f; matProject(1, 1) = 1; matProject(1, 2) = 0.0f; matProject(1, 3) = 0.0f;
89+
matProject(2, 0) = 0.0f; matProject(2, 1) = 0.0f; matProject(2, 2) = -(f / (f - n)); matProject(2, 3) = -1.0f;
90+
matProject(3, 0) = 0.0f; matProject(3, 1) = 0.0f; matProject(3, 2) = -((f * n) / (f - n)); matProject(3, 3) = 0.0f;
91+
92+
matWorld.identity();
93+
matView.identity();
94+
95+
// Create a unit cube, centered on origin
96+
meshCube = olc::utils::hw3d::CreateCube({ 1,1,1 }, {-0.5, -0.5, -0.5});
97+
98+
// Creat another cube, smaller
99+
meshLightCube = olc::utils::hw3d::CreateCube({ 0.5,0.5,0.5 }, { -0.25, -0.25, -0.25 });
100+
101+
// Why 2 cubes? the regular ones will have their vertex information recoloured
102+
103+
// Create texture (so we dont need to load anything)
104+
texCube.Create(128, 128);
105+
SetDrawTarget(texCube.Sprite());
106+
Clear(olc::WHITE);
107+
FillCircle(64, 64, 32, olc::BLACK);
108+
FillCircle(64, 64, 24, olc::BLUE);
109+
FillCircle(64, 64, 16, olc::RED);
110+
FillCircle(64, 64, 8, olc::YELLOW);
111+
SetDrawTarget(nullptr);
112+
texCube.Decal()->Update();
113+
114+
// Position cubes nicely
115+
for(int x=0; x<8; x++)
116+
for (int y = 0; y < 8; y++)
117+
{
118+
float z = sin(float(x)) + cos(float(y));
119+
cubes[y * 8 + x] = { float(x) - 4.0f, float(z), float(y) - 4.0f };
120+
}
121+
122+
123+
Clear(olc::VERY_DARK_BLUE);
124+
HW3D_Projection(matProject.m);
125+
HW3D_SetCullMode(olc::CullMode::CCW);
126+
return true;
127+
}
128+
129+
float fThetaX = 1;
130+
float fThetaY = 2;
131+
132+
float fLightTime = 0.0f;
133+
134+
135+
bool OnUserUpdate(float fElapsedTime) override
136+
{
137+
// spin stuff
138+
fThetaX += fElapsedTime * 0.1f;
139+
fThetaY += fElapsedTime * 0.05f;
140+
141+
olc::mf4d m1, m2, m3, m4;
142+
143+
// fake a pseudo-view matrix by transforming in an identity view
144+
m1.rotateY(fThetaY);
145+
m2.rotateX(fThetaX);
146+
m3.translate(0.0, 0.0, -10.0);
147+
matView = m3 * m2 * m1;
148+
149+
// Clear background
150+
ClearBuffer(olc::CYAN, true);
151+
152+
// Update light positions
153+
fLightTime += fElapsedTime;
154+
lights[0] = { 6.0f * sin(fLightTime * 2.5f), 6.0f * cos(fLightTime * 2.5f), 0.0f };
155+
lights[1] = { 0.0f, 6.0f * sin(fLightTime), 6.0f * cos(fLightTime) };
156+
lights[2] = { 6.0f * cos(fLightTime * 1.7f), 0.0f, 6.0f * sin(fLightTime * 1.7f) };
157+
158+
// World Space lighting! The 3 lights are used as directional light sources
159+
// so i dont need to pre-compute all the geometry on the CPU. This is a
160+
// limitation of the hw3d approach but like I said, its for basic 3D usage.
161+
for (size_t i = 0; i < meshCube.pos.size(); i += 3)
162+
{
163+
const auto& p0 = meshCube.pos[i + 0];
164+
const auto& p1 = meshCube.pos[i + 1];
165+
const auto& p2 = meshCube.pos[i + 2];
166+
167+
// Hand calculate surface normal (i know i know the norms are already there...)
168+
olc::vf3d vCross = olc::vf3d(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]).cross(olc::vf3d(p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2])).norm();
169+
170+
// Additive colouring
171+
meshCube.col[i + 0] = olc::BLACK;
172+
meshCube.col[i + 1] = olc::BLACK;
173+
meshCube.col[i + 2] = olc::BLACK;
174+
175+
olc::Pixel c[] = { olc::RED, olc::GREEN, olc::BLUE };
176+
for (int j = 0; j < 3; j++)
177+
{
178+
olc::vf3d vLight = -lights[j].norm();
179+
float illum = std::max(-vCross.dot(vLight), 0.0f) * 0.8f + 0.2f;
180+
meshCube.col[i + 0] += olc::PixelF(illum, illum, illum, 1.0f) * c[j];
181+
meshCube.col[i + 1] += olc::PixelF(illum, illum, illum, 1.0f) * c[j];
182+
meshCube.col[i + 2] += olc::PixelF(illum, illum, illum, 1.0f) * c[j];
183+
}
184+
}
185+
186+
187+
// Draw all cubes
188+
for (const auto& cube : cubes)
189+
{
190+
matWorld.translate(cube);
191+
HW3D_DrawObject((matView * matWorld).m, texCube.Decal(), meshCube.layout, meshCube.pos, meshCube.uv, meshCube.col);
192+
}
193+
194+
// Draw light cubes
195+
matWorld.translate(lights[0]);
196+
HW3D_DrawObject((matView * matWorld).m, nullptr, meshLightCube.layout, meshLightCube.pos, meshLightCube.uv, meshLightCube.col, olc::RED);
197+
matWorld.translate(lights[1]);
198+
HW3D_DrawObject((matView * matWorld).m, nullptr, meshLightCube.layout, meshLightCube.pos, meshLightCube.uv, meshLightCube.col, olc::GREEN);
199+
matWorld.translate(lights[2]);
200+
HW3D_DrawObject((matView * matWorld).m, nullptr, meshLightCube.layout, meshLightCube.pos, meshLightCube.uv, meshLightCube.col, olc::BLUE);
201+
return true;
202+
}
203+
};
204+
205+
int main()
206+
{
207+
Quad3D demo;
208+
if (demo.Construct(1280, 720, 1, 1, false, false))
209+
demo.Start();
210+
return 0;
211+
}

0 commit comments

Comments
 (0)