olcPixelGameEngine v2.28
The official distribution of olcPixelGameEngine, a tool used in javidx9's YouTube videos and projects
Loading...
Searching...
No Matches
olcPGEX_Graphics3D.h
Go to the documentation of this file.
1/*
2 olcPGEX_Graphics3D.h
3
4 +-------------------------------------------------------------+
5 | OneLoneCoder Pixel Game Engine Extension |
6 | 3D Rendering - v0.4 |
7 +-------------------------------------------------------------+
8
9 What is this?
10 ~~~~~~~~~~~~~
11 This is an extension to the olcPixelGameEngine, which provides
12 support for software rendering 3D graphics.
13
14 NOTE!!! This file is under development and may change!
15
16 Big Thanks to MaGetzUb for finding an OOB error, and joshinils
17 for pointing out sampling inaccuracy.
18
19 License (OLC-3)
20 ~~~~~~~~~~~~~~~
21
22 Copyright 2018-2019 OneLoneCoder.com
23
24 Redistribution and use in source and binary forms, with or without
25 modification, are permitted provided that the following conditions
26 are met:
27
28 1. Redistributions or derivations of source code must retain the above
29 copyright notice, this list of conditions and the following disclaimer.
30
31 2. Redistributions or derivative works in binary form must reproduce
32 the above copyright notice. This list of conditions and the following
33 disclaimer must be reproduced in the documentation and/or other
34 materials provided with the distribution.
35
36 3. Neither the name of the copyright holder nor the names of its
37 contributors may be used to endorse or promote products derived
38 from this software without specific prior written permission.
39
40 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
52 Links
53 ~~~~~
54 YouTube: https://www.youtube.com/javidx9
55 Discord: https://discord.gg/WhwHUMV
56 Twitter: https://www.twitter.com/javidx9
57 Twitch: https://www.twitch.tv/javidx9
58 GitHub: https://www.github.com/onelonecoder
59 Patreon: https://www.patreon.com/javidx9
60 Homepage: https://www.onelonecoder.com
61
62 Author
63 ~~~~~~
64 David Barr, aka javidx9, ©OneLoneCoder 2018
65*/
66
67
68#ifndef OLC_PGEX_GFX3D
69#define OLC_PGEX_GFX3D
70
71#include <algorithm>
72#include <vector>
73#include <list>
74#include <sstream>
75#include <string>
76#include <cstdint>
77
78#include "olcPixelGameEngine.h"
79
80#undef min
81#undef max
82
83//#include <omp.h>
84
85namespace olc
86{
87 // Container class for Advanced 2D Drawing functions
88 class GFX3D : public olc::PGEX
89 {
90
91 public:
92
93 struct vec2d
94 {
95 float x = 0;
96 float y = 0;
97 float z = 0;
98 };
99
100 struct vec3d
101 {
102 float x = 0;
103 float y = 0;
104 float z = 0;
105 float w = 1; // Need a 4th term to perform sensible matrix vector multiplication
106 };
107
108 struct triangle
109 {
113 };
114
115 struct mat4x4
116 {
117 float m[4][4] = { 0 };
118 };
119
120 struct mesh
121 {
122 std::vector<triangle> tris;
123 bool LoadOBJFile(std::string sFilename, bool bHasTexture = false);
124 };
125
126 /*class MipMap : public olc::Sprite
127 {
128 public:
129 MipMap();
130 MipMap(std::string sImageFile);
131 MipMap(std::string sImageFile, olc::ResourcePack *pack);
132 MipMap(int32_t w, int32_t h);
133 ~MipMap();
134
135 public:
136 olc::rcode LoadFromFile(std::string sImageFile, olc::ResourcePack *pack = nullptr);
137 olc::rcode LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack = nullptr);
138 Pixel Sample(float x, float y, float z);
139 Pixel SampleBL(float u, float v, float z);
140
141 private:
142 int GenerateMipLevels();
143 std::vector<olc::Sprite> vecMipMaps;
144
145 };*/
146
147 class Math
148 {
149 public:
151 public:
155 static mat4x4 Mat_MakeRotationX(float fAngleRad);
156 static mat4x4 Mat_MakeRotationY(float fAngleRad);
157 static mat4x4 Mat_MakeRotationZ(float fAngleRad);
158 static mat4x4 Mat_MakeScale(float x, float y, float z);
159 static mat4x4 Mat_MakeTranslation(float x, float y, float z);
160 static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar);
161 static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up);
162 static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices
164
165 static vec3d Vec_Add(vec3d &v1, vec3d &v2);
166 static vec3d Vec_Sub(vec3d &v1, vec3d &v2);
167 static vec3d Vec_Mul(vec3d &v1, float k);
168 static vec3d Vec_Div(vec3d &v1, float k);
169 static float Vec_DotProduct(vec3d &v1, vec3d &v2);
170 static float Vec_Length(vec3d &v);
173 static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t);
174
175 static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2);
176 };
177
188
196
197
199 {
200 public:
202
203 public:
204 void SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight);
207 void SetTexture(olc::Sprite *texture);
208 //void SetMipMapTexture(olc::GFX3D::MipMap *texture);
209 void SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir = { 0.0f, 0.0f, 1.0f, 1.0f }, float fParam = 0.0f);
210 uint32_t Render(std::vector<olc::GFX3D::triangle> &triangles, uint32_t flags = RENDER_CULL_CW | RENDER_TEXTURED | RENDER_DEPTH);
211 uint32_t Render(std::vector<olc::GFX3D::triangle> &triangles, uint32_t flags, int nOffset, int nCount);
214
215 private:
216 olc::GFX3D::mat4x4 matProj;
217 olc::GFX3D::mat4x4 matView;
218 olc::GFX3D::mat4x4 matWorld;
219 olc::Sprite *sprTexture;
220 //olc::GFX3D::MipMap *sprMipMap;
221 //bool bUseMipMap;
222 float fViewX;
223 float fViewY;
224 float fViewW;
225 float fViewH;
226
227 struct sLight
228 {
229 uint32_t type;
232 olc::Pixel col;
233 float param;
234 } lights[4];
235 };
236
237
238
239 public:
240 //static const int RF_TEXTURE = 0x00000001;
241 //static const int RF_ = 0x00000002;
242
243 static void ConfigureDisplay();
244 static void ClearDepth();
246 static void RenderScene();
247
251 static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1,
252 int x2, int y2, float u2, float v2, float w2,
253 int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr);
254
255 static void RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1,
256 int x2, int y2, float u2, float v2, float w2, olc::Pixel c2,
257 int x3, int y3, float u3, float v3, float w3, olc::Pixel c3,
258 olc::Sprite* spr,
259 uint32_t nFlags);
260
261 // Draws a sprite with the transform applied
262 //inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform);
263
264 private:
265 static float* m_DepthBuffer;
266 };
267}
268
269#endif
270
271
272#ifdef OLC_PGEX_GRAPHICS3D
273#undef OLC_PGEX_GRAPHICS3D
274
275namespace olc
276{
278 {
279
280 }
281
283 {
284 vec3d v;
285 v.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + i.w * m.m[3][0];
286 v.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + i.w * m.m[3][1];
287 v.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + i.w * m.m[3][2];
288 v.w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + i.w * m.m[3][3];
289 return v;
290 }
291
293 {
294 olc::GFX3D::mat4x4 matrix;
295 matrix.m[0][0] = 1.0f;
296 matrix.m[1][1] = 1.0f;
297 matrix.m[2][2] = 1.0f;
298 matrix.m[3][3] = 1.0f;
299 return matrix;
300 }
301
303 {
304 olc::GFX3D::mat4x4 matrix;
305 matrix.m[0][0] = 1.0f;
306 matrix.m[1][1] = cosf(fAngleRad);
307 matrix.m[1][2] = sinf(fAngleRad);
308 matrix.m[2][1] = -sinf(fAngleRad);
309 matrix.m[2][2] = cosf(fAngleRad);
310 matrix.m[3][3] = 1.0f;
311 return matrix;
312 }
313
315 {
316 olc::GFX3D::mat4x4 matrix;
317 matrix.m[0][0] = cosf(fAngleRad);
318 matrix.m[0][2] = sinf(fAngleRad);
319 matrix.m[2][0] = -sinf(fAngleRad);
320 matrix.m[1][1] = 1.0f;
321 matrix.m[2][2] = cosf(fAngleRad);
322 matrix.m[3][3] = 1.0f;
323 return matrix;
324 }
325
327 {
328 olc::GFX3D::mat4x4 matrix;
329 matrix.m[0][0] = cosf(fAngleRad);
330 matrix.m[0][1] = sinf(fAngleRad);
331 matrix.m[1][0] = -sinf(fAngleRad);
332 matrix.m[1][1] = cosf(fAngleRad);
333 matrix.m[2][2] = 1.0f;
334 matrix.m[3][3] = 1.0f;
335 return matrix;
336 }
337
338 olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeScale(float x, float y, float z)
339 {
340 olc::GFX3D::mat4x4 matrix;
341 matrix.m[0][0] = x;
342 matrix.m[1][1] = y;
343 matrix.m[2][2] = z;
344 matrix.m[3][3] = 1.0f;
345 return matrix;
346 }
347
349 {
350 olc::GFX3D::mat4x4 matrix;
351 matrix.m[0][0] = 1.0f;
352 matrix.m[1][1] = 1.0f;
353 matrix.m[2][2] = 1.0f;
354 matrix.m[3][3] = 1.0f;
355 matrix.m[3][0] = x;
356 matrix.m[3][1] = y;
357 matrix.m[3][2] = z;
358 return matrix;
359 }
360
361 olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar)
362 {
363 float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f);
364 olc::GFX3D::mat4x4 matrix;
365 matrix.m[0][0] = fAspectRatio * fFovRad;
366 matrix.m[1][1] = fFovRad;
367 matrix.m[2][2] = fFar / (fFar - fNear);
368 matrix.m[3][2] = (-fFar * fNear) / (fFar - fNear);
369 matrix.m[2][3] = 1.0f;
370 matrix.m[3][3] = 0.0f;
371 return matrix;
372 }
373
375 {
376 olc::GFX3D::mat4x4 matrix;
377 for (int c = 0; c < 4; c++)
378 for (int r = 0; r < 4; r++)
379 matrix.m[r][c] = m1.m[r][0] * m2.m[0][c] + m1.m[r][1] * m2.m[1][c] + m1.m[r][2] * m2.m[2][c] + m1.m[r][3] * m2.m[3][c];
380 return matrix;
381 }
382
384 {
385 // Calculate new forward direction
386 olc::GFX3D::vec3d newForward = Vec_Sub(target, pos);
387 newForward = Vec_Normalise(newForward);
388
389 // Calculate new Up direction
390 olc::GFX3D::vec3d a = Vec_Mul(newForward, Vec_DotProduct(up, newForward));
391 olc::GFX3D::vec3d newUp = Vec_Sub(up, a);
392 newUp = Vec_Normalise(newUp);
393
394 // New Right direction is easy, its just cross product
395 olc::GFX3D::vec3d newRight = Vec_CrossProduct(newUp, newForward);
396
397 // Construct Dimensioning and Translation Matrix
398 olc::GFX3D::mat4x4 matrix;
399 matrix.m[0][0] = newRight.x; matrix.m[0][1] = newRight.y; matrix.m[0][2] = newRight.z; matrix.m[0][3] = 0.0f;
400 matrix.m[1][0] = newUp.x; matrix.m[1][1] = newUp.y; matrix.m[1][2] = newUp.z; matrix.m[1][3] = 0.0f;
401 matrix.m[2][0] = newForward.x; matrix.m[2][1] = newForward.y; matrix.m[2][2] = newForward.z; matrix.m[2][3] = 0.0f;
402 matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1.0f;
403 return matrix;
404
405 }
406
407 olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_QuickInverse(olc::GFX3D::mat4x4 &m) // Only for Rotation/Translation Matrices
408 {
409 olc::GFX3D::mat4x4 matrix;
410 matrix.m[0][0] = m.m[0][0]; matrix.m[0][1] = m.m[1][0]; matrix.m[0][2] = m.m[2][0]; matrix.m[0][3] = 0.0f;
411 matrix.m[1][0] = m.m[0][1]; matrix.m[1][1] = m.m[1][1]; matrix.m[1][2] = m.m[2][1]; matrix.m[1][3] = 0.0f;
412 matrix.m[2][0] = m.m[0][2]; matrix.m[2][1] = m.m[1][2]; matrix.m[2][2] = m.m[2][2]; matrix.m[2][3] = 0.0f;
413 matrix.m[3][0] = -(m.m[3][0] * matrix.m[0][0] + m.m[3][1] * matrix.m[1][0] + m.m[3][2] * matrix.m[2][0]);
414 matrix.m[3][1] = -(m.m[3][0] * matrix.m[0][1] + m.m[3][1] * matrix.m[1][1] + m.m[3][2] * matrix.m[2][1]);
415 matrix.m[3][2] = -(m.m[3][0] * matrix.m[0][2] + m.m[3][1] * matrix.m[1][2] + m.m[3][2] * matrix.m[2][2]);
416 matrix.m[3][3] = 1.0f;
417 return matrix;
418 }
419
421 {
422 double det;
423
424
425 mat4x4 matInv;
426
427 matInv.m[0][0] = m.m[1][1] * m.m[2][2] * m.m[3][3] - m.m[1][1] * m.m[2][3] * m.m[3][2] - m.m[2][1] * m.m[1][2] * m.m[3][3] + m.m[2][1] * m.m[1][3] * m.m[3][2] + m.m[3][1] * m.m[1][2] * m.m[2][3] - m.m[3][1] * m.m[1][3] * m.m[2][2];
428 matInv.m[1][0] = -m.m[1][0] * m.m[2][2] * m.m[3][3] + m.m[1][0] * m.m[2][3] * m.m[3][2] + m.m[2][0] * m.m[1][2] * m.m[3][3] - m.m[2][0] * m.m[1][3] * m.m[3][2] - m.m[3][0] * m.m[1][2] * m.m[2][3] + m.m[3][0] * m.m[1][3] * m.m[2][2];
429 matInv.m[2][0] = m.m[1][0] * m.m[2][1] * m.m[3][3] - m.m[1][0] * m.m[2][3] * m.m[3][1] - m.m[2][0] * m.m[1][1] * m.m[3][3] + m.m[2][0] * m.m[1][3] * m.m[3][1] + m.m[3][0] * m.m[1][1] * m.m[2][3] - m.m[3][0] * m.m[1][3] * m.m[2][1];
430 matInv.m[3][0] = -m.m[1][0] * m.m[2][1] * m.m[3][2] + m.m[1][0] * m.m[2][2] * m.m[3][1] + m.m[2][0] * m.m[1][1] * m.m[3][2] - m.m[2][0] * m.m[1][2] * m.m[3][1] - m.m[3][0] * m.m[1][1] * m.m[2][2] + m.m[3][0] * m.m[1][2] * m.m[2][1];
431 matInv.m[0][1] = -m.m[0][1] * m.m[2][2] * m.m[3][3] + m.m[0][1] * m.m[2][3] * m.m[3][2] + m.m[2][1] * m.m[0][2] * m.m[3][3] - m.m[2][1] * m.m[0][3] * m.m[3][2] - m.m[3][1] * m.m[0][2] * m.m[2][3] + m.m[3][1] * m.m[0][3] * m.m[2][2];
432 matInv.m[1][1] = m.m[0][0] * m.m[2][2] * m.m[3][3] - m.m[0][0] * m.m[2][3] * m.m[3][2] - m.m[2][0] * m.m[0][2] * m.m[3][3] + m.m[2][0] * m.m[0][3] * m.m[3][2] + m.m[3][0] * m.m[0][2] * m.m[2][3] - m.m[3][0] * m.m[0][3] * m.m[2][2];
433 matInv.m[2][1] = -m.m[0][0] * m.m[2][1] * m.m[3][3] + m.m[0][0] * m.m[2][3] * m.m[3][1] + m.m[2][0] * m.m[0][1] * m.m[3][3] - m.m[2][0] * m.m[0][3] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[2][3] + m.m[3][0] * m.m[0][3] * m.m[2][1];
434 matInv.m[3][1] = m.m[0][0] * m.m[2][1] * m.m[3][2] - m.m[0][0] * m.m[2][2] * m.m[3][1] - m.m[2][0] * m.m[0][1] * m.m[3][2] + m.m[2][0] * m.m[0][2] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[2][2] - m.m[3][0] * m.m[0][2] * m.m[2][1];
435 matInv.m[0][2] = m.m[0][1] * m.m[1][2] * m.m[3][3] - m.m[0][1] * m.m[1][3] * m.m[3][2] - m.m[1][1] * m.m[0][2] * m.m[3][3] + m.m[1][1] * m.m[0][3] * m.m[3][2] + m.m[3][1] * m.m[0][2] * m.m[1][3] - m.m[3][1] * m.m[0][3] * m.m[1][2];
436 matInv.m[1][2] = -m.m[0][0] * m.m[1][2] * m.m[3][3] + m.m[0][0] * m.m[1][3] * m.m[3][2] + m.m[1][0] * m.m[0][2] * m.m[3][3] - m.m[1][0] * m.m[0][3] * m.m[3][2] - m.m[3][0] * m.m[0][2] * m.m[1][3] + m.m[3][0] * m.m[0][3] * m.m[1][2];
437 matInv.m[2][2] = m.m[0][0] * m.m[1][1] * m.m[3][3] - m.m[0][0] * m.m[1][3] * m.m[3][1] - m.m[1][0] * m.m[0][1] * m.m[3][3] + m.m[1][0] * m.m[0][3] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[1][3] - m.m[3][0] * m.m[0][3] * m.m[1][1];
438 matInv.m[3][2] = -m.m[0][0] * m.m[1][1] * m.m[3][2] + m.m[0][0] * m.m[1][2] * m.m[3][1] + m.m[1][0] * m.m[0][1] * m.m[3][2] - m.m[1][0] * m.m[0][2] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[1][2] + m.m[3][0] * m.m[0][2] * m.m[1][1];
439 matInv.m[0][3] = -m.m[0][1] * m.m[1][2] * m.m[2][3] + m.m[0][1] * m.m[1][3] * m.m[2][2] + m.m[1][1] * m.m[0][2] * m.m[2][3] - m.m[1][1] * m.m[0][3] * m.m[2][2] - m.m[2][1] * m.m[0][2] * m.m[1][3] + m.m[2][1] * m.m[0][3] * m.m[1][2];
440 matInv.m[1][3] = m.m[0][0] * m.m[1][2] * m.m[2][3] - m.m[0][0] * m.m[1][3] * m.m[2][2] - m.m[1][0] * m.m[0][2] * m.m[2][3] + m.m[1][0] * m.m[0][3] * m.m[2][2] + m.m[2][0] * m.m[0][2] * m.m[1][3] - m.m[2][0] * m.m[0][3] * m.m[1][2];
441 matInv.m[2][3] = -m.m[0][0] * m.m[1][1] * m.m[2][3] + m.m[0][0] * m.m[1][3] * m.m[2][1] + m.m[1][0] * m.m[0][1] * m.m[2][3] - m.m[1][0] * m.m[0][3] * m.m[2][1] - m.m[2][0] * m.m[0][1] * m.m[1][3] + m.m[2][0] * m.m[0][3] * m.m[1][1];
442 matInv.m[3][3] = m.m[0][0] * m.m[1][1] * m.m[2][2] - m.m[0][0] * m.m[1][2] * m.m[2][1] - m.m[1][0] * m.m[0][1] * m.m[2][2] + m.m[1][0] * m.m[0][2] * m.m[2][1] + m.m[2][0] * m.m[0][1] * m.m[1][2] - m.m[2][0] * m.m[0][2] * m.m[1][1];
443
444 det = m.m[0][0] * matInv.m[0][0] + m.m[0][1] * matInv.m[1][0] + m.m[0][2] * matInv.m[2][0] + m.m[0][3] * matInv.m[3][0];
445 // if (det == 0) return false;
446
447 det = 1.0 / det;
448
449 for (int i = 0; i < 4; i++)
450 for (int j = 0; j < 4; j++)
451 matInv.m[i][j] *= (float)det;
452
453 return matInv;
454 }
455
457 {
458 return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
459 }
460
462 {
463 return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
464 }
465
467 {
468 return { v1.x * k, v1.y * k, v1.z * k };
469 }
470
472 {
473 return { v1.x / k, v1.y / k, v1.z / k };
474 }
475
477 {
478 return v1.x*v2.x + v1.y*v2.y + v1.z * v2.z;
479 }
480
482 {
483 return sqrtf(Vec_DotProduct(v, v));
484 }
485
487 {
488 float l = Vec_Length(v);
489 return { v.x / l, v.y / l, v.z / l };
490 }
491
493 {
494 vec3d v;
495 v.x = v1.y * v2.z - v1.z * v2.y;
496 v.y = v1.z * v2.x - v1.x * v2.z;
497 v.z = v1.x * v2.y - v1.y * v2.x;
498 return v;
499 }
500
502 {
503 plane_n = Vec_Normalise(plane_n);
504 float plane_d = -Vec_DotProduct(plane_n, plane_p);
505 float ad = Vec_DotProduct(lineStart, plane_n);
506 float bd = Vec_DotProduct(lineEnd, plane_n);
507 t = (-plane_d - ad) / (bd - ad);
508 olc::GFX3D::vec3d lineStartToEnd = Vec_Sub(lineEnd, lineStart);
509 olc::GFX3D::vec3d lineToIntersect = Vec_Mul(lineStartToEnd, t);
510 return Vec_Add(lineStart, lineToIntersect);
511 }
512
513
514 int olc::GFX3D::Math::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2)
515 {
516 // Make sure plane normal is indeed normal
517 plane_n = Math::Vec_Normalise(plane_n);
518
519 out_tri1.t[0] = in_tri.t[0];
520 out_tri2.t[0] = in_tri.t[0];
521 out_tri1.t[1] = in_tri.t[1];
522 out_tri2.t[1] = in_tri.t[1];
523 out_tri1.t[2] = in_tri.t[2];
524 out_tri2.t[2] = in_tri.t[2];
525
526 // Return signed shortest distance from point to plane, plane normal must be normalised
527 auto dist = [&](vec3d &p)
528 {
529 vec3d n = Math::Vec_Normalise(p);
530 return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Math::Vec_DotProduct(plane_n, plane_p));
531 };
532
533 // Create two temporary storage arrays to classify points either side of plane
534 // If distance sign is positive, point lies on "inside" of plane
535 vec3d* inside_points[3]; int nInsidePointCount = 0;
536 vec3d* outside_points[3]; int nOutsidePointCount = 0;
537 vec2d* inside_tex[3]; int nInsideTexCount = 0;
538 vec2d* outside_tex[3]; int nOutsideTexCount = 0;
539
540
541 // Get signed distance of each point in triangle to plane
542 float d0 = dist(in_tri.p[0]);
543 float d1 = dist(in_tri.p[1]);
544 float d2 = dist(in_tri.p[2]);
545
546 if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.t[0]; }
547 else {
548 outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.t[0];
549 }
550 if (d1 >= 0) {
551 inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.t[1];
552 }
553 else {
554 outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.t[1];
555 }
556 if (d2 >= 0) {
557 inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.t[2];
558 }
559 else {
560 outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.t[2];
561 }
562
563 // Now classify triangle points, and break the input triangle into
564 // smaller output triangles if required. There are four possible
565 // outcomes...
566
567 if (nInsidePointCount == 0)
568 {
569 // All points lie on the outside of plane, so clip whole triangle
570 // It ceases to exist
571
572 return 0; // No returned triangles are valid
573 }
574
575 if (nInsidePointCount == 3)
576 {
577 // All points lie on the inside of plane, so do nothing
578 // and allow the triangle to simply pass through
579 out_tri1 = in_tri;
580
581 return 1; // Just the one returned original triangle is valid
582 }
583
584 if (nInsidePointCount == 1 && nOutsidePointCount == 2)
585 {
586 // Triangle should be clipped. As two points lie outside
587 // the plane, the triangle simply becomes a smaller triangle
588
589 // Copy appearance info to new triangle
590 out_tri1.col[0] = in_tri.col[0];
591 out_tri1.col[1] = in_tri.col[1];
592 out_tri1.col[2] = in_tri.col[2];
593
594 // The inside point is valid, so keep that...
595 out_tri1.p[0] = *inside_points[0];
596 out_tri1.t[0] = *inside_tex[0];
597
598 // but the two new points are at the locations where the
599 // original sides of the triangle (lines) intersect with the plane
600 float t;
601 out_tri1.p[1] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t);
602 out_tri1.t[1].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x;
603 out_tri1.t[1].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y;
604 out_tri1.t[1].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z;
605
606 out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t);
607 out_tri1.t[2].x = t * (outside_tex[1]->x - inside_tex[0]->x) + inside_tex[0]->x;
608 out_tri1.t[2].y = t * (outside_tex[1]->y - inside_tex[0]->y) + inside_tex[0]->y;
609 out_tri1.t[2].z = t * (outside_tex[1]->z - inside_tex[0]->z) + inside_tex[0]->z;
610
611 return 1; // Return the newly formed single triangle
612 }
613
614 if (nInsidePointCount == 2 && nOutsidePointCount == 1)
615 {
616 // Triangle should be clipped. As two points lie inside the plane,
617 // the clipped triangle becomes a "quad". Fortunately, we can
618 // represent a quad with two new triangles
619
620 // Copy appearance info to new triangles
621 out_tri1.col[0] = in_tri.col[0];
622 out_tri2.col[0] = in_tri.col[0];
623 out_tri1.col[1] = in_tri.col[1];
624 out_tri2.col[1] = in_tri.col[1];
625 out_tri1.col[2] = in_tri.col[2];
626 out_tri2.col[2] = in_tri.col[2];
627
628 // The first triangle consists of the two inside points and a new
629 // point determined by the location where one side of the triangle
630 // intersects with the plane
631 out_tri1.p[0] = *inside_points[0];
632 out_tri1.t[0] = *inside_tex[0];
633
634 out_tri1.p[1] = *inside_points[1];
635 out_tri1.t[1] = *inside_tex[1];
636
637 float t;
638 out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t);
639 out_tri1.t[2].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x;
640 out_tri1.t[2].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y;
641 out_tri1.t[2].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z;
642
643 // The second triangle is composed of one of he inside points, a
644 // new point determined by the intersection of the other side of the
645 // triangle and the plane, and the newly created point above
646 out_tri2.p[1] = *inside_points[1];
647 out_tri2.t[1] = *inside_tex[1];
648 out_tri2.p[0] = out_tri1.p[2];
649 out_tri2.t[0] = out_tri1.t[2];
650 out_tri2.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t);
651 out_tri2.t[2].x = t * (outside_tex[0]->x - inside_tex[1]->x) + inside_tex[1]->x;
652 out_tri2.t[2].y = t * (outside_tex[0]->y - inside_tex[1]->y) + inside_tex[1]->y;
653 out_tri2.t[2].z = t * (outside_tex[0]->z - inside_tex[1]->z) + inside_tex[1]->z;
654 return 2; // Return two newly formed triangles which form a quad
655 }
656
657 return 0;
658 }
659
661 {
662 pge->FillTriangle((int32_t)tri.p[0].x, (int32_t)tri.p[0].y, (int32_t)tri.p[1].x, (int32_t)tri.p[1].y, (int32_t)tri.p[2].x, (int32_t)tri.p[2].y, tri.col[0]);
663 }
664
666 {
667 pge->DrawTriangle((int32_t)tri.p[0].x, (int32_t)tri.p[0].y, (int32_t)tri.p[1].x, (int32_t)tri.p[1].y, (int32_t)tri.p[2].x, (int32_t)tri.p[2].y, col);
668 }
669
670 void GFX3D::TexturedTriangle(int x1, int y1, float u1, float v1, float w1,
671 int x2, int y2, float u2, float v2, float w2,
672 int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr)
673
674 {
675 if (y2 < y1)
676 {
677 std::swap(y1, y2);
678 std::swap(x1, x2);
679 std::swap(u1, u2);
680 std::swap(v1, v2);
681 std::swap(w1, w2);
682 }
683
684 if (y3 < y1)
685 {
686 std::swap(y1, y3);
687 std::swap(x1, x3);
688 std::swap(u1, u3);
689 std::swap(v1, v3);
690 std::swap(w1, w3);
691 }
692
693 if (y3 < y2)
694 {
695 std::swap(y2, y3);
696 std::swap(x2, x3);
697 std::swap(u2, u3);
698 std::swap(v2, v3);
699 std::swap(w2, w3);
700 }
701
702 int dy1 = y2 - y1;
703 int dx1 = x2 - x1;
704 float dv1 = v2 - v1;
705 float du1 = u2 - u1;
706 float dw1 = w2 - w1;
707
708 int dy2 = y3 - y1;
709 int dx2 = x3 - x1;
710 float dv2 = v3 - v1;
711 float du2 = u3 - u1;
712 float dw2 = w3 - w1;
713
714 float tex_u, tex_v, tex_w;
715
716 float dax_step = 0, dbx_step = 0,
717 du1_step = 0, dv1_step = 0,
718 du2_step = 0, dv2_step = 0,
719 dw1_step = 0, dw2_step = 0;
720
721 if (dy1) dax_step = dx1 / (float)abs(dy1);
722 if (dy2) dbx_step = dx2 / (float)abs(dy2);
723
724 if (dy1) du1_step = du1 / (float)abs(dy1);
725 if (dy1) dv1_step = dv1 / (float)abs(dy1);
726 if (dy1) dw1_step = dw1 / (float)abs(dy1);
727
728 if (dy2) du2_step = du2 / (float)abs(dy2);
729 if (dy2) dv2_step = dv2 / (float)abs(dy2);
730 if (dy2) dw2_step = dw2 / (float)abs(dy2);
731
732 if (dy1)
733 {
734 for (int i = y1; i <= y2; i++)
735 {
736 int ax = int(x1 + (float)(i - y1) * dax_step);
737 int bx = int(x1 + (float)(i - y1) * dbx_step);
738
739 float tex_su = u1 + (float)(i - y1) * du1_step;
740 float tex_sv = v1 + (float)(i - y1) * dv1_step;
741 float tex_sw = w1 + (float)(i - y1) * dw1_step;
742
743 float tex_eu = u1 + (float)(i - y1) * du2_step;
744 float tex_ev = v1 + (float)(i - y1) * dv2_step;
745 float tex_ew = w1 + (float)(i - y1) * dw2_step;
746
747 if (ax > bx)
748 {
749 std::swap(ax, bx);
750 std::swap(tex_su, tex_eu);
751 std::swap(tex_sv, tex_ev);
752 std::swap(tex_sw, tex_ew);
753 }
754
755 tex_u = tex_su;
756 tex_v = tex_sv;
757 tex_w = tex_sw;
758
759 float tstep = 1.0f / ((float)(bx - ax));
760 float t = 0.0f;
761
762 for (int j = ax; j < bx; j++)
763 {
764 tex_u = (1.0f - t) * tex_su + t * tex_eu;
765 tex_v = (1.0f - t) * tex_sv + t * tex_ev;
766 tex_w = (1.0f - t) * tex_sw + t * tex_ew;
767 if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j])
768 {
769 /*if (bMipMap)
770 pge->Draw(j, i, ((olc::GFX3D::MipMap*)spr)->Sample(tex_u / tex_w, tex_v / tex_w, tex_w));
771 else*/
772 if(pge->Draw(j, i, spr != nullptr ? spr->Sample(tex_u / tex_w, tex_v / tex_w) : olc::GREY))
773 m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w;
774 }
775 t += tstep;
776 }
777
778 }
779 }
780
781 dy1 = y3 - y2;
782 dx1 = x3 - x2;
783 dv1 = v3 - v2;
784 du1 = u3 - u2;
785 dw1 = w3 - w2;
786
787 if (dy1) dax_step = dx1 / (float)abs(dy1);
788 if (dy2) dbx_step = dx2 / (float)abs(dy2);
789
790 du1_step = 0, dv1_step = 0;
791 if (dy1) du1_step = du1 / (float)abs(dy1);
792 if (dy1) dv1_step = dv1 / (float)abs(dy1);
793 if (dy1) dw1_step = dw1 / (float)abs(dy1);
794
795 if (dy1)
796 {
797 for (int i = y2; i <= y3; i++)
798 {
799 int ax = int(x2 + (float)(i - y2) * dax_step);
800 int bx = int(x1 + (float)(i - y1) * dbx_step);
801
802 float tex_su = u2 + (float)(i - y2) * du1_step;
803 float tex_sv = v2 + (float)(i - y2) * dv1_step;
804 float tex_sw = w2 + (float)(i - y2) * dw1_step;
805
806 float tex_eu = u1 + (float)(i - y1) * du2_step;
807 float tex_ev = v1 + (float)(i - y1) * dv2_step;
808 float tex_ew = w1 + (float)(i - y1) * dw2_step;
809
810 if (ax > bx)
811 {
812 std::swap(ax, bx);
813 std::swap(tex_su, tex_eu);
814 std::swap(tex_sv, tex_ev);
815 std::swap(tex_sw, tex_ew);
816 }
817
818 tex_u = tex_su;
819 tex_v = tex_sv;
820 tex_w = tex_sw;
821
822 float tstep = 1.0f / ((float)(bx - ax));
823 float t = 0.0f;
824
825 for (int j = ax; j < bx; j++)
826 {
827 tex_u = (1.0f - t) * tex_su + t * tex_eu;
828 tex_v = (1.0f - t) * tex_sv + t * tex_ev;
829 tex_w = (1.0f - t) * tex_sw + t * tex_ew;
830
831 if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j])
832 {
833 /*if(bMipMap)
834 pge->Draw(j, i, ((olc::GFX3D::MipMap*)spr)->Sample(tex_u / tex_w, tex_v / tex_w, tex_w));
835 else*/
836 if(pge->Draw(j, i, spr != nullptr ? spr->Sample(tex_u / tex_w, tex_v / tex_w) : olc::GREY))
837 m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w;
838 }
839 t += tstep;
840 }
841 }
842 }
843 }
844
845
847 {
848
849 }
850
851 float* GFX3D::m_DepthBuffer = nullptr;
852
854 {
855 m_DepthBuffer = new float[pge->ScreenWidth() * pge->ScreenHeight()]{ 0 };
856 }
857
858
859 void GFX3D::ClearDepth()
860 {
861 memset(m_DepthBuffer, 0, pge->ScreenWidth() * pge->ScreenHeight() * sizeof(float));
862 }
863
864 bool GFX3D::mesh::LoadOBJFile(std::string sFilename, bool bHasTexture)
865 {
866 std::ifstream f(sFilename);
867 if (!f.is_open()) return false;
868
869 // Local cache of verts
870 std::vector<vec3d> verts;
871 std::vector<vec3d> norms;
872 std::vector<vec2d> texs;
873
874 while (!f.eof())
875 {
876 char line[128];
877 f.getline(line, 128);
878
879 std::stringstream s;
880 s << line;
881
882 char junk;
883
884 if (line[0] == 'v')
885 {
886 if (line[1] == 't')
887 {
888 vec2d v;
889 s >> junk >> junk >> v.x >> v.y;
890 //v.x = 1.0f - v.x;
891 v.y = 1.0f - v.y;
892 texs.push_back(v);
893 }
894 else if (line[1] == 'n')
895 {
896 vec3d v;
897 s >> junk >> junk >> v.x >> v.y >> v.z;
898 norms.push_back(v);
899 }
900 else
901 {
902 vec3d v;
903 s >> junk >> v.x >> v.y >> v.z;
904 verts.push_back(v);
905 }
906 }
907
908
909 /*if (!bHasTexture)
910 {
911 if (line[0] == 'f')
912 {
913 int f[3];
914 s >> junk >> f[0] >> f[1] >> f[2];
915 tris.push_back({ verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1] });
916 }
917 }
918 else*/
919 {
920 if (line[0] == 'f')
921 {
922 s >> junk;
923
924 std::string tokens[9];
925 int nTokenCount = -1;
926 while (!s.eof())
927 {
928 char c = s.get();
929 if (c == ' ' || c == '/')
930 {
931 if (tokens[nTokenCount].size() > 0)
932 {
933 nTokenCount++;
934 }
935 }
936 else
937 tokens[nTokenCount].append(1, c);
938 }
939
940 tokens[nTokenCount].pop_back();
941
942 int stride = 1;
943 if (!texs.empty()) stride++;
944 if (!norms.empty()) stride++;
945
946 if (!texs.empty())
947 {
948 tris.push_back({
949 verts[stoi(tokens[0 * stride]) - 1],
950 verts[stoi(tokens[1 * stride]) - 1],
951 verts[stoi(tokens[2 * stride]) - 1],
952 texs[stoi(tokens[0 * stride + 1]) - 1],
953 texs[stoi(tokens[1 * stride + 1]) - 1],
954 texs[stoi(tokens[2 * stride + 1]) - 1],
956 }
957 else
958 {
959 tris.push_back({
960 verts[stoi(tokens[0 * stride]) - 1],
961 verts[stoi(tokens[1 * stride]) - 1],
962 verts[stoi(tokens[2 * stride]) - 1],
963 olc::GFX3D::vec2d{0,0,0},
964 olc::GFX3D::vec2d{0,0,0},
965 olc::GFX3D::vec2d{0,0,0},
967
968 }
969 }
970 }
971 }
972 return true;
973 }
974
975
977 {
978 //bUseMipMap = false;
979 }
980
981 void GFX3D::PipeLine::SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight)
982 {
983 matProj = GFX3D::Math::Mat_MakeProjection(fFovDegrees, fAspectRatio, fNear, fFar);
984 fViewX = fLeft;
985 fViewY = fTop;
986 fViewW = fWidth;
987 fViewH = fHeight;
988 }
989
991 {
992 matView = GFX3D::Math::Mat_PointAt(pos, lookat, up);
993 matView = GFX3D::Math::Mat_QuickInverse(matView);
994 }
995
997 {
998 matWorld = transform;
999 }
1000
1002 {
1003 sprTexture = texture;
1004 //bUseMipMap = false;
1005 }
1006
1007 /*void GFX3D::PipeLine::SetMipMapTexture(olc::GFX3D::MipMap *texture)
1008 {
1009 sprMipMap = texture;
1010 bUseMipMap = true;
1011 }*/
1012
1013 void GFX3D::PipeLine::SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir, float fParam)
1014 {
1015 if (nSlot < 4)
1016 {
1017 lights[nSlot].type = nType;
1018 lights[nSlot].pos = pos;
1019 lights[nSlot].dir = dir;
1020 lights[nSlot].col = col;
1021 lights[nSlot].param = fParam;
1022 }
1023 }
1024
1025 uint32_t GFX3D::PipeLine::Render(std::vector<olc::GFX3D::triangle> &triangles, uint32_t flags)
1026 {
1027 return Render(triangles, flags, 0, triangles.size());
1028 }
1029
1031 {
1032 // Coordinates are assumed to be in world space
1033 olc::GFX3D::vec3d t1, t2;
1034
1035 // Transform into view
1036 t1 = GFX3D::Math::Mat_MultiplyVector(matView, p1);
1037 t2 = GFX3D::Math::Mat_MultiplyVector(matView, p2);
1038
1039 // Project onto screen
1040 t1 = GFX3D::Math::Mat_MultiplyVector(matProj, t1);
1041 t2 = GFX3D::Math::Mat_MultiplyVector(matProj, t2);
1042
1043 // Project
1044 t1.x = t1.x / t1.w;
1045 t1.y = t1.y / t1.w;
1046 t1.z = t1.z / t1.w;
1047
1048 t2.x = t2.x / t2.w;
1049 t2.y = t2.y / t2.w;
1050 t2.z = t2.z / t2.w;
1051
1052 vec3d vOffsetView = { 1,1,0 };
1053 t1 = Math::Vec_Add(t1, vOffsetView);
1054 t2 = Math::Vec_Add(t2, vOffsetView);
1055
1056 t1.x *= 0.5f * fViewW;
1057 t1.y *= 0.5f * fViewH;
1058 t2.x *= 0.5f * fViewW;
1059 t2.y *= 0.5f * fViewH;
1060
1061 vOffsetView = { fViewX,fViewY,0 };
1062 t1 = Math::Vec_Add(t1, vOffsetView);
1063 t2 = Math::Vec_Add(t2, vOffsetView);
1064
1065 pge->DrawLine((int32_t)t1.x, (int32_t)t1.y, (int32_t)t2.x, (int32_t)t2.y, col);
1066
1067 return 0;
1068 }
1069
1071 {
1072 // Coordinates are assumed to be in world space
1074 olc::GFX3D::vec3d t2 = { p1.x + r, p1.y, p1.z };
1075
1076 // Transform into view
1077 t1 = GFX3D::Math::Mat_MultiplyVector(matView, p1);
1078 t2 = GFX3D::Math::Mat_MultiplyVector(matView, t2);
1079
1080 // Project onto screen
1081 t1 = GFX3D::Math::Mat_MultiplyVector(matProj, t1);
1082 t2 = GFX3D::Math::Mat_MultiplyVector(matProj, t2);
1083
1084 // Project
1085 t1.x = t1.x / t1.w;
1086 t1.y = t1.y / t1.w;
1087 t1.z = t1.z / t1.w;
1088
1089 t2.x = t2.x / t2.w;
1090 t2.y = t2.y / t2.w;
1091 t2.z = t2.z / t2.w;
1092
1093 vec3d vOffsetView = { 1,1,0 };
1094 t1 = Math::Vec_Add(t1, vOffsetView);
1095 t2 = Math::Vec_Add(t2, vOffsetView);
1096
1097 t1.x *= 0.5f * fViewW;
1098 t1.y *= 0.5f * fViewH;
1099 t2.x *= 0.5f * fViewW;
1100 t2.y *= 0.5f * fViewH;
1101
1102 vOffsetView = { fViewX,fViewY,0 };
1103 t1 = Math::Vec_Add(t1, vOffsetView);
1104 t2 = Math::Vec_Add(t2, vOffsetView);
1105
1106 pge->FillCircle((int32_t)t1.x, (int32_t)t1.y, (int32_t)fabs(t2.x - t1.x), col);
1107
1108 return 0;
1109 }
1110
1111 uint32_t GFX3D::PipeLine::Render(std::vector<olc::GFX3D::triangle> &triangles, uint32_t flags, int nOffset, int nCount)
1112 {
1113 // Calculate Transformation Matrix
1114 mat4x4 matWorldView = Math::Mat_MultiplyMatrix(matWorld, matView);
1115 //matWorldViewProj = Math::Mat_MultiplyMatrix(matWorldView, matProj);
1116
1117 // Store triangles for rastering later
1118 std::vector<GFX3D::triangle> vecTrianglesToRaster;
1119
1120 int nTriangleDrawnCount = 0;
1121
1122 // Process Triangles
1123 //for (auto &tri : triangles)
1124// omp_set_dynamic(0);
1125// omp_set_num_threads(4);
1126//#pragma omp parallel for schedule(static)
1127 for(int tx = nOffset; tx < nOffset+nCount; tx++)
1128 {
1129 GFX3D::triangle &tri = triangles[tx];
1130 GFX3D::triangle triTransformed;
1131
1132 // Just copy through texture coordinates
1133 triTransformed.t[0] = { tri.t[0].x, tri.t[0].y, tri.t[0].z };
1134 triTransformed.t[1] = { tri.t[1].x, tri.t[1].y, tri.t[1].z };
1135 triTransformed.t[2] = { tri.t[2].x, tri.t[2].y, tri.t[2].z }; // Think!
1136
1137 // Dont forget vertex colours
1138 triTransformed.col[0] = tri.col[0];
1139 triTransformed.col[1] = tri.col[1];
1140 triTransformed.col[2] = tri.col[2];
1141
1142 // Transform Triangle from object into projected space
1143 triTransformed.p[0] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[0]);
1144 triTransformed.p[1] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[1]);
1145 triTransformed.p[2] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[2]);
1146
1147 // Calculate Triangle Normal in WorldView Space
1148 GFX3D::vec3d normal, line1, line2;
1149 line1 = GFX3D::Math::Vec_Sub(triTransformed.p[1], triTransformed.p[0]);
1150 line2 = GFX3D::Math::Vec_Sub(triTransformed.p[2], triTransformed.p[0]);
1151 normal = GFX3D::Math::Vec_CrossProduct(line1, line2);
1152 normal = GFX3D::Math::Vec_Normalise(normal);
1153
1154 // Cull triangles that face away from viewer
1155 if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue;
1156 if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue;
1157
1158 // If Lighting, calculate shading
1159 if (flags & RENDER_LIGHTS)
1160 {
1161 olc::Pixel ambient_clamp = { 0,0,0 };
1162 olc::Pixel light_combined = { 0,0,0 };
1163 uint32_t nLightSources = 0;
1164 float nLightR = 0, nLightG = 0, nLightB = 0;
1165
1166 for (int i = 0; i < 4; i++)
1167 {
1168 switch (lights[i].type)
1169 {
1170 case LIGHT_DISABLED:
1171 break;
1172 case LIGHT_AMBIENT:
1173 ambient_clamp = lights[i].col;
1174 break;
1175 case LIGHT_DIRECTIONAL:
1176 {
1177 nLightSources++;
1178 GFX3D::vec3d light_dir = GFX3D::Math::Vec_Normalise(lights[i].dir);
1179 float light = GFX3D::Math::Vec_DotProduct(light_dir, normal);
1180 if (light > 0)
1181 {
1182 int j = 0;
1183 }
1184
1185 light = std::max(light, 0.0f);
1186 nLightR += light * (lights[i].col.r/255.0f);
1187 nLightG += light * (lights[i].col.g/255.0f);
1188 nLightB += light * (lights[i].col.b/255.0f);
1189 }
1190 break;
1191 case LIGHT_POINT:
1192 break;
1193 }
1194 }
1195
1196 //nLightR /= nLightSources;
1197 //nLightG /= nLightSources;
1198 //nLightB /= nLightSources;
1199
1200 nLightR = std::max(nLightR, ambient_clamp.r / 255.0f);
1201 nLightG = std::max(nLightG, ambient_clamp.g / 255.0f);
1202 nLightB = std::max(nLightB, ambient_clamp.b / 255.0f);
1203
1204 triTransformed.col[0] = olc::Pixel(uint8_t(nLightR * triTransformed.col[0].r), uint8_t(nLightG * triTransformed.col[0].g), uint8_t(nLightB * triTransformed.col[0].b));
1205 triTransformed.col[1] = olc::Pixel(uint8_t(nLightR * triTransformed.col[1].r), uint8_t(nLightG * triTransformed.col[1].g), uint8_t(nLightB * triTransformed.col[1].b));
1206 triTransformed.col[2] = olc::Pixel(uint8_t(nLightR * triTransformed.col[2].r), uint8_t(nLightG * triTransformed.col[2].g), uint8_t(nLightB * triTransformed.col[2].b));
1207
1208
1209
1210 /*GFX3D::vec3d light_dir = { 1,1,1 };
1211 light_dir = GFX3D::Math::Vec_Normalise(light_dir);
1212 float light = GFX3D::Math::Vec_DotProduct(light_dir, normal);
1213 if (light < 0) light = 0;
1214 triTransformed.col[0] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f);
1215 triTransformed.col[1] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f);
1216 triTransformed.col[2] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f);*/
1217 }
1218 //else
1219 // triTransformed.col = olc::WHITE;
1220
1221 // Clip triangle against near plane
1222 int nClippedTriangles = 0;
1223 GFX3D::triangle clipped[2];
1224 nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]);
1225
1226 // This may yield two new triangles
1227 for (int n = 0; n < nClippedTriangles; n++)
1228 {
1229 triangle triProjected = clipped[n];
1230
1231 // Project new triangle
1232 triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[0]);
1233 triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[1]);
1234 triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[2]);
1235
1236 // Apply Projection to Verts
1237 triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w;
1238 triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w;
1239 triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w;
1240
1241 triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w;
1242 triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w;
1243 triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w;
1244
1245 triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w;
1246 triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w;
1247 triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w;
1248
1249 // Apply Projection to Tex coords
1250 triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w;
1251 triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w;
1252 triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w;
1253
1254 triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w;
1255 triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w;
1256 triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w;
1257
1258 triProjected.t[0].z = 1.0f / triProjected.p[0].w;
1259 triProjected.t[1].z = 1.0f / triProjected.p[1].w;
1260 triProjected.t[2].z = 1.0f / triProjected.p[2].w;
1261
1262 // Clip against viewport in screen space
1263 // Clip triangles against all four screen edges, this could yield
1264 // a bunch of triangles, so create a queue that we traverse to
1265 // ensure we only test new triangles generated against planes
1266 GFX3D::triangle sclipped[2];
1267 std::list<GFX3D::triangle> listTriangles;
1268
1269
1270 // Add initial triangle
1271 listTriangles.push_back(triProjected);
1272 int nNewTriangles = 1;
1273
1274 for (int p = 0; p < 4; p++)
1275 {
1276 int nTrisToAdd = 0;
1277 while (nNewTriangles > 0)
1278 {
1279 // Take triangle from front of queue
1280 triangle test = listTriangles.front();
1281 listTriangles.pop_front();
1282 nNewTriangles--;
1283
1284 // Clip it against a plane. We only need to test each
1285 // subsequent plane, against subsequent new triangles
1286 // as all triangles after a plane clip are guaranteed
1287 // to lie on the inside of the plane. I like how this
1288 // comment is almost completely and utterly justified
1289 switch (p)
1290 {
1291 case 0: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break;
1292 case 1: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, +1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break;
1293 case 2: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break;
1294 case 3: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ +1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break;
1295 }
1296
1297
1298 // Clipping may yield a variable number of triangles, so
1299 // add these new ones to the back of the queue for subsequent
1300 // clipping against next planes
1301 for (int w = 0; w < nTrisToAdd; w++)
1302 listTriangles.push_back(sclipped[w]);
1303 }
1304 nNewTriangles = listTriangles.size();
1305 }
1306
1307 for (auto &triRaster : listTriangles)
1308 {
1309 // Scale to viewport
1310 /*triRaster.p[0].x *= -1.0f;
1311 triRaster.p[1].x *= -1.0f;
1312 triRaster.p[2].x *= -1.0f;
1313 triRaster.p[0].y *= -1.0f;
1314 triRaster.p[1].y *= -1.0f;
1315 triRaster.p[2].y *= -1.0f;*/
1316 vec3d vOffsetView = { 1,1,0 };
1317 triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView);
1318 triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView);
1319 triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView);
1320 triRaster.p[0].x *= 0.5f * fViewW;
1321 triRaster.p[0].y *= 0.5f * fViewH;
1322 triRaster.p[1].x *= 0.5f * fViewW;
1323 triRaster.p[1].y *= 0.5f * fViewH;
1324 triRaster.p[2].x *= 0.5f * fViewW;
1325 triRaster.p[2].y *= 0.5f * fViewH;
1326 vOffsetView = { fViewX,fViewY,0 };
1327 triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView);
1328 triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView);
1329 triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView);
1330
1331 // For now, just draw triangle
1332
1333 //if (flags & RENDER_TEXTURED)
1334 //{/*
1335 // TexturedTriangle(
1336 // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z,
1337 // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z,
1338 // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z,
1339 // sprTexture);*/
1340
1341 // RasterTriangle(
1342 // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col,
1343 // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col,
1344 // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col,
1345 // sprTexture, nFlags);
1346
1347 //}
1348
1349 if (flags & RENDER_WIRE)
1350 {
1351 DrawTriangleWire(triRaster, olc::RED);
1352 }
1353 else
1354 {
1356 (int)triRaster.p[0].x,(int)triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col[0],
1357 (int)triRaster.p[1].x,(int)triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col[1],
1358 (int)triRaster.p[2].x,(int)triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col[2],
1359 sprTexture, flags);
1360
1361 }
1362
1363
1364
1365
1366 nTriangleDrawnCount++;
1367 }
1368 }
1369 }
1370
1371 return nTriangleDrawnCount;
1372 }
1373
1374 void GFX3D::RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1,
1375 int x2, int y2, float u2, float v2, float w2, olc::Pixel c2,
1376 int x3, int y3, float u3, float v3, float w3, olc::Pixel c3,
1377 olc::Sprite* spr,
1378 uint32_t nFlags)
1379
1380 {
1381 if (y2 < y1)
1382 {
1383 std::swap(y1, y2); std::swap(x1, x2); std::swap(u1, u2); std::swap(v1, v2); std::swap(w1, w2); std::swap(c1, c2);
1384 }
1385
1386 if (y3 < y1)
1387 {
1388 std::swap(y1, y3); std::swap(x1, x3); std::swap(u1, u3); std::swap(v1, v3); std::swap(w1, w3); std::swap(c1, c3);
1389 }
1390
1391 if (y3 < y2)
1392 {
1393 std::swap(y2, y3); std::swap(x2, x3); std::swap(u2, u3); std::swap(v2, v3); std::swap(w2, w3); std::swap(c2, c3);
1394 }
1395
1396 int dy1 = y2 - y1;
1397 int dx1 = x2 - x1;
1398 float dv1 = v2 - v1;
1399 float du1 = u2 - u1;
1400 float dw1 = w2 - w1;
1401 int dcr1 = c2.r - c1.r;
1402 int dcg1 = c2.g - c1.g;
1403 int dcb1 = c2.b - c1.b;
1404 int dca1 = c2.a - c1.a;
1405
1406 int dy2 = y3 - y1;
1407 int dx2 = x3 - x1;
1408 float dv2 = v3 - v1;
1409 float du2 = u3 - u1;
1410 float dw2 = w3 - w1;
1411 int dcr2 = c3.r - c1.r;
1412 int dcg2 = c3.g - c1.g;
1413 int dcb2 = c3.b - c1.b;
1414 int dca2 = c3.a - c1.a;
1415
1416 float tex_u, tex_v, tex_w;
1417 float col_r, col_g, col_b, col_a;
1418
1419 float dax_step = 0, dbx_step = 0,
1420 du1_step = 0, dv1_step = 0,
1421 du2_step = 0, dv2_step = 0,
1422 dw1_step = 0, dw2_step = 0,
1423 dcr1_step = 0, dcr2_step = 0,
1424 dcg1_step = 0, dcg2_step = 0,
1425 dcb1_step = 0, dcb2_step = 0,
1426 dca1_step = 0, dca2_step = 0;
1427
1428 if (dy1) dax_step = dx1 / (float)abs(dy1);
1429 if (dy2) dbx_step = dx2 / (float)abs(dy2);
1430
1431 if (dy1) du1_step = du1 / (float)abs(dy1);
1432 if (dy1) dv1_step = dv1 / (float)abs(dy1);
1433 if (dy1) dw1_step = dw1 / (float)abs(dy1);
1434
1435 if (dy2) du2_step = du2 / (float)abs(dy2);
1436 if (dy2) dv2_step = dv2 / (float)abs(dy2);
1437 if (dy2) dw2_step = dw2 / (float)abs(dy2);
1438
1439 if (dy1) dcr1_step = dcr1 / (float)abs(dy1);
1440 if (dy1) dcg1_step = dcg1 / (float)abs(dy1);
1441 if (dy1) dcb1_step = dcb1 / (float)abs(dy1);
1442 if (dy1) dca1_step = dca1 / (float)abs(dy1);
1443
1444 if (dy2) dcr2_step = dcr2 / (float)abs(dy2);
1445 if (dy2) dcg2_step = dcg2 / (float)abs(dy2);
1446 if (dy2) dcb2_step = dcb2 / (float)abs(dy2);
1447 if (dy2) dca2_step = dca2 / (float)abs(dy2);
1448
1449 float pixel_r = 0.0f;
1450 float pixel_g = 0.0f;
1451 float pixel_b = 0.0f;
1452 float pixel_a = 1.0f;
1453
1454 if (dy1)
1455 {
1456 for (int i = y1; i <= y2; i++)
1457 {
1458 int ax = int(x1 + (float)(i - y1) * dax_step);
1459 int bx = int(x1 + (float)(i - y1) * dbx_step);
1460
1461 float tex_su = u1 + (float)(i - y1) * du1_step;
1462 float tex_sv = v1 + (float)(i - y1) * dv1_step;
1463 float tex_sw = w1 + (float)(i - y1) * dw1_step;
1464
1465 float tex_eu = u1 + (float)(i - y1) * du2_step;
1466 float tex_ev = v1 + (float)(i - y1) * dv2_step;
1467 float tex_ew = w1 + (float)(i - y1) * dw2_step;
1468
1469 float col_sr = c1.r + (float)(i - y1) * dcr1_step;
1470 float col_sg = c1.g + (float)(i - y1) * dcg1_step;
1471 float col_sb = c1.b + (float)(i - y1) * dcb1_step;
1472 float col_sa = c1.a + (float)(i - y1) * dca1_step;
1473
1474 float col_er = c1.r + (float)(i - y1) * dcr2_step;
1475 float col_eg = c1.g + (float)(i - y1) * dcg2_step;
1476 float col_eb = c1.b + (float)(i - y1) * dcb2_step;
1477 float col_ea = c1.a + (float)(i - y1) * dca2_step;
1478
1479 if (ax > bx)
1480 {
1481 std::swap(ax, bx);
1482 std::swap(tex_su, tex_eu);
1483 std::swap(tex_sv, tex_ev);
1484 std::swap(tex_sw, tex_ew);
1485 std::swap(col_sr, col_er);
1486 std::swap(col_sg, col_eg);
1487 std::swap(col_sb, col_eb);
1488 std::swap(col_sa, col_ea);
1489 }
1490
1491 tex_u = tex_su;
1492 tex_v = tex_sv;
1493 tex_w = tex_sw;
1494 col_r = col_sr;
1495 col_g = col_sg;
1496 col_b = col_sb;
1497 col_a = col_sa;
1498
1499 float tstep = 1.0f / ((float)(bx - ax));
1500 float t = 0.0f;
1501
1502 for (int j = ax; j < bx; j++)
1503 {
1504 tex_u = (1.0f - t) * tex_su + t * tex_eu;
1505 tex_v = (1.0f - t) * tex_sv + t * tex_ev;
1506 tex_w = (1.0f - t) * tex_sw + t * tex_ew;
1507 col_r = (1.0f - t) * col_sr + t * col_er;
1508 col_g = (1.0f - t) * col_sg + t * col_eg;
1509 col_b = (1.0f - t) * col_sb + t * col_eb;
1510 col_a = (1.0f - t) * col_sa + t * col_ea;
1511
1512 pixel_r = col_r;
1513 pixel_g = col_g;
1514 pixel_b = col_b;
1515 pixel_a = col_a;
1516
1517 if (nFlags & GFX3D::RENDER_TEXTURED)
1518 {
1519 if (spr != nullptr)
1520 {
1521 olc::Pixel sample = spr->Sample(tex_u / tex_w, tex_v / tex_w);
1522 pixel_r *= sample.r / 255.0f;
1523 pixel_g *= sample.g / 255.0f;
1524 pixel_b *= sample.b / 255.0f;
1525 pixel_a *= sample.a / 255.0f;
1526 }
1527 }
1528
1529 if (nFlags & GFX3D::RENDER_DEPTH)
1530 {
1531 if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j])
1532 if (pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f))))
1533 m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w;
1534 }
1535 else
1536 {
1537 pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f)));
1538 }
1539
1540 t += tstep;
1541 }
1542 }
1543 }
1544
1545 dy1 = y3 - y2;
1546 dx1 = x3 - x2;
1547 dv1 = v3 - v2;
1548 du1 = u3 - u2;
1549 dw1 = w3 - w2;
1550 dcr1 = c3.r - c2.r;
1551 dcg1 = c3.g - c2.g;
1552 dcb1 = c3.b - c2.b;
1553 dca1 = c3.a - c2.a;
1554
1555 if (dy1) dax_step = dx1 / (float)abs(dy1);
1556 if (dy2) dbx_step = dx2 / (float)abs(dy2);
1557
1558 du1_step = 0; dv1_step = 0;
1559 if (dy1) du1_step = du1 / (float)abs(dy1);
1560 if (dy1) dv1_step = dv1 / (float)abs(dy1);
1561 if (dy1) dw1_step = dw1 / (float)abs(dy1);
1562
1563 dcr1_step = 0; dcg1_step = 0; dcb1_step = 0; dca1_step = 0;
1564 if (dy1) dcr1_step = dcr1 / (float)abs(dy1);
1565 if (dy1) dcg1_step = dcg1 / (float)abs(dy1);
1566 if (dy1) dcb1_step = dcb1 / (float)abs(dy1);
1567 if (dy1) dca1_step = dca1 / (float)abs(dy1);
1568
1569 if (dy1)
1570 {
1571 for (int i = y2; i <= y3; i++)
1572 {
1573 int ax = int(x2 + (float)(i - y2) * dax_step);
1574 int bx = int(x1 + (float)(i - y1) * dbx_step);
1575
1576 float tex_su = u2 + (float)(i - y2) * du1_step;
1577 float tex_sv = v2 + (float)(i - y2) * dv1_step;
1578 float tex_sw = w2 + (float)(i - y2) * dw1_step;
1579
1580 float tex_eu = u1 + (float)(i - y1) * du2_step;
1581 float tex_ev = v1 + (float)(i - y1) * dv2_step;
1582 float tex_ew = w1 + (float)(i - y1) * dw2_step;
1583
1584 float col_sr = c2.r + (float)(i - y2) * dcr1_step;
1585 float col_sg = c2.g + (float)(i - y2) * dcg1_step;
1586 float col_sb = c2.b + (float)(i - y2) * dcb1_step;
1587 float col_sa = c2.a + (float)(i - y2) * dca1_step;
1588
1589 float col_er = c1.r + (float)(i - y1) * dcr2_step;
1590 float col_eg = c1.g + (float)(i - y1) * dcg2_step;
1591 float col_eb = c1.b + (float)(i - y1) * dcb2_step;
1592 float col_ea = c1.a + (float)(i - y1) * dca2_step;
1593
1594 if (ax > bx)
1595 {
1596 std::swap(ax, bx);
1597 std::swap(tex_su, tex_eu);
1598 std::swap(tex_sv, tex_ev);
1599 std::swap(tex_sw, tex_ew);
1600 std::swap(col_sr, col_er);
1601 std::swap(col_sg, col_eg);
1602 std::swap(col_sb, col_eb);
1603 std::swap(col_sa, col_ea);
1604 }
1605
1606 tex_u = tex_su;
1607 tex_v = tex_sv;
1608 tex_w = tex_sw;
1609 col_r = col_sr;
1610 col_g = col_sg;
1611 col_b = col_sb;
1612 col_a = col_sa;
1613
1614 float tstep = 1.0f / ((float)(bx - ax));
1615 float t = 0.0f;
1616
1617 for (int j = ax; j < bx; j++)
1618 {
1619 tex_u = (1.0f - t) * tex_su + t * tex_eu;
1620 tex_v = (1.0f - t) * tex_sv + t * tex_ev;
1621 tex_w = (1.0f - t) * tex_sw + t * tex_ew;
1622 col_r = (1.0f - t) * col_sr + t * col_er;
1623 col_g = (1.0f - t) * col_sg + t * col_eg;
1624 col_b = (1.0f - t) * col_sb + t * col_eb;
1625 col_a = (1.0f - t) * col_sa + t * col_ea;
1626
1627 pixel_r = col_r;
1628 pixel_g = col_g;
1629 pixel_b = col_b;
1630 pixel_a = col_a;
1631
1632 if (nFlags & GFX3D::RENDER_TEXTURED)
1633 {
1634 if (spr != nullptr)
1635 {
1636 olc::Pixel sample = spr->Sample(tex_u / tex_w, tex_v / tex_w);
1637 pixel_r *= sample.r / 255.0f;
1638 pixel_g *= sample.g / 255.0f;
1639 pixel_b *= sample.b / 255.0f;
1640 pixel_a *= sample.a / 255.0f;
1641 }
1642 }
1643
1644 if (nFlags & GFX3D::RENDER_DEPTH)
1645 {
1646 if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j])
1647 if (pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f))))
1648 m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w;
1649 }
1650 else
1651 {
1652 pge->Draw(j, i, olc::Pixel(uint8_t(pixel_r * 1.0f), uint8_t(pixel_g * 1.0f), uint8_t(pixel_b * 1.0f), uint8_t(pixel_a * 1.0f)));
1653 }
1654
1655 t += tstep;
1656 }
1657 }
1658 }
1659 }
1660
1661
1662
1663 //GFX3D::MipMap::MipMap() : olc::Sprite(){}
1664 //GFX3D::MipMap::MipMap(std::string sImageFile) : olc::Sprite(sImageFile)
1665 //{
1666 // GenerateMipLevels();
1667 //}
1668 //GFX3D::MipMap::MipMap(std::string sImageFile, olc::ResourcePack *pack) : olc::Sprite(sImageFile, pack){}
1669 //GFX3D::MipMap::MipMap(int32_t w, int32_t h) : olc::Sprite(w, h) {}
1670
1671 //int GFX3D::MipMap::GenerateMipLevels()
1672 //{
1673 // int nLevelsW = 0;
1674 // int nLevelsH = 0;
1675 // int w = width;
1676 // int h = height;
1677 // while (w > 1) { w >>= 1; nLevelsW++; }
1678 // while (h > 1) { h >>= 1; nLevelsH++; }
1679
1680 // int nLevels = std::min(nLevelsW, nLevelsH);
1681
1682 // w = width >> 1;
1683 // h = height >> 1;
1684
1685 // vecMipMaps.emplace_back(w, h); // Level 0
1686 // memcpy(vecMipMaps[0].GetData(), GetData(), w*h*sizeof(uint32_t));
1687
1688 // for (int i = 1; i < nLevels; i++)
1689 // {
1690 // vecMipMaps.emplace_back(w, h);
1691 // pge->SetDrawTarget(&vecMipMaps[i]);
1692 // for (int x = 0; x < w; x++)
1693 // for (int y = 0; y < h; y++)
1694 // pge->Draw(x, y, vecMipMaps[i-1].SampleBL((float)x / (float)w, (float)y / (float)h));
1695 // w >>= 1; h >>= 1;
1696 // }
1697
1698 // pge->SetDrawTarget(nullptr);
1699 // return nLevels;
1700 //}
1701 //
1702 //olc::rcode GFX3D::MipMap::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack)
1703 //{
1704 // olc::rcode r = olc::Sprite::LoadFromFile(sImageFile, pack);
1705 // if (r == olc::FAIL) return r;
1706 // GenerateMipLevels();
1707 // return r;
1708 //}
1709
1710 //olc::rcode GFX3D::MipMap::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack)
1711 //{
1712 // olc::rcode r = olc::Sprite::LoadFromPGESprFile(sImageFile, pack);
1713 // if (r == olc::FAIL) return r;
1714 // GenerateMipLevels();
1715 // return r;
1716 //}
1717 //
1718 //olc::Pixel GFX3D::MipMap::Sample(float x, float y, float z)
1719 //{
1720 // int nLevel = (int)(z * (float)vecMipMaps.size());
1721 // return vecMipMaps[nLevel].Sample(x, y);
1722 //}
1723
1724 //olc::Pixel GFX3D::MipMap::SampleBL(float u, float v, float z);
1725
1726}
1727
1728#endif
Definition olcPGEX_Graphics3D.h:148
static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2)
static float Vec_Length(vec3d &v)
static float Vec_DotProduct(vec3d &v1, vec3d &v2)
static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up)
static mat4x4 Mat_MakeRotationY(float fAngleRad)
static vec3d Vec_Mul(vec3d &v1, float k)
static mat4x4 Mat_QuickInverse(mat4x4 &m)
static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2)
static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m)
static vec3d Vec_Normalise(vec3d &v)
static mat4x4 Mat_MakeRotationZ(float fAngleRad)
static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar)
static mat4x4 Mat_MakeTranslation(float x, float y, float z)
static vec3d Vec_Add(vec3d &v1, vec3d &v2)
static mat4x4 Mat_MakeRotationX(float fAngleRad)
static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2)
static vec3d Vec_Div(vec3d &v1, float k)
static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t)
static mat4x4 Mat_MakeIdentity()
static mat4x4 Mat_MakeScale(float x, float y, float z)
static vec3d Vec_Sub(vec3d &v1, vec3d &v2)
static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i)
Definition olcPGEX_Graphics3D.h:199
uint32_t Render(std::vector< olc::GFX3D::triangle > &triangles, uint32_t flags=RENDER_CULL_CW|RENDER_TEXTURED|RENDER_DEPTH)
void SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir={ 0.0f, 0.0f, 1.0f, 1.0f }, float fParam=0.0f)
uint32_t RenderLine(olc::GFX3D::vec3d &p1, olc::GFX3D::vec3d &p2, olc::Pixel col=olc::WHITE)
void SetTexture(olc::Sprite *texture)
void SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up)
void SetTransform(olc::GFX3D::mat4x4 &transform)
void SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight)
uint32_t Render(std::vector< olc::GFX3D::triangle > &triangles, uint32_t flags, int nOffset, int nCount)
uint32_t RenderCircleXZ(olc::GFX3D::vec3d &p1, float r, olc::Pixel col=olc::WHITE)
Definition olcPGEX_Graphics3D.h:89
LIGHTS
Definition olcPGEX_Graphics3D.h:190
@ LIGHT_POINT
Definition olcPGEX_Graphics3D.h:194
@ LIGHT_AMBIENT
Definition olcPGEX_Graphics3D.h:192
@ LIGHT_DISABLED
Definition olcPGEX_Graphics3D.h:191
@ LIGHT_DIRECTIONAL
Definition olcPGEX_Graphics3D.h:193
static void RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1, int x2, int y2, float u2, float v2, float w2, olc::Pixel c2, int x3, int y3, float u3, float v3, float w3, olc::Pixel c3, olc::Sprite *spr, uint32_t nFlags)
static void RenderScene()
static void ClearDepth()
RENDERFLAGS
Definition olcPGEX_Graphics3D.h:179
@ RENDER_CULL_CCW
Definition olcPGEX_Graphics3D.h:184
@ RENDER_WIRE
Definition olcPGEX_Graphics3D.h:180
@ RENDER_TEXTURED
Definition olcPGEX_Graphics3D.h:182
@ RENDER_FLAT
Definition olcPGEX_Graphics3D.h:181
@ RENDER_DEPTH
Definition olcPGEX_Graphics3D.h:185
@ RENDER_CULL_CW
Definition olcPGEX_Graphics3D.h:183
@ RENDER_LIGHTS
Definition olcPGEX_Graphics3D.h:186
static void ConfigureDisplay()
static void DrawTriangleFlat(olc::GFX3D::triangle &tri)
static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col=olc::WHITE)
static void AddTriangleToScene(olc::GFX3D::triangle &tri)
static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, int x2, int y2, float u2, float v2, float w2, int x3, int y3, float u3, float v3, float w3, olc::Sprite *spr)
static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite *spr)
Definition olcPixelGameEngine.h:1615
static PixelGameEngine * pge
Definition olcPixelGameEngine.h:1627
void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p=olc::WHITE, uint32_t pattern=0xFFFFFFFF)
void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p=olc::WHITE)
void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p=olc::WHITE)
virtual bool Draw(int32_t x, int32_t y, Pixel p=olc::WHITE)
int32_t ScreenWidth() const
int32_t ScreenHeight() const
void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p=olc::WHITE)
Definition olcPixelGameEngine.h:1047
Pixel Sample(float x, float y) const
Definition olcPixelGameEngine.h:593
static const Pixel RED(255, 0, 0)
static const Pixel WHITE(255, 255, 255)
Definition olcPGEX_Graphics3D.h:116
float m[4][4]
Definition olcPGEX_Graphics3D.h:117
Definition olcPGEX_Graphics3D.h:121
std::vector< triangle > tris
Definition olcPGEX_Graphics3D.h:122
bool LoadOBJFile(std::string sFilename, bool bHasTexture=false)
Definition olcPGEX_Graphics3D.h:109
olc::Pixel col[3]
Definition olcPGEX_Graphics3D.h:112
vec2d t[3]
Definition olcPGEX_Graphics3D.h:111
vec3d p[3]
Definition olcPGEX_Graphics3D.h:110
Definition olcPGEX_Graphics3D.h:94
float z
Definition olcPGEX_Graphics3D.h:97
float x
Definition olcPGEX_Graphics3D.h:95
float y
Definition olcPGEX_Graphics3D.h:96
Definition olcPGEX_Graphics3D.h:101
float w
Definition olcPGEX_Graphics3D.h:105
float z
Definition olcPGEX_Graphics3D.h:104
float x
Definition olcPGEX_Graphics3D.h:102
float y
Definition olcPGEX_Graphics3D.h:103
Definition olcPixelGameEngine.h:924
uint8_t g
Definition olcPixelGameEngine.h:928
uint8_t a
Definition olcPixelGameEngine.h:928
uint8_t b
Definition olcPixelGameEngine.h:928
uint8_t r
Definition olcPixelGameEngine.h:928