Skip to content

Commit 4903c9b

Browse files
committed
Added asset-less HW3D demo
Added tinting to objects
1 parent 2aa3c12 commit 4903c9b

3 files changed

Lines changed: 242 additions & 26 deletions

File tree

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+
}

olcPixelGameEngine.h

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,7 @@ namespace olc
12041204
0, 0, 0, 1
12051205
} };
12061206
olc::CullMode cull = olc::CullMode::NONE;
1207+
olc::Pixel tint = olc::WHITE;
12071208
};
12081209

12091210
struct LayerDesc
@@ -1764,6 +1765,7 @@ namespace olc
17641765
typedef void CALLSTYLE locUniform1f_t(GLint location, GLfloat v0);
17651766
typedef void CALLSTYLE locUniform1i_t(GLint location, GLint v0);
17661767
typedef void CALLSTYLE locUniform2fv_t(GLint location, GLsizei count, const GLfloat* value);
1768+
typedef void CALLSTYLE locUniform4fv_t(GLint location, GLsizei count, const GLfloat* value);
17671769
typedef void CALLSTYLE locUniformMatrix4fv_t(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value);
17681770
typedef void CALLSTYLE locActiveTexture_t(GLenum texture);
17691771
typedef void CALLSTYLE locGenFrameBuffers_t(GLsizei n, GLuint* ids);
@@ -3535,6 +3537,7 @@ namespace olc
35353537
task.depth = bHW3DDepthTest;
35363538
task.cull = nHW3DCullMode;
35373539
task.mvp = matModelView;
3540+
task.tint = tint;
35383541
task.vb.resize(pos.size());
35393542

35403543
for (size_t i = 0; i < pos.size(); i++)
@@ -3552,6 +3555,7 @@ namespace olc
35523555
task.depth = bHW3DDepthTest;
35533556
task.cull = nHW3DCullMode;
35543557
task.mvp = matModelView;
3558+
task.tint = olc::WHITE;
35553559
task.vb =
35563560
{
35573561
{ pos1[0], pos1[1], pos1[2], 1.0f, 0.0f, 0.0f, col.n},
@@ -3570,6 +3574,7 @@ namespace olc
35703574
task.depth = bHW3DDepthTest;
35713575
task.cull = nHW3DCullMode;
35723576
task.mvp = matModelView;
3577+
task.tint = olc::WHITE;
35733578

35743579
const float ox = pos[0];
35753580
const float oy = pos[1];
@@ -5453,42 +5458,24 @@ namespace olc
54535458
// x y z w u v rgb
54545459
//std::vector<std::tuple<float, float, float, float, float, float, uint32_t>> vb;
54555460

5461+
float f[4] = { float(task.tint.r) / 255.0f, float(task.tint.g) / 255.0f, float(task.tint.b) / 255.0f, float(task.tint.a) / 255.0f };
5462+
54565463
if (task.depth)
54575464
{
5458-
5459-
//// Render as 3D Spatial Entity
5460-
//for (uint32_t n = 0; n < decal.points; n++)
5461-
//{
5462-
// glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a);
5463-
// glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]);
5464-
// glVertex3f(decal.pos[n].x, decal.pos[n].y, decal.z[n]);
5465-
//}
5466-
54675465
for (uint32_t n = 0; n < task.vb.size(); n++)
54685466
{
54695467
olc::Pixel p = task.vb[n].c;
5470-
glColor4ub(p.r, p.g, p.b, p.a);
5468+
glColor4ub(GLubyte(p.r * f[0]), GLubyte(p.g * f[1]), GLubyte(p.b * f[2]), GLubyte(p.a * f[3]));
54715469
glTexCoord2f(task.vb[n].p[4], task.vb[n].p[5]);
54725470
glVertex4f(task.vb[n].p[0], task.vb[n].p[1], task.vb[n].p[2], task.vb[n].p[3]);
54735471
}
54745472
}
54755473
else
54765474
{
5477-
5478-
5479-
//// Render as 2D Spatial entity
5480-
//for (uint32_t n = 0; n < task.vb.size(); n++)
5481-
//{
5482-
// olc::Pixel p = std::get<6>(task.vb[n]);
5483-
// glColor4ub(p.r, p.g, p.b, p.a);
5484-
// glTexCoord4f(std::get<4>(task.vb[n]), std::get<5>(task.vb[n]), 0.0f, std::get<3>(task.vb[n]));
5485-
// glVertex2f(std::get<0>(task.vb[n]), std::get<1>(task.vb[n]));
5486-
//}
5487-
54885475
for (uint32_t n = 0; n < task.vb.size(); n++)
54895476
{
54905477
olc::Pixel p = task.vb[n].c;
5491-
glColor4ub(p.r, p.g, p.b, p.a);
5478+
glColor4ub(GLubyte(p.r * f[0]), GLubyte(p.g * f[1]), GLubyte(p.b * f[2]), GLubyte(p.a * f[3]));
54925479
glVertex4f(task.vb[n].p[4], task.vb[n].p[5], 0.0f, task.vb[n].p[3]);
54935480
glTexCoord2f(task.vb[n].p[0], task.vb[n].p[1]);
54945481
}
@@ -5724,6 +5711,7 @@ namespace olc
57245711
locGetUniformLocation_t* locGetUniformLocation = nullptr;
57255712
locUniformMatrix4fv_t* locUniformMatrix4fv = nullptr;
57265713
locUniform1i_t* locUniform1i = nullptr;
5714+
locUniform4fv_t* locUniform4fv = nullptr;
57275715

57285716
uint32_t m_nFS = 0;
57295717
uint32_t m_nVS = 0;
@@ -5733,6 +5721,7 @@ namespace olc
57335721

57345722
uint32_t m_uniMVP = 0;
57355723
uint32_t m_uniIs3D = 0;
5724+
uint32_t m_uniTint = 0;
57365725

57375726
struct locVertex
57385727
{
@@ -5871,6 +5860,7 @@ namespace olc
58715860
locUseProgram = OGL_LOAD(locUseProgram_t, glUseProgram);
58725861
locGetShaderInfoLog = OGL_LOAD(locGetShaderInfoLog_t, glGetShaderInfoLog);
58735862
locUniform1i = OGL_LOAD(locUniform1i_t, glUniform1i);
5863+
locUniform4fv = OGL_LOAD(locUniform4fv_t, glUniform4fv);
58745864
locUniformMatrix4fv = OGL_LOAD(locUniformMatrix4fv_t, glUniformMatrix4fv);
58755865
locGetUniformLocation = OGL_LOAD(locGetUniformLocation_t, glGetUniformLocation);
58765866
#if !defined(OLC_PLATFORM_EMSCRIPTEN)
@@ -5911,9 +5901,10 @@ namespace olc
59115901
"layout(location = 2) in vec4 aCol;\n"
59125902
"uniform mat4 mvp;\n"
59135903
"uniform int is3d;\n"
5904+
"uniform vec4 tint;\n"
59145905
"out vec2 oTex;\n"
59155906
"out vec4 oCol;\n"
5916-
"void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex;} oCol = aCol;}";
5907+
"void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex;} oCol = aCol * tint;}";
59175908
locShaderSource(m_nVS, 1, &strVS, NULL);
59185909
locCompileShader(m_nVS);
59195910

@@ -5924,8 +5915,11 @@ namespace olc
59245915

59255916
m_uniMVP = locGetUniformLocation(m_nQuadShader, "mvp");
59265917
m_uniIs3D = locGetUniformLocation(m_nQuadShader, "is3d");
5918+
m_uniTint = locGetUniformLocation(m_nQuadShader, "tint");
59275919
locUniform1i(m_uniIs3D, 0);
5928-
locUniformMatrix4fv(m_uniMVP, 1, false, matProjection.data());
5920+
locUniformMatrix4fv(m_uniMVP, 16, false, matProjection.data());
5921+
float f[4] = { 100.0f, 100.0f, 100.0f, 100.0f };
5922+
locUniform4fv(m_uniTint, 4, f);
59295923

59305924
// Create Quad
59315925
locGenBuffers(1, &m_vbQuad);
@@ -6002,6 +5996,8 @@ namespace olc
60025996
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
60035997
locUseProgram(m_nQuadShader);
60045998
locBindVertexArray(m_vaQuad);
5999+
float f[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
6000+
locUniform4fv(m_uniTint, 1, f);
60056001

60066002
#if defined(OLC_PLATFORM_EMSCRIPTEN)
60076003
locVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(locVertex), 0); locEnableVertexAttribArray(0);
@@ -6047,6 +6043,8 @@ namespace olc
60476043
locBufferData(0x8892, sizeof(locVertex) * 4, verts, 0x88E0);
60486044

60496045
locUniform1i(m_uniIs3D, 0);
6046+
float f[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
6047+
locUniform4fv(m_uniTint, 1, f);
60506048
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
60516049
}
60526050

@@ -6066,6 +6064,10 @@ namespace olc
60666064

60676065
locBufferData(0x8892, sizeof(locVertex) * decal.points, pVertexMem, 0x88E0);
60686066
locUniform1i(m_uniIs3D, 0);
6067+
6068+
float f[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
6069+
locUniform4fv(m_uniTint, 1, f);
6070+
60696071
if (nDecalMode == DecalMode::WIREFRAME)
60706072
glDrawArrays(GL_LINE_LOOP, 0, decal.points);
60716073
else
@@ -6186,6 +6188,9 @@ namespace olc
61866188
+ matProjection[3 * 4 + r] * task.mvp[c * 4 + 3];
61876189
locUniformMatrix4fv(m_uniMVP, 1, false, matMVP.data());
61886190

6191+
float f[4] = { float(task.tint.r) / 255.0f, float(task.tint.g) / 255.0f, float(task.tint.b) / 255.0f, float(task.tint.a) / 255.0f };
6192+
locUniform4fv(m_uniTint, 1, f);
6193+
61896194

61906195
if (task.cull == olc::CullMode::NONE)
61916196
{

0 commit comments

Comments
 (0)