2222import java .nio .FloatBuffer ;
2323import java .nio .IntBuffer ;
2424import java .util .ArrayList ;
25- import java .util .Map ;
25+ import java .util .concurrent . ThreadLocalRandom ;
2626
2727import static org .lwjgl .opengl .GL15 .*;
2828import static org .lwjgl .opengl .GL30 .*;
@@ -117,6 +117,7 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
117117 FloatBuffer uvBuffer = ByteBuffer .allocateDirect (numQuads * 8 * Float .BYTES ).order (ByteOrder .nativeOrder ()).asFloatBuffer ();
118118 IntBuffer texLayerBuffer = ByteBuffer .allocateDirect (numQuads * 4 * Integer .BYTES ).order (ByteOrder .nativeOrder ()).asIntBuffer ();
119119 FloatBuffer aoBuffer = ByteBuffer .allocateDirect (numQuads * 4 * Float .BYTES ).order (ByteOrder .nativeOrder ()).asFloatBuffer ();
120+ IntBuffer lightBuffer = ByteBuffer .allocateDirect (numQuads * 4 * Integer .BYTES ).order (ByteOrder .nativeOrder ()).asIntBuffer ();
120121
121122 // Positions (vec3 per vertex)
122123 for (float [] v : chunkMesh .vertices ) {
@@ -135,7 +136,7 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
135136 uvBuffer .put (uv , 0 , 8 );
136137 }
137138
138- // Texture layer (same layer repeated for the quad’ s 4 vertices)
139+ // Texture layer (same layer repeated for the quad' s 4 vertices)
139140 for (int layer : chunkMesh .texOffset ) {
140141 texLayerBuffer .put (layer ).put (layer ).put (layer ).put (layer );
141142 }
@@ -145,12 +146,18 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
145146 aoBuffer .put (a , 0 , 4 );
146147 }
147148
149+ // Light Buffer (same layer repeated for the quad's 4 vertices)
150+ for (int light : chunkMesh .light ) {
151+ lightBuffer .put (light ).put (light ).put (light ).put (light );
152+ }
153+
148154 // Flip for OpenGL
149155 vertexBuffer .flip ();
150156 indexBuffer .flip ();
151157 uvBuffer .flip ();
152158 texLayerBuffer .flip ();
153159 aoBuffer .flip ();
160+ lightBuffer .flip ();
154161
155162 if (transparent ) {
156163 transVertexCount = indexBuffer .limit ();
@@ -198,6 +205,14 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
198205 glEnableVertexAttribArray (3 );
199206 glVertexAttribPointer (3 , 1 , GL_FLOAT , false , 0 , 0 );
200207
208+ // --- Ambient Occlusion (Attribute 4) ---
209+ int lightVBO = glGenBuffers ();
210+ glBindBuffer (GL_ARRAY_BUFFER , lightVBO );
211+ glBufferData (GL_ARRAY_BUFFER , lightBuffer , GL_STATIC_DRAW );
212+
213+ glEnableVertexAttribArray (4 );
214+ glVertexAttribPointer (4 , 1 , GL_FLOAT , false , 0 , 0 );
215+
201216 // --- Index Buffer ---
202217 int ibo = glGenBuffers ();
203218 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER , ibo );
@@ -267,19 +282,22 @@ private static class ChunkMesh {
267282 ArrayList <float []> uvs ;
268283 ArrayList <Integer > texOffset ;
269284 ArrayList <float []> aos ;
285+ ArrayList <Integer > light ;
270286
271287 public ChunkMesh (
272288 ArrayList <float []> vertices ,
273289 ArrayList <int []> indices ,
274290 ArrayList <float []> uvs ,
275291 ArrayList <Integer > texOffset ,
276- ArrayList <float []> aos
292+ ArrayList <float []> aos ,
293+ ArrayList <Integer > light
277294 ) {
278295 this .vertices = vertices ;
279296 this .indices = indices ;
280297 this .uvs = uvs ;
281298 this .texOffset = texOffset ;
282299 this .aos = aos ;
300+ this .light = light ;
283301 }
284302 }
285303
@@ -385,6 +403,10 @@ private int getAo(int[] currentPos, int[] step, int axis, boolean positive) {
385403 ((aoLevels [3 ] & 0b11) << 6 ); // BR
386404 }
387405
406+ private int getLightLevel (int currID , int [] pos , int [] step ) {
407+ return ThreadLocalRandom .current ().nextInt (0 , 16 + 1 );
408+ }
409+
388410 private int getMaskValue (int id , int [] pos , int [] step ) {
389411 Block block = Blocks .get (id );
390412 Block neighbor = BlockGame .getInstance ().getWorld ().getChunkBlock (
@@ -433,12 +455,14 @@ private int getTextureValue(int id, int axis, boolean positive) {
433455 private ChunkMesh generateMesh (int [] dims , int [] voxels ) {
434456 int [] mask = new int [0 ];
435457 int [] aoMask = new int [0 ];
458+ int [] lightMask = new int [0 ];
436459 int [] texMask = new int [0 ];
437460
438461 ArrayList <float []> vertices = new ArrayList <>();
439462 ArrayList <int []> indices = new ArrayList <>();
440463 ArrayList <float []> uvs = new ArrayList <>();
441464 ArrayList <Integer > textures = new ArrayList <>();
465+ ArrayList <Integer > light = new ArrayList <>();
442466 ArrayList <float []> aos = new ArrayList <>();
443467
444468 // Sweep across 3 dimensions: X, Y, Z (0, 1, 2)
@@ -453,6 +477,7 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
453477 if (mask .length < dims [u ] * dims [v ]) {
454478 mask = new int [dims [u ] * dims [v ]];
455479 aoMask = new int [dims [u ] * dims [v ]];
480+ lightMask = new int [dims [u ] * dims [v ]];
456481 texMask = new int [dims [u ] * dims [v ]];
457482 }
458483
@@ -473,11 +498,13 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
473498 if ((currID != 0 ) == (nextID != 0 )) {
474499 mask [n ] = 0 ;
475500 aoMask [n ] = 3 ;
501+ lightMask [n ] = 0 ;
476502 texMask [n ] = 0 ;
477503 } else {
478504 // Generate an AO for the block, the value will be a bitwise total unique to the AO pattern
479505 if (currID != 0 ) {
480506 mask [n ] = getMaskValue (currID , pos , step );
507+ lightMask [n ] = getLightLevel (currID , pos , step );
481508 aoMask [n ] = this .getAo (
482509 nextPos ,
483510 step ,
@@ -487,6 +514,7 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
487514 texMask [n ] = getTextureValue (currID , axis , true );
488515 } else {
489516 mask [n ] = -getMaskValue (nextID , pos , new int [] { 0 , 0 , 0 });
517+ lightMask [n ] = -getLightLevel (currID , pos , step );
490518 aoMask [n ] = -this .getAo (
491519 nextPos ,
492520 step ,
@@ -507,11 +535,18 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
507535 for (int i = 0 ; i < dims [u ]; ) {
508536 int blockId = mask [n ];
509537 int aoVal = aoMask [n ];
538+ int lightLevel = lightMask [n ];
510539 int texVal = texMask [n ];
511540 if (blockId != 0 ) {
512541 // Calculate quad width
513542 int width = 1 ;
514- while (i + width < dims [u ] && blockId == mask [n + width ] && aoVal == aoMask [n + width ] && texVal == texMask [n + width ]) {
543+ while (
544+ i + width < dims [u ] &&
545+ blockId == mask [n + width ] &&
546+ lightLevel == lightMask [n + width ] &&
547+ aoVal == aoMask [n + width ] &&
548+ texVal == texMask [n + width ]
549+ ) {
515550 ++width ;
516551 }
517552
@@ -520,7 +555,12 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
520555 boolean stop = false ;
521556 while (j + height < dims [v ]) {
522557 for (int k = 0 ; k < width ; ++k ) {
523- if (blockId != mask [n + k + height * dims [u ]] || aoVal != aoMask [n + k + height * dims [u ]] || texVal != texMask [n + k + height * dims [u ]]) {
558+ if (
559+ blockId != mask [n + k + height * dims [u ]] ||
560+ lightLevel == lightMask [n + k + height * dims [u ]] ||
561+ aoVal != aoMask [n + k + height * dims [u ]] ||
562+ texVal != texMask [n + k + height * dims [u ]]
563+ ) {
524564 stop = true ;
525565 break ;
526566 }
@@ -543,6 +583,7 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
543583 du [u ] = width ;
544584 dv [v ] = height ;
545585 } else {
586+ lightLevel = -lightLevel ;
546587 aoVal = -aoVal ;
547588 dv [u ] = width ;
548589 du [v ] = height ;
@@ -620,6 +661,9 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
620661 // UV
621662 uvs .add (uv );
622663
664+ // LightVal
665+ light .add (lightLevel );
666+
623667 // Tex Offset
624668 textures .add (texVal );
625669
@@ -644,6 +688,6 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
644688 }
645689 }
646690 }
647- return new ChunkMesh (vertices , indices , uvs , textures , aos );
691+ return new ChunkMesh (vertices , indices , uvs , textures , aos , light );
648692 }
649693}
0 commit comments