deez nuts
This commit is contained in:
Radonchnk 2025-04-19 14:28:01 +01:00
commit 4999b300b2
7 changed files with 806 additions and 60 deletions

View file

@ -25,6 +25,7 @@ pub fn build(b: *std.Build) void {
exe.linkLibrary(rl.artifact("raylib"));
exe.root_module.addImport("znoise", znoise.module("root"));
exe.root_module.addIncludePath(b.path("src/c"));
exe.linkLibrary(znoise.artifact("FastNoiseLite"));
b.installArtifact(exe);
@ -47,6 +48,7 @@ pub fn build(b: *std.Build) void {
exe_unit_tests.linkLibrary(rl.artifact("raylib"));
exe_unit_tests.root_module.addImport("znoise", znoise.module("root"));
exe_unit_tests.linkLibrary(znoise.artifact("FastNoiseLite"));
exe_unit_tests.root_module.addIncludePath(b.path("src/c"));
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

View file

@ -4,8 +4,8 @@ uniform sampler2D diffuseMap;
uniform vec2 textureTiling;
in vec2 fragTexCoord;
in vec2 fragTexCoord2;
in vec4 fragColor;
in vec3 fragNormal;
in vec2 fragTileTexCoord;
flat in int ambientOcclusionSide1;
flat in int ambientOcclusionSide2;
flat in int ambientOcclusionCorner1;
@ -16,14 +16,28 @@ flat in int quadWidth;
out vec4 outColor;
// this is a shitty approximation of arcsin(x)/pi that gets the tails right and is reasonably close to the actual arcsin(x)/pi curve.
float fakeArcsin(float x) {
x = clamp(x, -1.0, 1.0);
float ax = abs(x);
float sqrtPart = sqrt(1.0 - ax);
float result = 0.5 - sqrtPart * (0.5 - 0.06667 * ax);
return x < 0.0 ? -result : result;
}
void main()
{
vec2 texCoord = (floor(fragTexCoord*textureTiling) + fract(fragTexCoord2)) / textureTiling;
vec2 texCoord = (floor(fragTexCoord*textureTiling) + fract(fragTileTexCoord)) / textureTiling;
outColor = texture(diffuseMap, texCoord);
ivec2 floorFragTexCoord2 = ivec2(fragTexCoord2);
if ((fragTexCoord2.x < 0.05 || fragTexCoord2.x > quadWidth-0.05) && (((ambientOcclusionSide1 >> floorFragTexCoord2.y) & 1) == 1)) outColor *= 0.5;
else if((fragTexCoord2.y < 0.05 || fragTexCoord2.y > quadHeight-0.05) && (((ambientOcclusionSide2 >> floorFragTexCoord2.y) & 1) == 1)) outColor *= 0.5;
ivec2 floorFragTileTexCoord = ivec2(fragTileTexCoord);
if(fragTileTexCoord.x < 1 && (((ambientOcclusionSide1 >> floorFragTileTexCoord.y) & 1) == 1)) outColor *= 0.5 + fakeArcsin(fragTileTexCoord.x);
// if(fragTileTexCoord.x < 0.125 && fragTileTexCoord.x < fract(fragTileTexCoord.y) && fragTileTexCoord.x + fract(fragTileTexCoord.y) < 1.0 && ((ambientOcclusionSide1 >> floorFragTileTexCoord.y) & 1) == 1) outColor *= 0.5;
//if((fragTileTexCoord.x < 0.25 || fragTileTexCoord.x > quadWidth-0.25) && (((ambientOcclusionSide1 >> floorFragTileTexCoord.y) & 1) == 1)) outColor *= 0.5;
//if((fragTileTexCoord.y < 0.25 || fragTileTexCoord.y > quadHeight-0.25) && (((ambientOcclusionSide2 >> floorFragTileTexCoord.y) & 1) == 1)) outColor *= 0.5;
outColor.a = 1;
}

View file

@ -2,13 +2,13 @@
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec2 vertexTexCoord2;
in vec4 vertexColor;
in vec4 vertexTangent; // metadata1
in vec3 vertexNormal;
in vec2 vertexTileTexCoord;
in vec4 vertexMetadata1;
out vec2 fragTexCoord;
out vec2 fragTexCoord2;
out vec4 fragColor;
out vec3 fragNormal;
out vec2 fragTileTexCoord;
flat out int ambientOcclusionSide1;
flat out int ambientOcclusionSide2;
@ -22,18 +22,18 @@ uniform mat4 mvp;
void main() {
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
fragTexCoord2 = vertexTexCoord2;
fragTileTexCoord = vertexTileTexCoord;
fragNormal = vertexNormal;
gl_Position = mvp*vec4(vertexPosition, 1.0);
// metadata 1 processing
ambientOcclusionSide1 = floatBitsToInt(vertexTangent.x);
ambientOcclusionSide2 = floatBitsToInt(vertexTangent.y);
int metadata1Z = floatBitsToInt(vertexTangent.z);
int metadata1W = floatBitsToInt(vertexTangent.w);
ambientOcclusionCorner1 = (metadata1Z & 0x1) >> 0;
ambientOcclusionCorner2 = (metadata1Z & 0x2) >> 1;
ambientOcclusionCorner3 = (metadata1Z & 0x4) >> 2;
quadHeight = (metadata1Z & 0x1f8) >> 3;
quadWidth = (metadata1Z & 0x7e00) >> 9;
// metadata 1 parsing
ambientOcclusionSide1 = floatBitsToInt(vertexMetadata1.x);
ambientOcclusionSide2 = floatBitsToInt(vertexMetadata1.y);
int metadata1Z = floatBitsToInt(vertexMetadata1.z);
int metadata1W = floatBitsToInt(vertexMetadata1.w);
ambientOcclusionCorner1 = (metadata1Z & 0x1) >> 0; // Take 0th bit.
ambientOcclusionCorner2 = (metadata1Z & 0x2) >> 1; // Take 1st bit.
ambientOcclusionCorner3 = (metadata1Z & 0x4) >> 2; // Take 2nd bit.
quadHeight = (metadata1Z & 0x1f8) >> 3; // Take 3rd-8th bits.
quadWidth = (metadata1Z & 0x7e00) >> 9; // Take 9th-14th bits.
}

675
src/c/raylib_extension.h Normal file
View file

@ -0,0 +1,675 @@
/**********************************************************************************************
* This file contains modified pieces of code from the Raylib library.
* Original license follows below.
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
**********************************************************************************************/
#include "raylib.h"
#include "rlgl.h"
#include "raymath.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHUNK_MAX_MESH_VERTEX_BUFFERS 5
#define CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
#define CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
#define CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
#define CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD 3
#define CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1 4
#define CHUNK_MAX_MATERIAL_MAPS 12
#define CHUNK_MAX_SHADER_LOCATIONS 32
typedef enum {
CHUNK_SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position
CHUNK_SHADER_LOC_VERTEX_TEXCOORD, // Shader location: vertex attribute: texcoord
CHUNK_SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal
CHUNK_SHADER_LOC_VERTEX_TILETEXCOORD, // Shader location: vertex attribute: tiletexcoord
CHUNK_SHADER_LOC_VERTEX_METADATA1, // Shader location: vertex attribute: metadata1
CHUNK_SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection
CHUNK_SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform)
CHUNK_SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection
CHUNK_SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform)
CHUNK_SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal
CHUNK_SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view
CHUNK_SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color
CHUNK_SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color
CHUNK_SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color
CHUNK_SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: CHUNK_SHADER_LOC_MAP_DIFFUSE)
CHUNK_SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: CHUNK_SHADER_LOC_MAP_SPECULAR)
CHUNK_SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal
CHUNK_SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness
CHUNK_SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion
CHUNK_SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission
CHUNK_SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height
CHUNK_SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap
CHUNK_SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance
CHUNK_SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter
CHUNK_SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf
} chunkShaderLocationIndex;
#define CHUNK_SHADER_LOC_MAP_DIFFUSE CHUNK_SHADER_LOC_MAP_ALBEDO
#define CHUNK_SHADER_LOC_MAP_SPECULAR CHUNK_SHADER_LOC_MAP_METALNESS
#define CHUNK_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
#define CHUNK_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
#define CHUNK_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
#define CHUNK_DEFAULT_SHADER_ATTRIB_NAME_TILETEXCOORD "vertexTileTexCoord" // Bound by default to shader location: CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD
#define CHUNK_DEFAULT_SHADER_ATTRIB_NAME_METADATA1 "vertexMetadata1" // Bound by default to shader location: CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)))
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
#define CHUNK_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices
#define CHUNK_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
#define CHUNK_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
#define CHUNK_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
typedef struct ChunkMesh {
int vertexCount; // Number of vertices stored in arrays
int triangleCount; // Number of triangles stored (indexed or not)
// Vertex attributes data
float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tiletexcoords; // Vertex tile tex coordinates (UV - 2 components per vertex) (shader-location = 3)
float *metadata1; // Vertex metadata 1 (ABCD - 4 components per vertex) (shader-location = 4)
// OpenGL identifiers
unsigned int vaoId; // OpenGL Vertex Array Object id
unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data)
} ChunkMesh;
// Model, meshes, materials and animation data
typedef struct ChunkModel {
Matrix transform; // Local transform matrix
int meshCount; // Number of meshes
int materialCount; // Number of materials
ChunkMesh *meshes; // Meshes array
Material *materials; // Materials array
int *meshMaterial; // Mesh material number
// Animation data
int boneCount; // Number of bones
BoneInfo *bones; // Bones information (skeleton)
Transform *bindPose; // Bones base transformation (pose)
} ChunkModel;
RLAPI void UploadChunkMesh(ChunkMesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids
RLAPI ChunkModel LoadChunkModelFromMesh(ChunkMesh mesh); // Load model from generated mesh (default material)
RLAPI void UnloadChunkModel(ChunkModel model); // Unload model (including meshes) from memory (RAM and/or VRAM)
RLAPI void UnloadChunkMesh(ChunkMesh mesh); // Unload mesh data from CPU and GPU
RLAPI void DrawChunkModel(ChunkModel model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
RLAPI void DrawChunkModelEx(ChunkModel model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
RLAPI void DrawChunkMesh(ChunkMesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
RLAPI Shader LoadChunkShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadChunkShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
RLAPI unsigned int chunkLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings
RLAPI unsigned int chunkLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program
// Upload vertex data into a VAO (if supported) and VBO
void UploadChunkMesh(ChunkMesh *mesh, bool dynamic) {
if (mesh->vaoId > 0)
{
// Check if mesh has already been loaded in GPU
printf("CHUNK VAO: [ID %i] Trying to re-load an already loaded mesh\n", mesh->vaoId);
return;
}
mesh->vboId = (unsigned int *)RL_CALLOC(CHUNK_MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
mesh->vaoId = 0; // Vertex Array Object
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0;
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0;
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0;
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD] = 0;
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1] = 0;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
mesh->vaoId = rlLoadVertexArray();
rlEnableVertexArray(mesh->vaoId);
// NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
// Enable vertex attributes: position (shader-location = 0)
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(mesh->vertices, mesh->vertexCount*3*sizeof(float), dynamic);
rlSetVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION);
// Enable vertex attributes: texcoords (shader-location = 1)
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
rlSetVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
// Enable vertex attributes: normals (shader-location = 2)
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(mesh->normals, mesh->vertexCount*3*sizeof(float), dynamic);
rlSetVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
// Enable vertex attribute: tiletexcoord (shader-location = 3)
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD] = rlLoadVertexBuffer(mesh->tiletexcoords, mesh->vertexCount*2*sizeof(float), dynamic);
rlSetVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD, 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD);
// Enable vertex attribute: metadata1 (shader-location = 4)
mesh->vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1] = rlLoadVertexBuffer(mesh->metadata1, mesh->vertexCount*4*sizeof(float), dynamic);
rlSetVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1, 4, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1);
if (mesh->vaoId > 0) printf("CHUNK VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)\n", mesh->vaoId);
else printf("CHUNK VBO: Mesh uploaded successfully to VRAM (GPU)");
rlDisableVertexArray();
#endif
}
// Load model from generated mesh
// WARNING: A shallow copy of mesh is generated, passed by value,
// as long as struct contains pointers to data and some values, we get a copy
// of mesh pointing to same data as original version... be careful!
ChunkModel LoadChunkModelFromMesh(ChunkMesh mesh)
{
ChunkModel model = { 0 };
model.transform = MatrixIdentity();
model.meshCount = 1;
model.meshes = (ChunkMesh *)RL_CALLOC(model.meshCount, sizeof(ChunkMesh));
model.meshes[0] = mesh;
model.materialCount = 1;
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
model.materials[0] = LoadMaterialDefault();
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
model.meshMaterial[0] = 0; // First material index
return model;
}
// Unload model (meshes/materials) from memory (RAM and/or VRAM)
// NOTE: This function takes care of all model elements, for a detailed control
// over them, use UnloadMesh() and UnloadMaterial()
void UnloadChunkModel(ChunkModel model)
{
// Unload meshes
for (int i = 0; i < model.meshCount; i++) UnloadChunkMesh(model.meshes[i]);
// Unload materials maps
// NOTE: As the user could be sharing shaders and textures between models,
// we don't unload the material but just free its maps,
// the user is responsible for freeing models shaders and textures
for (int i = 0; i < model.materialCount; i++) RL_FREE(model.materials[i].maps);
// Unload arrays
RL_FREE(model.meshes);
RL_FREE(model.materials);
RL_FREE(model.meshMaterial);
TRACELOG(LOG_INFO, "CHUNK MODEL: Unloaded model (and meshes) from RAM and VRAM");
}
// Unload mesh from memory (RAM and VRAM)
void UnloadChunkMesh(ChunkMesh mesh)
{
// Unload rlgl mesh vboId data
rlUnloadVertexArray(mesh.vaoId);
if (mesh.vboId != NULL) for (int i = 0; i < CHUNK_MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
RL_FREE(mesh.vboId);
RL_FREE(mesh.vertices);
RL_FREE(mesh.texcoords);
RL_FREE(mesh.normals);
RL_FREE(mesh.tiletexcoords);
}
// Draw a model (with texture if set)
void DrawChunkModel(ChunkModel model, Vector3 position, float scale, Color tint)
{
Vector3 vScale = { scale, scale, scale };
Vector3 rotationAxis = { 0.0f, 1.0f, 0.0f };
DrawChunkModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
}
// Draw a model with extended parameters
void DrawChunkModelEx(ChunkModel model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
// Calculate transformation matrix from function parameters
// Get transform matrix (rotation -> scale -> translation)
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
// Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
model.transform = MatrixMultiply(model.transform, matTransform);
for (int i = 0; i < model.meshCount; i++)
{
Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
Color colorTint = WHITE;
colorTint.r = (unsigned char)(((int)color.r*(int)tint.r)/255);
colorTint.g = (unsigned char)(((int)color.g*(int)tint.g)/255);
colorTint.b = (unsigned char)(((int)color.b*(int)tint.b)/255);
colorTint.a = (unsigned char)(((int)color.a*(int)tint.a)/255);
model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
DrawChunkMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = color;
}
}
// Draw a 3d mesh with material and transform
void DrawChunkMesh(ChunkMesh mesh, Material material, Matrix transform)
{
#if defined(GRAPHICS_API_OPENGL_11)
#define GL_VERTEX_ARRAY 0x8074
#define GL_NORMAL_ARRAY 0x8075
#define GL_COLOR_ARRAY 0x8076
#define GL_TEXTURE_COORD_ARRAY 0x8078
rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
rlPushMatrix();
rlMultMatrixf(MatrixToFloat(transform));
rlColor4ub(material.maps[MATERIAL_MAP_DIFFUSE].color.r,
material.maps[MATERIAL_MAP_DIFFUSE].color.g,
material.maps[MATERIAL_MAP_DIFFUSE].color.b,
material.maps[MATERIAL_MAP_DIFFUSE].color.a);
if (mesh.indices != NULL) rlDrawVertexArrayElements(0, mesh.triangleCount*3, mesh.indices);
else rlDrawVertexArray(0, mesh.vertexCount);
rlPopMatrix();
rlDisableStatePointer(GL_VERTEX_ARRAY);
rlDisableStatePointer(GL_TEXTURE_COORD_ARRAY);
rlDisableStatePointer(GL_NORMAL_ARRAY);
rlDisableStatePointer(GL_COLOR_ARRAY);
rlDisableTexture();
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Bind shader program
rlEnableShader(material.shader.id);
// Send required data to shader (matrices, values)
//-----------------------------------------------------
// Upload to shader material.colDiffuse
if (material.shader.locs[CHUNK_SHADER_LOC_COLOR_DIFFUSE] != -1)
{
float values[4] = {
(float)material.maps[MATERIAL_MAP_DIFFUSE].color.r/255.0f,
(float)material.maps[MATERIAL_MAP_DIFFUSE].color.g/255.0f,
(float)material.maps[MATERIAL_MAP_DIFFUSE].color.b/255.0f,
(float)material.maps[MATERIAL_MAP_DIFFUSE].color.a/255.0f
};
rlSetUniform(material.shader.locs[CHUNK_SHADER_LOC_COLOR_DIFFUSE], values, SHADER_UNIFORM_VEC4, 1);
}
// Upload to shader material.colSpecular (if location available)
if (material.shader.locs[CHUNK_SHADER_LOC_COLOR_SPECULAR] != -1)
{
float values[4] = {
(float)material.maps[MATERIAL_MAP_SPECULAR].color.r/255.0f,
(float)material.maps[MATERIAL_MAP_SPECULAR].color.g/255.0f,
(float)material.maps[MATERIAL_MAP_SPECULAR].color.b/255.0f,
(float)material.maps[MATERIAL_MAP_SPECULAR].color.a/255.0f
};
rlSetUniform(material.shader.locs[CHUNK_SHADER_LOC_COLOR_SPECULAR], values, SHADER_UNIFORM_VEC4, 1);
}
// Get a copy of current matrices to work with,
// just in case stereo render is required, and we need to modify them
// NOTE: At this point the modelview matrix just contains the view matrix (camera)
// That's because BeginMode3D() sets it and there is no model-drawing function
// that modifies it, all use rlPushMatrix() and rlPopMatrix()
Matrix matModel = MatrixIdentity();
Matrix matView = rlGetMatrixModelview();
Matrix matModelView = MatrixIdentity();
Matrix matProjection = rlGetMatrixProjection();
// Upload view and projection matrices (if locations available)
if (material.shader.locs[CHUNK_SHADER_LOC_MATRIX_VIEW] != -1) rlSetUniformMatrix(material.shader.locs[CHUNK_SHADER_LOC_MATRIX_VIEW], matView);
if (material.shader.locs[CHUNK_SHADER_LOC_MATRIX_PROJECTION] != -1) rlSetUniformMatrix(material.shader.locs[CHUNK_SHADER_LOC_MATRIX_PROJECTION], matProjection);
// Accumulate several model transformations:
// transform: model transformation provided (includes DrawModel() params combined with model.transform)
// rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
matModel = MatrixMultiply(transform, rlGetMatrixTransform());
// Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL
if (material.shader.locs[CHUNK_SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[CHUNK_SHADER_LOC_MATRIX_MODEL], matModel);
// Get model-view matrix
matModelView = MatrixMultiply(matModel, matView);
// Upload model normal matrix (if locations available)
if (material.shader.locs[CHUNK_SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[CHUNK_SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
//-----------------------------------------------------
// Bind active texture maps (if available)
for (int i = 0; i < CHUNK_MAX_MATERIAL_MAPS; i++)
{
if (material.maps[i].texture.id > 0)
{
// Select current shader texture slot
rlActiveTextureSlot(i);
// Enable texture for active slot
if ((i == MATERIAL_MAP_IRRADIANCE) ||
(i == MATERIAL_MAP_PREFILTER) ||
(i == MATERIAL_MAP_CUBEMAP)) rlEnableTextureCubemap(material.maps[i].texture.id);
else rlEnableTexture(material.maps[i].texture.id);
rlSetUniform(material.shader.locs[CHUNK_SHADER_LOC_MAP_DIFFUSE + i], &i, SHADER_UNIFORM_INT, 1);
}
}
// Try binding vertex array objects (VAO) or use VBOs if not possible
// WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values
// for shader expected vertex attributes that are not provided by the mesh (i.e. colors)
// This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes
if (!rlEnableVertexArray(mesh.vaoId))
{
// Bind mesh VBO data: vertex position (shader-location = 0)
rlEnableVertexBuffer(mesh.vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
rlSetVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_POSITION]);
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
rlEnableVertexBuffer(mesh.vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
rlSetVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_TEXCOORD], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_TEXCOORD]);
// Bind mesh VBO data: vertex normal (shader-location = 2)
rlEnableVertexBuffer(mesh.vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
rlSetVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_NORMAL]);
// Bind mesh VBO data: vertex tiletexcoords (shader-location = 3)
rlEnableVertexBuffer(mesh.vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD]);
rlSetVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_TILETEXCOORD], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_TILETEXCOORD]);
// Bind mesh VBO data: vertex metadata1 (shader-location = 4)
rlEnableVertexBuffer(mesh.vboId[CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1]);
rlSetVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_METADATA1], 4, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[CHUNK_SHADER_LOC_VERTEX_METADATA1]);
}
int eyeCount = 1;
if (rlIsStereoRenderEnabled()) eyeCount = 2;
for (int eye = 0; eye < eyeCount; eye++)
{
// Calculate model-view-projection matrix (MVP)
Matrix matModelViewProjection = MatrixIdentity();
if (eyeCount == 1) matModelViewProjection = MatrixMultiply(matModelView, matProjection);
else
{
// Setup current eye viewport (half screen width)
rlViewport(eye*rlGetFramebufferWidth()/2, 0, rlGetFramebufferWidth()/2, rlGetFramebufferHeight());
matModelViewProjection = MatrixMultiply(MatrixMultiply(matModelView, rlGetMatrixViewOffsetStereo(eye)), rlGetMatrixProjectionStereo(eye));
}
// Send combined model-view-projection matrix to shader
rlSetUniformMatrix(material.shader.locs[CHUNK_SHADER_LOC_MATRIX_MVP], matModelViewProjection);
// Draw mesh
rlDrawVertexArray(0, mesh.vertexCount);
}
// Unbind all bound texture maps
for (int i = 0; i < CHUNK_MAX_MATERIAL_MAPS; i++)
{
if (material.maps[i].texture.id > 0)
{
// Select current shader texture slot
rlActiveTextureSlot(i);
// Disable texture for active slot
if ((i == MATERIAL_MAP_IRRADIANCE) ||
(i == MATERIAL_MAP_PREFILTER) ||
(i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
else rlDisableTexture();
}
}
// Disable all possible vertex array objects (or VBOs)
rlDisableVertexArray();
rlDisableVertexBuffer();
rlDisableVertexBufferElement();
// Disable shader program
rlDisableShader();
// Restore rlgl internal modelview and projection matrices
rlSetMatrixModelview(matView);
rlSetMatrixProjection(matProjection);
#endif
}
// Load shader from files and bind default locations
// NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadChunkShader(const char *vsFileName, const char *fsFileName)
{
Shader shader = { 0 };
char *vShaderStr = NULL;
char *fShaderStr = NULL;
if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName);
if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName);
if ((vShaderStr == NULL) && (fShaderStr == NULL)) printf("CHUNK SHADER: Shader files provided are not valid, using default shader\n");
shader = LoadChunkShaderFromMemory(vShaderStr, fShaderStr);
UnloadFileText(vShaderStr);
UnloadFileText(fShaderStr);
printf("CHUNK SHADER: Shader loaded successfully from shader files\n");
return shader;
}
// Load shader from code strings and bind default locations
Shader LoadChunkShaderFromMemory(const char *vsCode, const char *fsCode)
{
Shader shader = { 0 };
shader.id = rlLoadShaderCode(vsCode, fsCode);
if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
else if (shader.id > 0)
{
// After custom shader loading, we TRY to set default location names
// Default shader attribute locations have been binded before linking:
// vertex position location = 0
// vertex texcoord location = 1
// vertex normal location = 2
// vertex tiletexcoord location = 3
// vertex metadata1 location = 4
// NOTE: If any location is not found, loc point becomes -1
shader.locs = (int *)RL_CALLOC(CHUNK_MAX_SHADER_LOCATIONS, sizeof(int));
// All locations reset to -1 (no location)
for (int i = 0; i < CHUNK_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
// Get handles to GLSL input attribute locations
shader.locs[CHUNK_SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
shader.locs[CHUNK_SHADER_LOC_VERTEX_TEXCOORD] = rlGetLocationAttrib(shader.id, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
shader.locs[CHUNK_SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
shader.locs[CHUNK_SHADER_LOC_VERTEX_TILETEXCOORD] = rlGetLocationAttrib(shader.id, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_TILETEXCOORD);
shader.locs[CHUNK_SHADER_LOC_VERTEX_METADATA1] = rlGetLocationAttrib(shader.id, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_METADATA1);
// Get handles to GLSL uniform locations (vertex shader)
shader.locs[CHUNK_SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_UNIFORM_NAME_MVP);
shader.locs[CHUNK_SHADER_LOC_MATRIX_VIEW] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_UNIFORM_NAME_VIEW);
shader.locs[CHUNK_SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION);
shader.locs[CHUNK_SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_UNIFORM_NAME_MODEL);
shader.locs[CHUNK_SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_UNIFORM_NAME_NORMAL);
// Get handles to GLSL uniform locations (fragment shader)
shader.locs[CHUNK_SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_UNIFORM_NAME_COLOR);
shader.locs[CHUNK_SHADER_LOC_MAP_DIFFUSE] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0); // SHADER_LOC_MAP_ALBEDO
shader.locs[CHUNK_SHADER_LOC_MAP_SPECULAR] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1); // SHADER_LOC_MAP_METALNESS
shader.locs[CHUNK_SHADER_LOC_MAP_NORMAL] = rlGetLocationUniform(shader.id, CHUNK_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2);
}
return shader;
}
#ifdef RLGL_IMPLEMENTATION
// Load custom shader strings and return program id
unsigned int chunkLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
{
unsigned int program = 0;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
GLint success = 0;
program = glCreateProgram();
glAttachShader(program, vShaderId);
glAttachShader(program, fShaderId);
// NOTE: Default attribute shader locations must be Bound before linking
glBindAttribLocation(program, CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
glBindAttribLocation(program, CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
glBindAttribLocation(program, CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
glBindAttribLocation(program, CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_TILETEXCOORD, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_TILETEXCOORD);
glBindAttribLocation(program, CHUNK_DEFAULT_SHADER_ATTRIB_LOCATION_METADATA1, CHUNK_DEFAULT_SHADER_ATTRIB_NAME_METADATA1);
// NOTE: If some attrib name is no found on the shader, it locations becomes -1
glLinkProgram(program);
// NOTE: All uniform variables are intitialised to 0 when a program links
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success == GL_FALSE)
{
printf("SHADER: [ID %i] Failed to link shader program\n", program);
int maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
if (maxLength > 0)
{
int length = 0;
char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
glGetProgramInfoLog(program, maxLength, &length, log);
printf("SHADER: [ID %i] Link error: %s\n", program, log);
RL_FREE(log);
}
glDeleteProgram(program);
program = 0;
}
else
{
// Get the size of compiled shader program (not available on OpenGL ES 2.0)
// NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero
//GLint binarySize = 0;
//glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize);
printf(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully\n", program);
}
#endif
}
// Load shader from code strings
// NOTE: If shader string is NULL, using default vertex/fragment shaders
unsigned int chunkLoadShaderCode(const char *vsCode, const char *fsCode)
{
unsigned int id = 0;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
unsigned int vertexShaderId = 0;
unsigned int fragmentShaderId = 0;
// Compile vertex shader (if provided)
// NOTE: If not vertex shader is provided, use default one
if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER);
else {
printf("vertex shader is null!\n");
exit(1);
}
// Compile fragment shader (if provided)
// NOTE: If not vertex shader is provided, use default one
if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER);
else {
printf("fragment shader is null!\n");
exit(1);
}
if ((vertexShaderId > 0) && (fragmentShaderId > 0))
{
// One of or both shader are new, we need to compile a new shader program
id = chunkLoadShaderProgram(vertexShaderId, fragmentShaderId);
// WARNING: Shader program linkage could fail and returned id is 0
if (id > 0) glDetachShader(id, vertexShaderId);
glDeleteShader(vertexShaderId);
// WARNING: Shader program linkage could fail and returned id is 0
if (id > 0) glDetachShader(id, fragmentShaderId);
glDeleteShader(fragmentShaderId);
// In case shader program loading failed
if (id == 0)
{
printf("failed to load custom shaders!\n");
exit(1);
}
}
#endif
return id;
}
#endif // RLGL_IMPLEMENTATION

View file

@ -1,6 +1,5 @@
pub const raylib = @cImport({
@cInclude("raylib.h");
@cInclude("raymath.h");
@cInclude("raylib_extension.h");
});
pub const v3 = struct {

View file

@ -50,9 +50,9 @@ pub fn main() !void {
raylib.SetWindowState(raylib.FLAG_FULLSCREEN_MODE);
var camera = raylib.Camera3D{
.position = raylib.Vector3{ .x = 0, .y = 0, .z = 0 },
.position = raylib.Vector3{ .x = 0, .y = 8, .z = 20 },
.up = raylib.Vector3{ .x = 0, .y = 1, .z = 0 },
.target = raylib.Vector3{ .x = 0, .y = 0, .z = -1 },
.target = raylib.Vector3{ .x = 0, .y = 8, .z = 19 },
.fovy = 45,
.projection = raylib.CAMERA_PERSPECTIVE,
};
@ -64,8 +64,17 @@ pub fn main() !void {
defer raylib.UnloadTexture(texture);
raylib.UnloadImage(tiles);
const shader = raylib.LoadShader("resources/shaders/tiling.vs", "resources/shaders/tiling.fs");
const shader = raylib.LoadChunkShader("resources/shaders/tiling.vs", "resources/shaders/tiling.fs");
defer raylib.UnloadShader(shader);
//std.debug.print("shader id: {}\n", .{shader.id});
//std.debug.print("shader attrib position loc: {}\n", .{raylib.GetShaderLocationAttrib(shader, "vertexPosition")});
//std.debug.print("shader attrib texcoord loc: {}\n", .{raylib.GetShaderLocationAttrib(shader, "vertexTexCoord")});
//std.debug.print("shader attrib normal loc: {}\n", .{raylib.GetShaderLocationAttrib(shader, "vertexNormal")});
//std.debug.print("shader attrib tiletexcoord loc: {}\n", .{raylib.GetShaderLocationAttrib(shader, "vertexTileTexCoord")});
//std.debug.print("shader attrib metadata1 loc: {}\n", .{raylib.GetShaderLocationAttrib(shader, "vertexMetadata1")});
//for (0..32) |i|{
// std.debug.print("shader loc {}: {}\n", .{i, shader.locs[i]});
//}
raylib.SetShaderValue(shader, raylib.GetShaderLocation(shader, "textureTiling"), &.{ @as(f32, @floatFromInt(tile_columns)), @as(f32, @floatFromInt(tile_rows)) }, raylib.SHADER_UNIFORM_VEC2);
var chunk = try chunks.Chunk.init(a7r);
@ -80,7 +89,7 @@ pub fn main() !void {
const xf: f32 = @floatFromInt(raw_x);
const yf: f32 = @floatFromInt(raw_y);
const zf: f32 = @floatFromInt(raw_z);
const height: f32 = (height_generator.noise2(xf, zf) + 1) * 16;
const height: f32 = (height_generator.noise2(xf, zf) + 1) * 16 + @as(f32, if(x > 24) 4.0 else 0.0) + @as(f32, if(z < 8) 4.0 else 0.0);
const tile_type: u32 = if (tile_type_generator.noise3(xf, yf, zf) > 0) 1 else 2;
if (height >= yf) chunk.setTile(x, y, z, tile_type);
};
@ -89,8 +98,8 @@ pub fn main() !void {
var tmp: u64 = 0;
for (0..500) |_| {
const start = try std.time.Instant.now();
const model = raylib.LoadModelFromMesh(try chunk.createMesh(tile_rows, tile_columns));
defer raylib.UnloadModel(model);
const model = raylib.LoadChunkModelFromMesh(try chunk.createMesh(tile_rows, tile_columns));
defer raylib.UnloadChunkModel(model);
const end = try std.time.Instant.now();
tmp += end.since(start);
}
@ -99,8 +108,8 @@ pub fn main() !void {
});
}
const model = raylib.LoadModelFromMesh(try chunk.createMesh(tile_rows, tile_columns));
defer raylib.UnloadModel(model);
const model = raylib.LoadChunkModelFromMesh(try chunk.createMesh(tile_rows, tile_columns));
defer raylib.UnloadChunkModel(model);
model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = texture;
model.materials[0].shader = shader;
@ -108,7 +117,7 @@ pub fn main() !void {
raylib.ClearBackground(raylib.BLACK);
const right = v3.neg(v3.nor(v3.cross(camera.up, v3.sub(camera.target, camera.position))));
const forward = v3.cross(right, v3.new(0, -1, 0));
const forward = v3.cross(right, v3.neg(camera.up));
const speed = @as(f32, if (raylib.IsKeyDown(raylib.KEY_LEFT_CONTROL)) 25 else 5) * raylib.GetFrameTime();
var movement = v3.new(0, 0, 0);
@ -124,8 +133,11 @@ pub fn main() !void {
moveCamera(&camera, v3.scl(v3.nor(movement), speed));
const delta = raylib.GetMouseDelta();
camera.target = v3.add(camera.position, v3.rotate(v3.sub(camera.target, camera.position), v3.new(0, 1, 0), -0.005 * delta.x));
camera.target = v3.add(camera.position, v3.rotate(v3.sub(camera.target, camera.position), right, -0.005 * delta.y));
// on the first mouse movement, for some reason mouse delta is completely insane, so we just ignore too large deltas
if(delta.x < 1000 and delta.y < 1000 and delta.x > -1000 and delta.y > -1000){
camera.target = v3.add(camera.position, v3.rotate(v3.sub(camera.target, camera.position), camera.up, -0.005 * delta.x));
camera.target = v3.add(camera.position, v3.rotate(v3.sub(camera.target, camera.position), right, -0.005 * delta.y));
}
raylib.BeginDrawing();
defer raylib.EndDrawing();
@ -138,7 +150,7 @@ pub fn main() !void {
raylib.BeginShaderMode(shader);
defer raylib.EndShaderMode();
raylib.DrawModel(model, model_position, 0.5, raylib.WHITE);
raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE);
}
raylib.DrawFPS(10, 10);

View file

@ -4,7 +4,6 @@ const raylib = raylib_helper.raylib;
const v3 = raylib_helper.v3;
const A7r = std.mem.Allocator;
const comptimePrint = std.fmt.comptimePrint;
const VERTICES_BLOCK_SIZE = 2 * 3 * 3;
const TEXCOORDS_BLOCK_SIZE = 2 * 2 * 3;
@ -43,7 +42,7 @@ const Metadata1 = packed struct {
comptime {
if (@bitSizeOf(Metadata1) != 128) {
@compileError(comptimePrint("Metadata 1 has wrong size. Expected 128 bits, found {}", .{@bitSizeOf(Metadata1)}));
@compileError(comptimePrint("Metadata 1 has wrong size. Expected 128 bytes, found {}", .{@bitSizeOf(Metadata1)}));
}
}
@ -91,7 +90,18 @@ pub const Chunk = struct {
}
// Create a raw quad with specified parameters and surface, accounting for dimension and sign. Surface is the block ID.
fn pack_raw_quad(x: f32, y_start: usize, y_end: usize, z_start: usize, z_end: usize, sign: comptime_int, d: comptime_int, surface: u32) RawQuad {
fn pack_raw_quad(
x: f32,
y_start: usize, y_end: usize,
z_start: usize, z_end: usize,
sign: comptime_int,
d: comptime_int,
surface: u32,
y_minus_obscuring_pattern: u32,
y_plus_obscuring_pattern: u32,
z_minus_obscuring_pattern: u32,
z_plus_obscuring_pattern: u32,
) RawQuad {
const ymin: f32 = @as(f32, @floatFromInt(y_start)) - 0.5;
const ymax: f32 = @as(f32, @floatFromInt(y_end)) - 0.5;
const zmin: f32 = @as(f32, @floatFromInt(z_start)) - 0.5;
@ -113,10 +123,10 @@ pub const Chunk = struct {
.width = zmax - zmin,
.height = ymax - ymin,
.top_obscuring_pattern = 0,
.left_obscuring_pattern = 0,
.right_obscuring_pattern = 0,
.bottom_obscuring_pattern = 0,
.top_obscuring_pattern = z_plus_obscuring_pattern,
.left_obscuring_pattern = z_minus_obscuring_pattern,
.right_obscuring_pattern = y_plus_obscuring_pattern,
.bottom_obscuring_pattern = y_minus_obscuring_pattern,
.top_left_obscured = false,
.top_right_obscured = false,
.bottom_right_obscured = false,
@ -155,10 +165,10 @@ pub const Chunk = struct {
.width = zmax - zmin,
.height = ymax - ymin,
.top_obscuring_pattern = 0xffffffff,
.left_obscuring_pattern = 0xffffffff,
.right_obscuring_pattern = 0xffffffff,
.bottom_obscuring_pattern = 0xffffffff,
.top_obscuring_pattern = 0,
.left_obscuring_pattern = 0,
.right_obscuring_pattern = 0,
.bottom_obscuring_pattern = 0,
.top_left_obscured = false,
.top_right_obscured = false,
.bottom_right_obscured = false,
@ -171,7 +181,7 @@ pub const Chunk = struct {
}
// Create mesh of a chunk. tile_rows and tile_columns are the dimensions of the tiles.png file, in terms of individual tile textures.
pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.Mesh {
pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.ChunkMesh {
var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096);
defer raw_quads.deinit();
@ -200,6 +210,7 @@ pub const Chunk = struct {
// The end coordinates of the quad. The quad is therefore covers rectangle from start coordinates (inclusive) to end coordinates (exclusive).
var y_end = y_start + 1;
var z_end = z_start + 1;
// todo: meshing can be optimized with SIMD stuff!!
// Greedy meshing: Extend the quad in the +y direction, until we hit a tile of a different type or the end of the chunk.
while (y_end <= 31 and tile_surfaces[y_end][z_start] == surface) : (y_end += 1) {
tile_surfaces[y_end][z_start] = 0;
@ -209,8 +220,41 @@ pub const Chunk = struct {
for (y_start..y_end) |y| if (tile_surfaces[y][z_end] != surface) break :zloop; // Stop extending if we hit a tile of incorrect type.
for (y_start..y_end) |y| tile_surfaces[y][z_end] = 0;
}
// todo: scan tiles around quad surface for ambient occlusion
const raw_quad = pack_raw_quad(@floatFromInt(raw_x), y_start, y_end, z_start, z_end, sign, d, surface);
// Scan the line of tiles adjacent to the quad for ambient occlusion
var z_minus_obscuring_pattern: u32 = 0;
if (x != (if (sign == 1) 31 else 0) and z_start != 0) {
for (y_start..y_end) |raw_y| {
const y: u5 = @intCast(raw_y);
z_minus_obscuring_pattern <<= 1;
if (chunk.getTileRawShifted(if (sign == 1) x+1 else x-1, y, @intCast(z_start - 1), d) != 0) z_minus_obscuring_pattern |= 1;
}
}
var z_plus_obscuring_pattern: u32 = 0;
if (x != (if (sign == 1) 31 else 0) and z_end != 32) {
for (y_start..y_end) |raw_y| {
const y: u5 = @intCast(raw_y);
z_plus_obscuring_pattern <<= 1;
if (chunk.getTileRawShifted(if (sign == 1) x+1 else x-1, y, @intCast(z_end), d) != 0) z_plus_obscuring_pattern |= 1;
}
}
var y_minus_obscuring_pattern: u32 = 0;
if (x != (if (sign == 1) 31 else 0) and y_start != 0) {
for (z_start..z_end) |raw_z| {
const z: u5 = @intCast(raw_z);
y_minus_obscuring_pattern <<= 1;
if (chunk.getTileRawShifted(if (sign == 1) x+1 else x-1, @intCast(y_start - 1), z, d) != 0) y_minus_obscuring_pattern |= 1;
}
}
var y_plus_obscuring_pattern: u32 = 0;
if (x != (if (sign == 1) 31 else 0) and y_end != 32) {
for (z_start..z_end) |raw_z| {
const z: u5 = @intCast(raw_z);
y_plus_obscuring_pattern <<= 1;
if (chunk.getTileRawShifted(if (sign == 1) x+1 else x-1, @intCast(y_end), z, d) != 0) y_plus_obscuring_pattern |= 1;
}
}
// std.debug.print("{}\n", .{z_minus_obscuring_pattern});
const raw_quad = pack_raw_quad(@floatFromInt(raw_x), y_start, y_end, z_start, z_end, sign, d, surface, y_minus_obscuring_pattern, y_plus_obscuring_pattern, z_minus_obscuring_pattern, z_plus_obscuring_pattern);
try raw_quads.append(raw_quad);
};
}
@ -224,7 +268,7 @@ pub const Chunk = struct {
const vertices: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 3)));
const texcoords: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2)));
const texcoords2: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2)));
const tiletexcoords: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2)));
const normals: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 3)));
const metadata1_packed: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 4)));
@ -249,8 +293,8 @@ pub const Chunk = struct {
const vertex_corners = .{ raw_quad.top_left, raw_quad.bottom_left, raw_quad.top_right, raw_quad.bottom_right, raw_quad.top_right, raw_quad.bottom_left };
const texcoords_x = .{ left_uv, left_uv, right_uv, right_uv, right_uv, left_uv };
const texcoords_y = .{ top_uv, bottom_uv } ** 3;
const texcoords2_x = .{ 0.0, 0.0, raw_quad.width, raw_quad.width, raw_quad.width, 0.0 };
const texcoords2_y = .{ 0.0, raw_quad.height } ** 3;
const tiletexcoords_x = .{ 0.0, 0.0, raw_quad.width, raw_quad.width, raw_quad.width, 0.0 };
const tiletexcoords_y = .{ 0.0, raw_quad.height } ** 3;
inline for (0..6) |corner_id| {
vertices[VERTICES_BLOCK_SIZE * i + corner_id * 3 + 0] = vertex_corners[corner_id].x;
@ -258,8 +302,8 @@ pub const Chunk = struct {
vertices[VERTICES_BLOCK_SIZE * i + corner_id * 3 + 2] = vertex_corners[corner_id].z;
texcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = texcoords_x[corner_id];
texcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = texcoords_y[corner_id];
texcoords2[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = texcoords2_x[corner_id];
texcoords2[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = texcoords2_y[corner_id];
tiletexcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = tiletexcoords_x[corner_id];
tiletexcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = tiletexcoords_y[corner_id];
}
// Store metadata into OpenGL buffers.
@ -296,21 +340,21 @@ pub const Chunk = struct {
}
// Create mesh using the buffers.
var mesh = raylib.Mesh{
var mesh = raylib.ChunkMesh{
.triangleCount = triangle_count,
.vertexCount = triangle_count * 3,
.vertices = vertices,
.texcoords = texcoords,
.texcoords2 = texcoords2,
.tiletexcoords = tiletexcoords,
.normals = normals,
.tangents = metadata1_packed,
.metadata1 = metadata1_packed,
.vaoId = 0,
.vboId = null,
};
raylib.UploadMesh(@ptrCast(&mesh), false);
raylib.UploadChunkMesh(@ptrCast(&mesh), false);
return mesh;
}