strichmaennchen git · main
git clone https://git.christianimmanuel.de/games/strichmaennchen.gitwget https://git.christianimmanuel.de/games/strichmaennchen/archive/strichmaennchen.tar.gzmesh.c raw
#include "mesh.h"
#include "linalg.h"
#include "renderer.h"
#include "stdio.h"
#include "glfuncs.h"
#include <stdlib.h>
float cosf(float x);
float tanf(float x);
float sinf(float x);
float sqrtf(float x);
#define M_PI 3.14159265358979323846
const Mesh mesh_default = {
.vao = 0,
.vbo = 0,
.ebo = 0,
.vertexCount = 0,
.drawMode = GL_TRIANGLES,
.hasIndices = false,
};
void Mesh_draw(Mesh mesh, struct Renderer *renderer, TransformMatrices* trans_matrices, Time* time, Vec3 viewPos) {
glUseProgram(renderer->shaderProgram);
// Set matrices
GLint locModel = glGetUniformLocation(renderer->shaderProgram, "model");
GLint locView = glGetUniformLocation(renderer->shaderProgram, "view");
GLint locProj = glGetUniformLocation(renderer->shaderProgram, "projection");
glUniformMatrix4fv(locModel, 1, GL_FALSE, (float*)&(trans_matrices->model));
glUniformMatrix4fv(locView, 1, GL_FALSE, (float*)&(trans_matrices->view));
glUniformMatrix4fv(locProj, 1, GL_FALSE, (float*)&(trans_matrices->projection));
// Set light & camera positions using Time
GLint locLightDir = glGetUniformLocation(renderer->shaderProgram, "lightDirection");
GLint locLightColor = glGetUniformLocation(renderer->shaderProgram, "lightColor");
GLint locViewPos = glGetUniformLocation(renderer->shaderProgram, "viewPos");
glUniform3f(locLightDir, time->sunDirection.x, time->sunDirection.y, time->sunDirection.z);
glUniform3f(locLightColor, time->sunColor.x, time->sunColor.y, time->sunColor.z);
glUniform3f(locViewPos, viewPos.x, viewPos.y, viewPos.z);
// set dayFactor
GLint locDay = glGetUniformLocation(renderer->shaderProgram, "dayFactor");
if (locDay != -1) {
glUniform1f(locDay, time->dayFactor);
}
// For main pass only (not shadow pass)
Mat4 lightSpace = mat4_mul(renderer->lightProjection, mat4_mul(renderer->lightView, trans_matrices->model));
GLint locLightSpace = glGetUniformLocation(renderer->shaderProgram, "lightSpaceMatrix");
glUniformMatrix4fv(locLightSpace, 1, GL_FALSE, (float*)&lightSpace);
// Bind shadow map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderer->shadowMap);
GLint locShadowMap = glGetUniformLocation(renderer->shaderProgram, "shadowMap");
glUniform1i(locShadowMap, 0);
// Draw
glBindVertexArray(mesh.vao);
if (mesh.hasIndices)
glDrawElements(GL_TRIANGLES, mesh.indexCount, GL_UNSIGNED_INT, 0);
else
glDrawArrays(mesh.drawMode, 0, mesh.vertexCount);
glBindVertexArray(0);
}
Mesh Mesh_createTriangle() {
float vertices[] = {
// positions // colors
-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
Mesh m = mesh_default;
glGenVertexArrays(1, &m.vao);
glGenBuffers(1, &m.vbo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER, m.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
m.vertexCount = 3;
m.drawMode = GL_TRIANGLES;
m.ebo = 0;
return m;
}
Mesh Mesh_createPyramid(float size, float height) {
float half = size / 2.0f;
float vertices[] = {
// positions // colors
// Base (square)
-half, 0.0f, -half, 1,0,0, // 0
half, 0.0f, -half, 0,1,0, // 1
half, 0.0f, half, 0,0,1, // 2
-half, 0.0f, half, 1,1,0, // 3
// Apex
0.0f, height, 0.0f, 1,0,1 // 4
};
unsigned int indices[] = {
// Base
0,1,2,
2,3,0,
// Sides
0,1,4,
1,2,4,
2,3,4,
3,0,4
};
Mesh m = mesh_default;
m.vertexCount = sizeof(vertices)/sizeof(vertices[0]);
m.indexCount = sizeof(indices)/sizeof(indices[0]);
m.drawMode = GL_TRIANGLES;
m.hasIndices = true;
glGenVertexArrays(1, &m.vao);
glGenBuffers(1, &m.vbo);
glGenBuffers(1, &m.ebo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER, m.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
return m;
}
Mesh Mesh_createCube(Vec3 size, VertexPreset preset) {
float hx = size.x/2.0f;
float hy = size.y/2.0f;
float hz = size.z/2.0f;
float vertices[24*9]; // 24 vertices, 3 pos + 3 normal + 3 color
// Face normals
Vec3 faceNormals[6] = {
{ 0, 0, -1}, // back
{ 0, 0, 1}, // front
{-1, 0, 0}, // left
{ 1, 0, 0}, // right
{ 0, -1, 0}, // bottom
{ 0, 1, 0} // top
};
// Face colors (same as before)
float faceColors[6][3];
switch (preset) {
case CUBE_VERTICES_STANDARD:
for (int i=0;i<6;i++){ faceColors[i][0]=1; faceColors[i][1]=1; faceColors[i][2]=1; }
break;
case CUBE_VERTICES_MODERN:
faceColors[0][0]=1;faceColors[0][1]=0;faceColors[0][2]=0;
faceColors[1][0]=0;faceColors[1][1]=1;faceColors[1][2]=0;
faceColors[2][0]=0;faceColors[2][1]=0;faceColors[2][2]=1;
faceColors[3][0]=1;faceColors[3][1]=1;faceColors[3][2]=0;
faceColors[4][0]=1;faceColors[4][1]=0;faceColors[4][2]=1;
faceColors[5][0]=0;faceColors[5][1]=1;faceColors[5][2]=1;
break;
case CUBE_VERTICES_GROUND:
for (int i=0;i<4;i++){ faceColors[i][0]=0.55f; faceColors[i][1]=0.27f; faceColors[i][2]=0.07f; }
faceColors[4][0]=0.3f; faceColors[4][1]=0.15f; faceColors[4][2]=0.05f;
faceColors[5][0]=0.1f; faceColors[5][1]=0.8f; faceColors[5][2]=0.1f;
break;
case CUBE_VERTICES_WARM:
for (int i=0;i<6;i++){ faceColors[i][0]=1; faceColors[i][1]=0.5; faceColors[i][2]=0; }
break;
}
int vi = 0;
Vec3 faceOffsets[6][4] = {
{{-hx,-hy,-hz},{hx,-hy,-hz},{hx,hy,-hz},{-hx,hy,-hz}}, // back
{{-hx,-hy,hz},{hx,-hy,hz},{hx,hy,hz},{-hx,hy,hz}}, // front
{{-hx,-hy,-hz},{-hx,hy,-hz},{-hx,hy,hz},{-hx,-hy,hz}}, // left
{{hx,-hy,-hz},{hx,hy,-hz},{hx,hy,hz},{hx,-hy,hz}}, // right
{{-hx,-hy,-hz},{hx,-hy,-hz},{hx,-hy,hz},{-hx,-hy,hz}}, // bottom
{{-hx,hy,-hz},{hx,hy,-hz},{hx,hy,hz},{-hx,hy,hz}}, // top
};
for (int f=0; f<6; f++) {
for (int v=0; v<4; v++) {
vertices[vi++] = faceOffsets[f][v].x;
vertices[vi++] = faceOffsets[f][v].y;
vertices[vi++] = faceOffsets[f][v].z;
vertices[vi++] = faceNormals[f].x;
vertices[vi++] = faceNormals[f].y;
vertices[vi++] = faceNormals[f].z;
vertices[vi++] = faceColors[f][0];
vertices[vi++] = faceColors[f][1];
vertices[vi++] = faceColors[f][2];
}
}
unsigned int indices[] = {
0,1,2, 2,3,0, // back
4,5,6, 6,7,4, // front
8,9,10,10,11,8, // left
12,13,14,14,15,12,// right
16,17,18,18,19,16,// bottom
20,21,22,22,23,20 // top
};
Mesh m = mesh_default;
m.vertexCount = 24;
m.indexCount = 36;
m.hasIndices = true;
m.drawMode = GL_TRIANGLES;
glGenVertexArrays(1,&m.vao);
glGenBuffers(1,&m.vbo);
glGenBuffers(1,&m.ebo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER,m.vbo);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)0); // pos
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(3*sizeof(float))); // normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(6*sizeof(float))); // color
glEnableVertexAttribArray(2);
glBindVertexArray(0);
return m;
}
Mesh Mesh_createTree(float trunkHeight, float trunkRadius, int leafLayers, float leafRadius) {
Mesh m = mesh_default;
const int segments = 12; // circular segments for trunk and leaves
int vOffset = 0;
int floatsPerVertex = 9;
int maxVertices = segments*36 + leafLayers*segments*18; // old
maxVertices = maxVertices / 6 * floatsPerVertex; // fix: scale up to 9 floats per vertex
float* vertices = malloc(sizeof(float) * maxVertices);
if (!vertices) {
fprintf(stderr, "Failed to allocate memory for tree vertices\n");
return mesh_default;
}
// Trunk (cylinder)
for (int i=0; i<segments; i++) {
float angle0 = 2*M_PI*i/segments;
float angle1 = 2*M_PI*((i+1)%segments)/segments;
float x0 = cosf(angle0)*trunkRadius;
float z0 = sinf(angle0)*trunkRadius;
float x1 = cosf(angle1)*trunkRadius;
float z1 = sinf(angle1)*trunkRadius;
float y0 = 0;
float y1 = trunkHeight;
// side quad as two triangles
// triangle 1
// Normal is just outward direction on XZ plane
float nx0 = cosf(angle0);
float nz0 = sinf(angle0);
float nx1 = cosf(angle1);
float nz1 = sinf(angle1);
// V1
vertices[vOffset++] = x0; vertices[vOffset++] = y0; vertices[vOffset++] = z0;
vertices[vOffset++] = nx0; vertices[vOffset++] = 0.0f; vertices[vOffset++] = nz0;
vertices[vOffset++] = 0.55f; vertices[vOffset++] = 0.27f; vertices[vOffset++] = 0.07f;
// V2
vertices[vOffset++] = x1; vertices[vOffset++] = y0; vertices[vOffset++] = z1;
vertices[vOffset++] = nx1; vertices[vOffset++] = 0.0f; vertices[vOffset++] = nz1;
vertices[vOffset++] = 0.55f; vertices[vOffset++] = 0.27f; vertices[vOffset++] = 0.07f;
// V3
vertices[vOffset++] = x1; vertices[vOffset++] = y1; vertices[vOffset++] = z1;
vertices[vOffset++] = nx1; vertices[vOffset++] = 0.0f; vertices[vOffset++] = nz1;
vertices[vOffset++] = 0.55f; vertices[vOffset++] = 0.27f; vertices[vOffset++] = 0.07f;
// Second triangle (x0,y0,z0) -> (x1,y1,z1) -> (x0,y1,z0)
// V4
vertices[vOffset++] = x0; vertices[vOffset++] = y0; vertices[vOffset++] = z0;
vertices[vOffset++] = nx0; vertices[vOffset++] = 0.0f; vertices[vOffset++] = nz0;
vertices[vOffset++] = 0.55f; vertices[vOffset++] = 0.27f; vertices[vOffset++] = 0.07f;
// V5
vertices[vOffset++] = x1; vertices[vOffset++] = y1; vertices[vOffset++] = z1;
vertices[vOffset++] = nx1; vertices[vOffset++] = 0.0f; vertices[vOffset++] = nz1;
vertices[vOffset++] = 0.55f; vertices[vOffset++] = 0.27f; vertices[vOffset++] = 0.07f;
// V6
vertices[vOffset++] = x0; vertices[vOffset++] = y1; vertices[vOffset++] = z0;
vertices[vOffset++] = nx0; vertices[vOffset++] = 0.0f; vertices[vOffset++] = nz0;
vertices[vOffset++] = 0.55f; vertices[vOffset++] = 0.27f; vertices[vOffset++] = 0.07f;
}
// Leaves (cones, layered from top to bottom)
for (int l=0; l<leafLayers; l++) {
float yLayer = trunkHeight + l*0.6f; // staggered layers
float rLayer = leafRadius * (1.0f - (float)l/leafLayers);
for (int i=0; i<segments; i++) {
float angle0 = 2*M_PI*i/segments;
float angle1 = 2*M_PI*((i+1)%segments)/segments;
float x0 = cosf(angle0)*rLayer;
float z0 = sinf(angle0)*rLayer;
float x1 = cosf(angle1)*rLayer;
float z1 = sinf(angle1)*rLayer;
// top of the cone
float tx = 0.0f, ty = yLayer + 0.8f, tz = 0.0f;
// compute normal via cross product of two triangle edges
float ux = x0 - tx;
float uy = yLayer - ty;
float uz = z0 - tz;
float vx = x1 - tx;
float vy = yLayer - ty;
float vz = z1 - tz;
// correct cross product: v x u instead of u x v
float nx = vy*uz - vz*uy;
float ny = vz*ux - vx*uz;
float nz = vx*uy - vy*ux;
// normalize
float len = sqrtf(nx*nx + ny*ny + nz*nz);
if (len > 0.0f) {
nx /= len; ny /= len; nz /= len;
}
// green color
float cr = 0.0f, cg = 0.8f, cb = 0.0f;
// V1: tip of cone
vertices[vOffset++] = tx; vertices[vOffset++] = ty; vertices[vOffset++] = tz;
vertices[vOffset++] = nx; vertices[vOffset++] = ny; vertices[vOffset++] = nz;
vertices[vOffset++] = cr; vertices[vOffset++] = cg; vertices[vOffset++] = cb;
// V2: base corner 0
vertices[vOffset++] = x0; vertices[vOffset++] = yLayer; vertices[vOffset++] = z0;
vertices[vOffset++] = nx; vertices[vOffset++] = ny; vertices[vOffset++] = nz;
vertices[vOffset++] = cr; vertices[vOffset++] = cg; vertices[vOffset++] = cb;
// V3: base corner 1
vertices[vOffset++] = x1; vertices[vOffset++] = yLayer; vertices[vOffset++] = z1;
vertices[vOffset++] = nx; vertices[vOffset++] = ny; vertices[vOffset++] = nz;
vertices[vOffset++] = cr; vertices[vOffset++] = cg; vertices[vOffset++] = cb;
}
}
// Generate OpenGL buffers
glGenVertexArrays(1, &m.vao);
glGenBuffers(1, &m.vbo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER, m.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vOffset, vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)0); // position
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)(3*sizeof(float))); // normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)(6*sizeof(float))); // color
glEnableVertexAttribArray(2);
glBindVertexArray(0);
m.vertexCount = vOffset / 9;
m.drawMode = GL_TRIANGLES;
m.ebo = 0;
m.hasIndices = false;
free(vertices);
return m;
}
Mesh Mesh_createCylinder(float diameter, float height, int segments, VertexPreset preset) {
float radius = diameter*0.5f;
float hy = height * 0.5f;
// vertex layout: pos(3), normal(3), color(3) = 9 floats
int side_vertices = segments * 2; // top + bottom ring
int cap_ring_vertices = segments * 2; // cap ring (top + bottom)
int cap_center_vertices = 2; // top + bottom centers
int vertex_count = side_vertices + cap_ring_vertices + cap_center_vertices;
float *vertices = malloc(vertex_count * 9 * sizeof(float));
// color setup
float color[3] = {1,1,1};
switch (preset) {
case CUBE_VERTICES_STANDARD: color[0]=color[1]=color[2]=1; break;
case CUBE_VERTICES_MODERN: color[0]=1; color[1]=0; color[2]=0; break;
case CUBE_VERTICES_GROUND: color[0]=0.55f; color[1]=0.27f; color[2]=0.07f; break;
case CUBE_VERTICES_WARM: color[0]=1; color[1]=0.5f; color[2]=0; break;
}
// precompute sin/cos
float *cos_vals = malloc(segments * sizeof(float));
float *sin_vals = malloc(segments * sizeof(float));
for (int i=0; i<segments; i++) {
float theta = (2.0f * M_PI * i) / segments;
cos_vals[i] = cosf(theta);
sin_vals[i] = sinf(theta);
}
int vi = 0;
// side vertices
for (int i=0; i<segments; i++) {
float x = cos_vals[i] * radius;
float z = sin_vals[i] * radius;
// bottom
vertices[vi++] = x; vertices[vi++] = -hy; vertices[vi++] = z;
vertices[vi++] = cos_vals[i]; vertices[vi++] = 0; vertices[vi++] = sin_vals[i];
vertices[vi++] = color[0]; vertices[vi++] = color[1]; vertices[vi++] = color[2];
// top
vertices[vi++] = x; vertices[vi++] = hy; vertices[vi++] = z;
vertices[vi++] = cos_vals[i]; vertices[vi++] = 0; vertices[vi++] = sin_vals[i];
vertices[vi++] = color[0]; vertices[vi++] = color[1]; vertices[vi++] = color[2];
}
// cap ring vertices
for (int i=0; i<segments; i++) {
float x = cos_vals[i] * radius;
float z = sin_vals[i] * radius;
// bottom cap ring
vertices[vi++] = x; vertices[vi++] = -hy; vertices[vi++] = z;
vertices[vi++] = 0; vertices[vi++] = -1; vertices[vi++] = 0;
vertices[vi++] = color[0]; vertices[vi++] = color[1]; vertices[vi++] = color[2];
// top cap ring
vertices[vi++] = x; vertices[vi++] = hy; vertices[vi++] = z;
vertices[vi++] = 0; vertices[vi++] = 1; vertices[vi++] = 0;
vertices[vi++] = color[0]; vertices[vi++] = color[1]; vertices[vi++] = color[2];
}
// cap centers
// bottom center
vertices[vi++] = 0; vertices[vi++] = -hy; vertices[vi++] = 0;
vertices[vi++] = 0; vertices[vi++] = -1; vertices[vi++] = 0;
vertices[vi++] = color[0]; vertices[vi++] = color[1]; vertices[vi++] = color[2];
// top center
vertices[vi++] = 0; vertices[vi++] = hy; vertices[vi++] = 0;
vertices[vi++] = 0; vertices[vi++] = 1; vertices[vi++] = 0;
vertices[vi++] = color[0]; vertices[vi++] = color[1]; vertices[vi++] = color[2];
// indices
int side_indices = segments * 6;
int cap_indices = segments * 6;
int index_count = side_indices + cap_indices;
unsigned int *indices = malloc(index_count * sizeof(unsigned int));
int ii = 0;
// sides
for (int i=0; i<segments; i++) {
int i0 = i*2;
int i1 = i0 + 1;
int i2 = (i0 + 2) % (segments*2);
int i3 = (i0 + 3) % (segments*2);
indices[ii++] = i0; indices[ii++] = i2; indices[ii++] = i1;
indices[ii++] = i1; indices[ii++] = i2; indices[ii++] = i3;
}
int cap_base = side_vertices;
int center_bottom = side_vertices + cap_ring_vertices;
int center_top = center_bottom + 1;
for (int i=0; i<segments; i++) {
int next = (i+1) % segments;
// bottom cap
indices[ii++] = center_bottom;
indices[ii++] = cap_base + i*2;
indices[ii++] = cap_base + next*2;
// top cap
indices[ii++] = center_top;
indices[ii++] = cap_base + next*2+1;
indices[ii++] = cap_base + i*2+1;
}
Mesh m = mesh_default;
m.vertexCount = vertex_count;
m.indexCount = index_count;
m.hasIndices = true;
m.drawMode = GL_TRIANGLES;
glGenVertexArrays(1,&m.vao);
glGenBuffers(1,&m.vbo);
glGenBuffers(1,&m.ebo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER,m.vbo);
glBufferData(GL_ARRAY_BUFFER,vertex_count*9*sizeof(float),vertices,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_count*sizeof(unsigned int),indices,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(6*sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
free(vertices);
free(indices);
free(cos_vals);
free(sin_vals);
return m;
}
Mesh Mesh_createAxes(float length) {
float vertices[] = {
// X axis (red)
0.0f, 0.0f, 0.0f, 1,0,0,
length, 0.0f, 0.0f, 1,0,0,
// Y axis (green)
0.0f, 0.0f, 0.0f, 0,1,0,
0.0f, length, 0.0f, 0,1,0,
// Z axis (blue)
0.0f, 0.0f, 0.0f, 0,0,1,
0.0f, 0.0f, length,0,0,1
};
Mesh m = mesh_default;
glGenVertexArrays(1, &m.vao);
glGenBuffers(1, &m.vbo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER, m.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
m.vertexCount = 6; // 3 lines * 2 vertices
m.drawMode = GL_LINES;
m.ebo = 0;
m.hasIndices = false;
return m;
}
static void addCube(
float* vertices, unsigned int* indices,
int* vOffset, int* iOffset, int* vertexBase,
Vec3 pos, Vec3 size, VertexPreset preset)
{
float hx = size.x / 2.0f;
float hy = size.y / 2.0f;
float hz = size.z / 2.0f;
float faceColors[6][3];
switch (preset) {
case CUBE_VERTICES_STANDARD:
for (int f=0; f<6; f++){ faceColors[f][0]=1; faceColors[f][1]=1; faceColors[f][2]=1; }
break;
case CUBE_VERTICES_MODERN:
faceColors[0][0]=1;faceColors[0][1]=0;faceColors[0][2]=0;
faceColors[1][0]=0;faceColors[1][1]=1;faceColors[1][2]=0;
faceColors[2][0]=0;faceColors[2][1]=0;faceColors[2][2]=1;
faceColors[3][0]=1;faceColors[3][1]=1;faceColors[3][2]=0;
faceColors[4][0]=1;faceColors[4][1]=0;faceColors[4][2]=1;
faceColors[5][0]=0;faceColors[5][1]=1;faceColors[5][2]=1;
break;
case CUBE_VERTICES_GROUND:
for (int i=0;i<4;i++){ faceColors[i][0]=0.55f; faceColors[i][1]=0.27f; faceColors[i][2]=0.07f; }
faceColors[4][0]=0.3f; faceColors[4][1]=0.15f; faceColors[4][2]=0.05f;
faceColors[5][0]=0.1f; faceColors[5][1]=0.8f; faceColors[5][2]=0.1f;
break;
case CUBE_VERTICES_WARM:
for (int f=0; f<6; f++){ faceColors[f][0]=1; faceColors[f][1]=0.5; faceColors[f][2]=0; }
break;
}
Vec3 faceNormals[6] = {
{0,0,-1}, {0,0,1}, {-1,0,0}, {1,0,0}, {0,-1,0}, {0,1,0}
};
Vec3 faceOffsets[6][4] = {
{{-hx,-hy,-hz},{hx,-hy,-hz},{hx,hy,-hz},{-hx,hy,-hz}}, // back
{{-hx,-hy,hz},{hx,-hy,hz},{hx,hy,hz},{-hx,hy,hz}}, // front
{{-hx,-hy,-hz},{-hx,hy,-hz},{-hx,hy,hz},{-hx,-hy,hz}}, // left
{{hx,-hy,-hz},{hx,hy,-hz},{hx,hy,hz},{hx,-hy,hz}}, // right
{{-hx,-hy,-hz},{hx,-hy,-hz},{hx,-hy,hz},{-hx,-hy,hz}}, // bottom
{{-hx,hy,-hz},{hx,hy,-hz},{hx,hy,hz},{-hx,hy,hz}}, // top
};
for (int f=0; f<6; f++) {
for (int v=0; v<4; v++) {
vertices[(*vOffset)++] = pos.x + faceOffsets[f][v].x;
vertices[(*vOffset)++] = pos.y + faceOffsets[f][v].y;
vertices[(*vOffset)++] = pos.z + faceOffsets[f][v].z;
vertices[(*vOffset)++] = faceNormals[f].x;
vertices[(*vOffset)++] = faceNormals[f].y;
vertices[(*vOffset)++] = faceNormals[f].z;
vertices[(*vOffset)++] = faceColors[f][0];
vertices[(*vOffset)++] = faceColors[f][1];
vertices[(*vOffset)++] = faceColors[f][2];
}
unsigned int base = *vertexBase + f*4;
indices[(*iOffset)++] = base + 0;
indices[(*iOffset)++] = base + 1;
indices[(*iOffset)++] = base + 2;
indices[(*iOffset)++] = base + 2;
indices[(*iOffset)++] = base + 3;
indices[(*iOffset)++] = base + 0;
}
*vertexBase += 24;
}
Mesh Mesh_createHuman(VertexPreset preset, bool is_player) {
Mesh m = mesh_default;
float vertices[6*24*9]; // 6 parts * 24 vertices * 9 floats (pos+normal+color)
unsigned int indices[6*36];
int vOffset = 0, iOffset = 0, vertexBase = 0;
// Add body parts (same positions as before)
addCube(vertices, indices, &vOffset, &iOffset, &vertexBase, (Vec3){0.0f, 0.285f, 0.0f}, (Vec3){0.5f,0.57f,0.25f}, preset); // torso
if (!is_player)
addCube(vertices, indices, &vOffset, &iOffset, &vertexBase, (Vec3){0.0f, 0.72f, 0.0f}, (Vec3){0.2f,0.2f,0.2f}, preset); // head
addCube(vertices, indices, &vOffset, &iOffset, &vertexBase, (Vec3){-0.4f, 0.17f, 0.0f}, (Vec3){0.2f,0.76f,0.2f}, preset); // left arm
addCube(vertices, indices, &vOffset, &iOffset, &vertexBase, (Vec3){0.4f, 0.17f, 0.0f}, (Vec3){0.2f,0.76f,0.2f}, preset); // right arm
addCube(vertices, indices, &vOffset, &iOffset, &vertexBase, (Vec3){0.15f, -0.4f, 0.0f}, (Vec3){0.2f,0.76f,0.2f}, preset); // left leg
addCube(vertices, indices, &vOffset, &iOffset, &vertexBase, (Vec3){-0.15f, -0.4f, 0.0f}, (Vec3){0.2f,0.76f,0.2f}, preset); // right leg
m.vertexCount = vertexBase;
m.indexCount = iOffset;
m.hasIndices = true;
m.drawMode = GL_TRIANGLES;
glGenVertexArrays(1,&m.vao);
glGenBuffers(1,&m.vbo);
glGenBuffers(1,&m.ebo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER,m.vbo);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)0); // position
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(3*sizeof(float))); // normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(6*sizeof(float))); // color
glEnableVertexAttribArray(2);
glBindVertexArray(0);
return m;
}
Mesh Mesh_createHouse() {
float length = 18.0f;
float width = 12.0f;
float height = 6.0f;
float roofHeight = 5.0f;
float lx = length / 2.0f;
float wy = height;
float wz = width / 2.0f;
float rh = roofHeight;
// We’ll store positions, normals, colors
// Estimate: walls (24 verts), roof (12 verts), windows+doors (4 each)
float vertices[5000];
unsigned int indices[5000];
int vi = 0, ii = 0, vcount = 0;
// Helper macro to add a vertex
#define ADDV(px,py,pz,nx,ny,nz,r,g,b) \
do { \
vertices[vi++] = (px); \
vertices[vi++] = (py); \
vertices[vi++] = (pz); \
vertices[vi++] = (nx); \
vertices[vi++] = (ny); \
vertices[vi++] = (nz); \
vertices[vi++] = (r); \
vertices[vi++] = (g); \
vertices[vi++] = (b); \
} while(0)
// Brick color
float br = 0.7f, bg = 0.3f, bb = 0.2f;
// Roof color
float rr = 0.3f, rg = 0.3f, rb = 0.3f;
// Window color
float wr = 0.4f, wg = 0.6f, wb = 0.9f;
// Door color
float dr = 0.4f, dg = 0.2f, db = 0.05f;
// --- Walls (like cube, but long/short dimensions)
Vec3 faceNormals[6] = {
{ 0, 0, -1}, // back
{ 0, 0, 1}, // front
{-1, 0, 0}, // left
{ 1, 0, 0}, // right
{ 0, -1, 0}, // bottom
{ 0, 1, 0} // top
};
Vec3 wallOffsets[6][4] = {
{{-lx,0,-wz},{lx,0,-wz},{lx,wy,-wz},{-lx,wy,-wz}}, // back
{{-lx,0,wz},{lx,0,wz},{lx,wy,wz},{-lx,wy,wz}}, // front
{{-lx,0,-wz},{-lx,wy,-wz},{-lx,wy,wz},{-lx,0,wz}}, // left
{{lx,0,-wz},{lx,wy,-wz},{lx,wy,wz},{lx,0,wz}}, // right
{{-lx,0,-wz},{lx,0,-wz},{lx,0,wz},{-lx,0,wz}}, // bottom
{{-lx,wy,-wz},{lx,wy,-wz},{lx,wy,wz},{-lx,wy,wz}}, // top
};
for (int f=0; f<6; f++) {
for (int v=0; v<4; v++) {
ADDV(wallOffsets[f][v].x, wallOffsets[f][v].y, wallOffsets[f][v].z,
faceNormals[f].x, faceNormals[f].y, faceNormals[f].z,
br,bg,bb);
}
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
indices[ii++] = vcount+2; indices[ii++] = vcount+3; indices[ii++] = vcount;
vcount += 4;
}
// --- Roof (triangular prism)
// ridge runs along x-axis (length), centered
// base at y=wy, height = rh
ADDV(-lx,wy,-wz, 0,1,0, rr,rg,rb); // left-back
ADDV(-lx,wy, wz, 0,1,0, rr,rg,rb); // left-front
ADDV(-lx,wy+rh, 0, 0,1,0, rr,rg,rb); // left-top
ADDV( lx,wy,-wz, 0,1,0, rr,rg,rb); // right-back
ADDV( lx,wy, wz, 0,1,0, rr,rg,rb); // right-front
ADDV( lx,wy+rh, 0, 0,1,0, rr,rg,rb); // right-top
// Left triangle
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
// Right triangle
indices[ii++] = vcount+3; indices[ii++] = vcount+4; indices[ii++] = vcount+5;
// Back roof quad
indices[ii++] = vcount; indices[ii++] = vcount+3; indices[ii++] = vcount+5;
indices[ii++] = vcount+5; indices[ii++] = vcount+2; indices[ii++] = vcount;
// Front roof quad
indices[ii++] = vcount+1; indices[ii++] = vcount+4; indices[ii++] = vcount+5;
indices[ii++] = vcount+5; indices[ii++] = vcount+2; indices[ii++] = vcount+1;
vcount += 6;
// --- Windows (3 along front wall at z=+wz)
float winSize = 1.5f;
float winY = 3.0f;
for (int i=0;i<3;i++) {
float cx = -lx + (i+1)*length/4.0f; // evenly spaced
float cy = winY;
float cz = wz+0.01f;
ADDV(cx-winSize,cy-winSize,cz, 0,0,1, wr,wg,wb);
ADDV(cx+winSize,cy-winSize,cz, 0,0,1, wr,wg,wb);
ADDV(cx+winSize,cy+winSize,cz, 0,0,1, wr,wg,wb);
ADDV(cx-winSize,cy+winSize,cz, 0,0,1, wr,wg,wb);
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
indices[ii++] = vcount+2; indices[ii++] = vcount+3; indices[ii++] = vcount;
vcount += 4;
}
// --- Doors (front and back)
float dw = 1.0f, dh = 2.0f;
// Front door
ADDV(-lx+1,0,wz+0.01f, 0,0,1, dr,dg,db);
ADDV(-lx+1+dw,0,wz+0.01f, 0,0,1, dr,dg,db);
ADDV(-lx+1+dw,dh,wz+0.01f, 0,0,1, dr,dg,db);
ADDV(-lx+1,dh,wz+0.01f, 0,0,1, dr,dg,db);
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
indices[ii++] = vcount+2; indices[ii++] = vcount+3; indices[ii++] = vcount;
vcount += 4;
// Back door
ADDV(lx-1-dw,0,-wz-0.01f, 0,0,-1, dr,dg,db);
ADDV(lx-1,0,-wz-0.01f, 0,0,-1, dr,dg,db);
ADDV(lx-1,dh,-wz-0.01f, 0,0,-1, dr,dg,db);
ADDV(lx-1-dw,dh,-wz-0.01f, 0,0,-1, dr,dg,db);
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
indices[ii++] = vcount+2; indices[ii++] = vcount+3; indices[ii++] = vcount;
vcount += 4;
// Upload to GPU
Mesh m = mesh_default;
m.vertexCount = vcount;
m.indexCount = ii;
m.hasIndices = true;
m.drawMode = GL_TRIANGLES;
glGenVertexArrays(1,&m.vao);
glGenBuffers(1,&m.vbo);
glGenBuffers(1,&m.ebo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER,m.vbo);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(6*sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
return m;
}
Mesh Mesh_createBarn() {
float length = 24.0f;
float width = 12.0f;
float height = 6.0f;
float roofHeight = 5.0f;
float lx = length / 2.0f;
float wy = height;
float wz = width / 2.0f;
float rh = roofHeight;
// We’ll store positions, normals, colors
// Estimate: walls (24 verts), roof (12 verts), windows+doors (4 each)
float vertices[5000];
unsigned int indices[5000];
int vi = 0, ii = 0, vcount = 0;
// Helper macro to add a vertex
#define ADDV(px,py,pz,nx,ny,nz,r,g,b) \
do { \
vertices[vi++] = (px); \
vertices[vi++] = (py); \
vertices[vi++] = (pz); \
vertices[vi++] = (nx); \
vertices[vi++] = (ny); \
vertices[vi++] = (nz); \
vertices[vi++] = (r); \
vertices[vi++] = (g); \
vertices[vi++] = (b); \
} while(0)
// Brick color
float br = 0.7f, bg = 0.3f, bb = 0.2f;
// Roof color
float rr = 0.3f, rg = 0.3f, rb = 0.3f;
// --- Walls (like cube, but long/short dimensions)
Vec3 faceNormals[6] = {
{ 0, 0, -1}, // back
{ 0, 0, 1}, // front
{-1, 0, 0}, // left
{ 1, 0, 0}, // right
{ 0, -1, 0}, // bottom
{ 0, 1, 0} // top
};
Vec3 wallOffsets[6][4] = {
{{-lx,0,-wz},{lx,0,-wz},{lx,wy,-wz},{-lx,wy,-wz}}, // back
{{-lx,0,wz},{lx,0,wz},{lx,wy,wz},{-lx,wy,wz}}, // front
{{-lx,0,-wz},{-lx,wy,-wz},{-lx,wy,wz},{-lx,0,wz}}, // left
{{lx,0,-wz},{lx,wy,-wz},{lx,wy,wz},{lx,0,wz}}, // right
{{-lx,0,-wz},{lx,0,-wz},{lx,0,wz},{-lx,0,wz}}, // bottom
{{-lx,wy,-wz},{lx,wy,-wz},{lx,wy,wz},{-lx,wy,wz}}, // top
};
for (int f=0; f<6; f++) {
for (int v=0; v<4; v++) {
ADDV(wallOffsets[f][v].x, wallOffsets[f][v].y, wallOffsets[f][v].z,
faceNormals[f].x, faceNormals[f].y, faceNormals[f].z,
br,bg,bb);
}
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
indices[ii++] = vcount+2; indices[ii++] = vcount+3; indices[ii++] = vcount;
vcount += 4;
}
// --- Roof (triangular prism)
// ridge runs along x-axis (length), centered
// base at y=wy, height = rh
ADDV(-lx,wy,-wz, 0,1,0, rr,rg,rb); // left-back
ADDV(-lx,wy, wz, 0,1,0, rr,rg,rb); // left-front
ADDV(-lx,wy+rh, 0, 0,1,0, rr,rg,rb); // left-top
ADDV( lx,wy,-wz, 0,1,0, rr,rg,rb); // right-back
ADDV( lx,wy, wz, 0,1,0, rr,rg,rb); // right-front
ADDV( lx,wy+rh, 0, 0,1,0, rr,rg,rb); // right-top
// Left triangle
indices[ii++] = vcount; indices[ii++] = vcount+1; indices[ii++] = vcount+2;
// Right triangle
indices[ii++] = vcount+3; indices[ii++] = vcount+4; indices[ii++] = vcount+5;
// Back roof quad
indices[ii++] = vcount; indices[ii++] = vcount+3; indices[ii++] = vcount+5;
indices[ii++] = vcount+5; indices[ii++] = vcount+2; indices[ii++] = vcount;
// Front roof quad
indices[ii++] = vcount+1; indices[ii++] = vcount+4; indices[ii++] = vcount+5;
indices[ii++] = vcount+5; indices[ii++] = vcount+2; indices[ii++] = vcount+1;
vcount += 6;
// Upload to GPU
Mesh m = mesh_default;
m.vertexCount = vcount;
m.indexCount = ii;
m.hasIndices = true;
m.drawMode = GL_TRIANGLES;
glGenVertexArrays(1,&m.vao);
glGenBuffers(1,&m.vbo);
glGenBuffers(1,&m.ebo);
glBindVertexArray(m.vao);
glBindBuffer(GL_ARRAY_BUFFER,m.vbo);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,9*sizeof(float),(void*)(6*sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
return m;
}