#include <SDL.h>
#include <stdio.h>
#include <cstring>
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <cmath>
#include <Windows.h>
#include <gl\GL.h>
static constexpr const float PI = 3.1416f; // 3.14159265359
inline constexpr float DegToRad(float degrees)
{
return degrees * (PI / 180.0f);
}
#include "matrix.h"
#include "Vector.h"
// --- x86 vs x64 ---
//__cdecl
//__stdcall
#if defined(_WIN32) && !defined(_WIN64)
#define STDCALL __stdcall
#else
#define STDCALL
#endif
// --- OpenGL defines ---
#define GL_MULTISAMPLE 0x809D
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_STATIC_DRAW 0x88E4
#define GL_STATIC_READ 0x88E5
#define GL_STATIC_COPY 0x88E6
#define GL_DYNAMIC_DRAW 0x88E8
#define GL_DYNAMIC_READ 0x88E9
#define GL_DYNAMIC_COPY 0x88EA
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
// -----------------------------------------
#define GL_ACTIVE_TEXTURE 0x84E0
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3
#define GL_CURRENT_PROGRAM 0x8B8D
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_VERTEX_ARRAY_BINDING 0x85B5
#define GL_BLEND_DST_RGB 0x80C8
#define GL_BLEND_SRC_RGB 0x80C9
#define GL_BLEND_DST_ALPHA 0x80CA
#define GL_BLEND_SRC_ALPHA 0x80CB
#define GL_BLEND_EQUATION 0x8009
#define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION
#define GL_BLEND_EQUATION_ALPHA 0x883D
#define GL_FUNC_ADD 0x8006
#define GL_STREAM_DRAW 0x88E0
#define GL_ACTIVE_UNIFORMS 0x8B86
#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
#define GL_UNIFORM_TYPE 0x8A37
#define GL_SHADER_TYPE 0x8B4F
#define GL_FLOAT_VEC2 0x8B50
#define GL_FLOAT_VEC3 0x8B51
#define GL_FLOAT_VEC4 0x8B52
#define GL_INT_VEC2 0x8B53
#define GL_INT_VEC3 0x8B54
#define GL_INT_VEC4 0x8B55
#define GL_BOOL 0x8B56
#define GL_BOOL_VEC2 0x8B57
#define GL_BOOL_VEC3 0x8B58
#define GL_BOOL_VEC4 0x8B59
#define GL_FLOAT_MAT2 0x8B5A
#define GL_FLOAT_MAT3 0x8B5B
#define GL_FLOAT_MAT4 0x8B5C
#define GL_SAMPLER_1D 0x8B5D
#define GL_SAMPLER_2D 0x8B5E
#define GL_SAMPLER_3D 0x8B5F
#define GL_SAMPLER_CUBE 0x8B60
#define GL_SAMPLER_1D_SHADOW 0x8B61
#define GL_SAMPLER_2D_SHADOW 0x8B62
// --- OpenGL types ---
typedef char GLchar;
typedef size_t GLsizeiptr;
void(STDCALL *glGenVertexArrays)(GLuint, GLuint*) = nullptr;
void(STDCALL *glBindVertexArray)(GLuint) = nullptr;
void(STDCALL *glGenBuffers)(GLuint, GLuint*) = nullptr;
void(STDCALL *glBindBuffer)(GLenum target, GLuint buffer) = nullptr;
void(STDCALL *glBufferData)(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage) = nullptr;
// Shaders
GLuint(STDCALL *glCreateShader)(GLenum shaderType) = nullptr;
void(STDCALL *glDeleteShader)(GLuint shader) = nullptr;
GLuint(STDCALL *glCreateProgram)() = nullptr;
void(STDCALL *glDeleteProgram)(GLuint program) = nullptr;
void(STDCALL *glShaderSource)(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) = nullptr;
void(STDCALL *glCompileShader)(GLuint shader) = nullptr;
void(STDCALL *glAttachShader)(GLuint program, GLuint shader) = nullptr;
void(STDCALL *glDetachShader)(GLuint program, GLuint shader) = nullptr;
void(STDCALL *glLinkProgram)(GLuint program) = nullptr;
void(STDCALL *glUseProgram)(GLuint program) = nullptr;
void(STDCALL *glGetShaderiv)(GLuint shader, GLenum pname, GLint *params) = nullptr;
void(STDCALL *glGetProgramiv)(GLuint program, GLenum pname, GLint *params) = nullptr;
void(STDCALL *glGetShaderInfoLog)(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog) = nullptr;
void(STDCALL *glGetProgramInfoLog)(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog) = nullptr;
GLint(STDCALL *glGetAttribLocation)(GLuint program, const GLchar *name) = nullptr;
void(STDCALL *glEnableVertexAttribArray)(GLuint index) = nullptr;
void(STDCALL *glDisableVertexAttribArray)(GLuint index) = nullptr;
void(STDCALL *glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer) = nullptr;
GLint(STDCALL *glGetUniformLocation)(GLuint program, const GLchar *name) = nullptr;
void(STDCALL *glUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) = nullptr;
void(STDCALL *glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = nullptr;
typedef void (APIENTRY *DEBUGPROC)(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar *message,
const void *userParam);
void(STDCALL *glDebugMessageCallback)(DEBUGPROC callback, void* userData) = nullptr;
struct Color {
float r, g, b, a;
static Color White;
static Color Black;
static Color Red;
static Color Green;
static Color Blue;
};
Color Color::White = { 1.0f, 1.0f, 1.0f, 1.0f };
Color Color::Black = { 0.0f, 0.0f, 0.0f, 1.0f };
Color Color::Red = { 1.0f, 0.0f, 0.0f, 1.0f };
Color Color::Green = { 0.0f, 1.0f, 0.0f, 1.0f };
Color Color::Blue = { 0.0f, 0.0f, 1.0f, 1.0f };
enum class AlphaMode { SOLID = 0, BLEND, ADDATIVE };
// --- SHADER ---
struct Shader
{
GLuint gl_shader_program = 0;
inline ~Shader();
bool Create(const char* vertex_shader, const char* pixel_shader);
void Destroy();
void Use();
static void ClearActiveShader();
static bool LoadShader(Shader& shader_out, const char* vert_shader_path, const char* frag_shader_path);
};
static Shader s_defaultShaderSimple;
static GLuint s_current_shader = 0;
// ----------------------------------------------------
Matrix s_view_matrix = Matrix::CreateScale(1.0f);
Matrix s_projection_matrix = Matrix::CreateScale(1.0f);
// --- --- --- --- --- --- --- --- --- --- --- --- ---
struct ScreenResolution
{
int w, h;
};
static const constexpr ScreenResolution screen_resolution_16_9[] =
{
{ 1024, 576 }, { 1152, 648 }, { 1280, 720 }, { 1366, 768 },
{ 1600, 900 }, { 1920, 1080 }, { 2560, 1440 }, { 3840, 2160 }
};
//Screen dimension constants
static const constexpr int SCREEN_W = screen_resolution_16_9[2].w;
static const constexpr int SCREEN_H = screen_resolution_16_9[2].h;
// --- --- --- --- --- --- --- --- --- --- --- --- ---
static SDL_Window* s_sdl_window = nullptr;
static SDL_GLContext s_gl_context;
void InitializeGraphics();
void CheckForErrors();
extern Matrix s_view_matrix;
extern Vector3 s_view_pos;
extern Matrix s_projection_matrix;
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
// ---
struct Mesh
{
GLuint vao = 0; // Vertex array object
GLuint vbo = 0; // Vertices
bool made_buffers = false;
bool MakeBuffers();
//struct Vertex { float x, y, z; };
typedef Vector3 Vertex;
Vertex* vertices = nullptr;
size_t num_verts = 0;
};
void CreateTree(Mesh& mesh, float height, float width);
void DrawMeshShaded(Mesh& mesh, Color color, Shader& shader, AlphaMode alpha_mode = AlphaMode::SOLID, Matrix* mat = nullptr);
int main(int argc, char* argv[])
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
{
SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
// Setup window
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
//SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
//SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
//SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_DisplayMode current;
SDL_GetCurrentDisplayMode(0, ¤t);
s_sdl_window = SDL_CreateWindow("Testbed", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_W, SCREEN_H, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (s_sdl_window == NULL)
{
const char* err = SDL_GetError();
printf("Could not create window: %s\n", err);
return 1;
}
// Graphics
s_gl_context = SDL_GL_CreateContext(s_sdl_window);
SDL_GL_SetSwapInterval(1); // Enable vsync
// Other
SDL_GL_MakeCurrent(s_sdl_window, s_gl_context);
InitializeGraphics();
Mesh tube_mesh;
CreateTree(tube_mesh, 1.0, 1.0f);
// Main loop
bool running = true;
while (running)
{
SDL_Event current_event;
while (SDL_PollEvent(¤t_event))
{
switch (current_event.type)
{
case SDL_QUIT:
running = false;
break;
}
}
SDL_GL_MakeCurrent(s_sdl_window, s_gl_context);
glViewport(0, 0, SCREEN_W, SCREEN_H);
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 235.0f / 255.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// PROJECTION & VIEW
{
float aspect = (float)SCREEN_W / SCREEN_H;
s_projection_matrix = Matrix::CreatePerspective(90.0f, aspect, 0.001f, 500.0f);
s_view_matrix = Matrix::CreateTranslation({0.0f, 0.0f, 5.0f});
}
DrawMeshShaded(tube_mesh, Color::White, s_defaultShaderSimple, AlphaMode::SOLID, nullptr);
glDisable(GL_DEPTH_TEST);
SDL_GL_SwapWindow(s_sdl_window);
}
s_defaultShaderSimple.Destroy();
SDL_GL_DeleteContext(s_gl_context);
SDL_Quit();
return 0;
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void APIENTRY glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
std::cout << message << std::endl;
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void CheckForErrors()
{
GLenum error_code = 0;
while (error_code = glGetError())
{
std::cout << (int)error_code << std::endl;
}
}
void InitializeGraphics()
{
(void *&)glGenVertexArrays = SDL_GL_GetProcAddress("glGenVertexArrays");
(void *&)glBindVertexArray = SDL_GL_GetProcAddress("glBindVertexArray");
(void *&)glGenBuffers = SDL_GL_GetProcAddress("glGenBuffers");
(void *&)glBindBuffer = SDL_GL_GetProcAddress("glBindBuffer");
(void *&)glBufferData = SDL_GL_GetProcAddress("glBufferData");
// --- Shaders
(void *&)glCreateShader = SDL_GL_GetProcAddress("glCreateShader");
(void *&)glDeleteShader = SDL_GL_GetProcAddress("glDeleteShader");
(void *&)glCreateProgram = SDL_GL_GetProcAddress("glCreateProgram");
(void *&)glDeleteProgram = SDL_GL_GetProcAddress("glDeleteProgram");
(void *&)glShaderSource = SDL_GL_GetProcAddress("glShaderSource"); // Set the source text
(void *&)glCompileShader = SDL_GL_GetProcAddress("glCompileShader"); // Compile it
(void *&)glAttachShader = SDL_GL_GetProcAddress("glAttachShader");
(void *&)glDetachShader = SDL_GL_GetProcAddress("glDetachShader");
(void *&)glLinkProgram = SDL_GL_GetProcAddress("glLinkProgram");
(void *&)glUseProgram = SDL_GL_GetProcAddress("glUseProgram");
(void *&)glGetShaderiv = SDL_GL_GetProcAddress("glGetShaderiv");
(void *&)glGetProgramiv = SDL_GL_GetProcAddress("glGetProgramiv");
(void *&)glGetShaderInfoLog = SDL_GL_GetProcAddress("glGetShaderInfoLog");
(void *&)glGetProgramInfoLog = SDL_GL_GetProcAddress("glGetProgramInfoLog");
(void *&)glGetAttribLocation = SDL_GL_GetProcAddress("glGetAttribLocation");
(void *&)glVertexAttribPointer = SDL_GL_GetProcAddress("glVertexAttribPointer");
(void *&)glEnableVertexAttribArray = SDL_GL_GetProcAddress("glEnableVertexAttribArray");
(void *&)glDisableVertexAttribArray = SDL_GL_GetProcAddress("glDisableVertexAttribArray");
(void *&)glGetUniformLocation = SDL_GL_GetProcAddress("glGetUniformLocation");
(void *&)glUniform4f = SDL_GL_GetProcAddress("glUniform4f");
(void *&)glUniformMatrix4fv = SDL_GL_GetProcAddress("glUniformMatrix4fv");
(void*&)glDebugMessageCallback = SDL_GL_GetProcAddress("glDebugMessageCallback");
Shader::LoadShader(s_defaultShaderSimple, "Shaders/default_simple.vert", "Shaders/default_simple.frag");
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(glDebugCallback, nullptr);
glEnable(GL_MULTISAMPLE);
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
static_assert(3 * sizeof(GLfloat) == sizeof(Mesh::Vertex), "Mesh::Vertex must ve 3 * sizeof(GLfloat)");
bool Mesh::MakeBuffers()
{
if (!made_buffers)
{
made_buffers = true;
glGenVertexArrays(1, &vao);
CheckForErrors();
//Create VBO
if (vertices)
{
glGenBuffers(1, &vbo);
CheckForErrors();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
CheckForErrors();
glBufferData(GL_ARRAY_BUFFER, num_verts * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
CheckForErrors();
}
CheckForErrors();
}
return true;
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
inline Shader::~Shader() { Destroy(); }
bool Shader::Create(const char* vertex_shader, const char* pixel_shader)
{
GLuint vertexshader = 0;
GLuint fragmentshader = 0;
vertexshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexshader, 1, (const GLchar**)&vertex_shader, 0);
glCompileShader(vertexshader);
GLint IsCompiled_VS = 0;
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &IsCompiled_VS);
if (IsCompiled_VS == FALSE)
{
GLint maxLength = 0;
glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &maxLength);
/* The maxLength includes the NULL character */
char* vertexInfoLog = (char *)malloc(maxLength);
glGetShaderInfoLog(vertexshader, maxLength, &maxLength, vertexInfoLog);
printf(vertexInfoLog);
free(vertexInfoLog);
return false;
}
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, (const GLchar**)&pixel_shader, 0);
glCompileShader(fragmentshader);
GLint IsCompiled_FS = 0;
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &IsCompiled_FS);
if (IsCompiled_FS == FALSE)
{
GLint maxLength = 0;
glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &maxLength);
/* The maxLength includes the NULL character */
char* fragmentInfoLog = (char *)malloc(maxLength);
glGetShaderInfoLog(fragmentshader, maxLength, &maxLength, fragmentInfoLog);
printf(fragmentInfoLog);
free(fragmentInfoLog);
return false;
}
gl_shader_program = glCreateProgram();
glAttachShader(gl_shader_program, vertexshader);
glAttachShader(gl_shader_program, fragmentshader);
glLinkProgram(gl_shader_program);
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
GLint IsLinked = 0;
glGetProgramiv(gl_shader_program, GL_LINK_STATUS, (int *)&IsLinked);
if (IsLinked == FALSE)
{
/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
GLint maxLength = 0;
glGetProgramiv(gl_shader_program, GL_INFO_LOG_LENGTH, &maxLength);
/* The maxLength includes the NULL character */
char* shaderProgramInfoLog = (char *)malloc(maxLength);
glGetProgramInfoLog(gl_shader_program, maxLength, &maxLength, shaderProgramInfoLog);
printf(shaderProgramInfoLog);
free(shaderProgramInfoLog);
return false;
}
return true;
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void Shader::Destroy()
{
// Clear Shader
if (gl_shader_program != 0)
{
if (s_current_shader == gl_shader_program)
Shader::ClearActiveShader();
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Detach vert and frag from shader
//glDetachShader(shaderprogram, vertexshader);
//glDetachShader(shaderprogram, fragmentshader);
// Destroy
glDeleteProgram(gl_shader_program);
//glDeleteShader(vertexshader);
//glDeleteShader(fragmentshader);
gl_shader_program = 0;
//vertexshader = 0;
//fragmentshader = 0;
}
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void Shader::Use()
{
glUseProgram(gl_shader_program);
s_current_shader = gl_shader_program;
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void Shader::ClearActiveShader()
{
s_current_shader = 0;
glUseProgram(0);
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
bool Shader::LoadShader(Shader& shader_out, const char* vert_shader_path, const char* frag_shader_path)
{
std::ifstream file_vert(vert_shader_path);
std::ifstream file_frag(frag_shader_path);
if (file_vert.is_open() && file_frag.is_open())
{
std::string vert;
{
file_vert.seekg(0, std::ios::end);
vert.resize(file_vert.tellg());
file_vert.seekg(0, std::ios::beg);
file_vert.read(&vert[0], vert.size());
file_vert.close();
}
std::string frag;
{
file_frag.seekg(0, std::ios::end);
frag.resize(file_frag.tellg());
file_frag.seekg(0, std::ios::beg);
file_frag.read(&frag[0], frag.size());
file_frag.close();
}
return shader_out.Create(vert.c_str(), frag.c_str());
}
return false;
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void DrawMeshShaded(Mesh& mesh, Color color, Shader& shader, AlphaMode alpha_mode, Matrix* mat)
{
if (mesh.vbo == 0)
return;
//Bind program
shader.Use();
//Set vertex data
glBindVertexArray(mesh.vao);
CheckForErrors();
GLint positionLocation = -1;
positionLocation = glGetAttribLocation(shader.gl_shader_program, "in_Position");
if (positionLocation != -1)
{
if (mesh.vertices)
{
glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
}
else
{
glDisableVertexAttribArray(positionLocation);
}
}
CheckForErrors();
GLint modelViewProjMatLocation = glGetUniformLocation(shader.gl_shader_program, "in_ModelViewProjection");
if (modelViewProjMatLocation != -1)
{
Matrix matrix;
if (mat)
{
matrix = (*mat) * s_view_matrix * s_projection_matrix;
}
else
{
matrix = s_view_matrix * s_projection_matrix;
}
glEnableVertexAttribArray(modelViewProjMatLocation);
glUniformMatrix4fv(modelViewProjMatLocation, 1, GL_FALSE, (GLfloat*)&matrix);
}
CheckForErrors();
GLint colorLocation = glGetUniformLocation(shader.gl_shader_program, "in_Color");
if (colorLocation != -1)
{
glEnableVertexAttribArray(colorLocation);
glUniform4f(colorLocation, color.r, color.g, color.b, color.a);
}
CheckForErrors();
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)mesh.num_verts);
CheckForErrors();
glBindBuffer(GL_ARRAY_BUFFER, 0);
CheckForErrors();
if (colorLocation != -1)
glDisableVertexAttribArray(colorLocation);
if (modelViewProjMatLocation != -1)
glDisableVertexAttribArray(modelViewProjMatLocation);
//Disable vertex position
if (positionLocation != -1)
glDisableVertexAttribArray(positionLocation);
//Unbind program
Shader::ClearActiveShader();
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void AppendTube(std::vector<Mesh::Vertex>& verts, Vector3 pos1, Vector3 pos2, float w1, float w2, int segments)
{
float angle = PI / segments;
Vector3 normal = (pos2 - pos1).Normal();
Matrix mtx = Matrix::CreateScale(1.0f);
if (normal.y != 1.0f)
mtx = Matrix::CreateLookAt(normal, { 0.0f, 1.0f, 0.0f });
for (int i = 0; i < segments; ++i)
{
float xl = std::cosf(i * angle * 2);
float xr = std::cosf((i + 1) * angle * 2);
float zl = std::sinf(i * angle * 2);
float zr = std::sinf((i + 1) * angle * 2);
Vector3 ul = mtx.AxisVectorX() * xl + mtx.AxisVectorZ() * zl; ul *= w1; ul += pos1;
Vector3 ur = mtx.AxisVectorX() * xr + mtx.AxisVectorZ() * zr; ur *= w1; ur += pos1;
Vector3 ll = mtx.AxisVectorX() * xl + mtx.AxisVectorZ() * zl; ll *= w2; ll += pos2;
Vector3 lr = mtx.AxisVectorX() * xr + mtx.AxisVectorZ() * zr; lr *= w2; lr += pos2;
// Triangles
verts.push_back({ ur.x, ur.y, ur.z });
verts.push_back({ ul.x, ul.y, ul.z });
verts.push_back({ lr.x, lr.y, lr.z });
verts.push_back({ lr.x, lr.y, lr.z });
verts.push_back({ ul.x, ul.y, ul.z });
verts.push_back({ ll.x, ll.y, ll.z });
}
}
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void CreateTree(Mesh& mesh, float height, float width)
{
mesh = {};
std::vector<Mesh::Vertex> vertices;
AppendTube(vertices, {}, { 0.0f, height, 0.0f }, width, width / 2.0f, 8);
mesh.num_verts = vertices.size();
mesh.vertices = new Mesh::Vertex[mesh.num_verts];
for (int i = 0; i < mesh.num_verts; ++i)
mesh.vertices[i] = vertices[i];
mesh.MakeBuffers();
}