Add texture atlasing to block models
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
e8c38584fa
commit
96753152e6
13
assets/Data/game/blockTypes.json
Normal file
13
assets/Data/game/blockTypes.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"types" : [
|
||||
{
|
||||
"id" : 0,
|
||||
"name" : "air"
|
||||
},
|
||||
{
|
||||
"id" : 1,
|
||||
"name" : "brick",
|
||||
"texture" : "/Textures/Ground/Dirt2_256.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
289
assets/Shaders/entities/block/block.fs
Normal file
289
assets/Shaders/entities/block/block.fs
Normal file
@ -0,0 +1,289 @@
|
||||
#version 450 core
|
||||
|
||||
//texture defines
|
||||
#define ATLAS_ELEMENT_DIM 256.0
|
||||
#define ATLAS_DIM 8192.0
|
||||
#define ATLAS_EL_PER_ROW 32
|
||||
#define ATLAS_NORMALIZED_ELEMENT_WIDTH 0.031 //within the single texture within the atlas, we use this so we never go over the end of the texture
|
||||
#define ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL 0.03125 //used to properly shift from texture to texture in the atlas
|
||||
|
||||
|
||||
/**
|
||||
Bind points for different SSBOs
|
||||
*/
|
||||
#define CLUSTER_SSBO_BIND_POINT 1
|
||||
#define POINT_LIGHT_SSBO_BIND_POINT 2
|
||||
#define DIRECT_LIGHT_SSBO_BIND_POINT 3
|
||||
|
||||
|
||||
/**
|
||||
Maximum number of point lights
|
||||
*/
|
||||
#define MAX_POINT_LIGHTS 512
|
||||
|
||||
/**
|
||||
Maximum number of lights per cluster
|
||||
*/
|
||||
#define MAX_LIGHTS_PER_CLUSTER 100
|
||||
|
||||
/**
|
||||
The direct global light
|
||||
*/
|
||||
struct DirectLight {
|
||||
vec3 direction;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
/**
|
||||
A point light
|
||||
*/
|
||||
struct PointLight {
|
||||
vec4 position;
|
||||
vec4 color;
|
||||
float constant;
|
||||
float linear;
|
||||
float quadratic;
|
||||
float radius;
|
||||
};
|
||||
|
||||
/**
|
||||
A light cluster
|
||||
*/
|
||||
struct Cluster {
|
||||
vec4 minPoint;
|
||||
vec4 maxPoint;
|
||||
uint count;
|
||||
uint lightIndices[MAX_LIGHTS_PER_CLUSTER];
|
||||
};
|
||||
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO {
|
||||
Cluster clusters[];
|
||||
};
|
||||
|
||||
layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO {
|
||||
PointLight pointLight[];
|
||||
};
|
||||
|
||||
layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO {
|
||||
DirectLight directLight;
|
||||
};
|
||||
|
||||
struct Material {
|
||||
sampler2D diffuse;
|
||||
sampler2D specular;
|
||||
float shininess;
|
||||
};
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec3 ViewFragPos;
|
||||
in vec3 Normal;
|
||||
in vec2 uv;
|
||||
in vec4 FragPosLightSpace;
|
||||
in flat int samplerIndexVec; //the indices in the atlas of textures to sample
|
||||
|
||||
|
||||
uniform vec3 viewPos;
|
||||
// uniform DirLight dirLight;
|
||||
// uniform PointLight pointLights[NR_POINT_LIGHTS];
|
||||
// uniform SpotLight spotLight;
|
||||
uniform Material material;
|
||||
|
||||
//texture stuff
|
||||
// uniform sampler2D ourTexture;
|
||||
uniform int hasTransparency;
|
||||
// uniform sampler2D specularTexture;
|
||||
|
||||
//light depth map
|
||||
uniform sampler2D shadowMap;
|
||||
|
||||
/**
|
||||
Used for light cluster calculation
|
||||
*/
|
||||
uniform float zNear;
|
||||
uniform float zFar;
|
||||
uniform uvec3 gridSize;
|
||||
uniform uvec2 screenDimensions;
|
||||
uniform mat4 view;
|
||||
|
||||
|
||||
// function prototypes
|
||||
uint findCluster(vec3 FragPos, float zNear, float zFar);
|
||||
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||
float calcLightIntensityTotal(vec3 normal);
|
||||
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
|
||||
vec3 getColor(vec2 uv, vec3 normal, int samplerIndexVec, Material material);
|
||||
|
||||
void main(){
|
||||
vec3 norm = normalize(Normal);
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
|
||||
//grab light intensity
|
||||
vec3 lightIntensity = vec3(calcLightIntensityTotal(norm));
|
||||
|
||||
//get color of base texture
|
||||
vec3 textureColor = getColor(uv, norm, samplerIndexVec, material);
|
||||
|
||||
//shadow
|
||||
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), -norm);
|
||||
|
||||
//
|
||||
//point light calculations
|
||||
uint clusterIndex = findCluster(ViewFragPos, zNear, zFar);
|
||||
uint pointLightCount = clusters[clusterIndex].count;
|
||||
for(int i = 0; i < pointLightCount; i++){
|
||||
uint pointLightIndex = clusters[clusterIndex].lightIndices[i];
|
||||
PointLight pointLight = pointLight[pointLightIndex];
|
||||
lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir);
|
||||
}
|
||||
//error checking on light clusters
|
||||
if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){
|
||||
FragColor = vec4(1.0f,0.0f,0.0f,1);
|
||||
return;
|
||||
}
|
||||
|
||||
//calculate final color
|
||||
vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4);
|
||||
|
||||
//this final calculation is for transparency
|
||||
FragColor = vec4(finalColor, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The function that gets the texture color based on the triplanar texture mapping and the voxel type at each point along the vert.
|
||||
* See the triplanar mapping wiki article for an explanation of math involved.
|
||||
*/
|
||||
vec3 getColor(vec2 uv, vec3 normal, int samplerIndexVec, Material material){
|
||||
|
||||
//the uv of the texture clamped within the atlas
|
||||
vec2 actualUv = vec2(
|
||||
(fract(uv.x) * ATLAS_NORMALIZED_ELEMENT_WIDTH) + (mod(samplerIndexVec,ATLAS_EL_PER_ROW) * ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL),
|
||||
(fract(uv.y) * ATLAS_NORMALIZED_ELEMENT_WIDTH) + (round(samplerIndexVec / ATLAS_EL_PER_ROW) * ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL)
|
||||
);
|
||||
//albedo for the X texture
|
||||
vec3 color = texture(material.diffuse, actualUv).rgb;
|
||||
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//
|
||||
float calcLightIntensityAmbient(){
|
||||
//calculate average of ambient light
|
||||
float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0;
|
||||
return avg;
|
||||
}
|
||||
|
||||
//
|
||||
float calcLightIntensityDir(vec3 normal){
|
||||
vec3 lightDir = normalize(-directLight.direction);
|
||||
// diffuse shading
|
||||
float diff = max(dot(normal, lightDir), 0.0);
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
//
|
||||
float calcLightIntensityTotal(vec3 normal){
|
||||
//ambient intensity
|
||||
float ambientLightIntensity = calcLightIntensityAmbient();
|
||||
|
||||
//get direct intensity
|
||||
float directLightIntensity = calcLightIntensityDir(normal);
|
||||
|
||||
//sum
|
||||
float total = ambientLightIntensity + directLightIntensity;
|
||||
return total;
|
||||
}
|
||||
|
||||
//
|
||||
vec3 getTotalLightColor(vec3 normal){
|
||||
//get the direct light color adjusted for intensity
|
||||
vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal);
|
||||
|
||||
//sum light colors
|
||||
vec3 totalLightColor = diffuseLightColor;
|
||||
return totalLightColor;
|
||||
}
|
||||
|
||||
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){
|
||||
vec3 lightDir = normalize(pointLight.position.xyz - fragPos);
|
||||
// diffuse shading
|
||||
float diff = max(dot(normal, lightDir), 0.0);
|
||||
// specular shading
|
||||
// vec3 reflectDir = reflect(-lightDir, normal);
|
||||
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||
// attenuation
|
||||
float distance = length(pointLight.position.xyz - fragPos);
|
||||
float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance));
|
||||
if(distance > pointLight.radius){
|
||||
attenuation = 0;
|
||||
}
|
||||
// combine results
|
||||
vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz;
|
||||
vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
|
||||
// vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
|
||||
ambient = ambient * attenuation;
|
||||
diffuse = diffuse * attenuation;
|
||||
// specular *= attenuation;
|
||||
vec3 specular = vec3(0,0,0);
|
||||
|
||||
vec3 finalValue = vec3(0);
|
||||
if(distance < pointLight.radius){
|
||||
finalValue = (ambient + diffuse + specular);
|
||||
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
|
||||
}
|
||||
|
||||
return finalValue;
|
||||
}
|
||||
|
||||
/**
|
||||
Finds the light cluster this fragment belongs to
|
||||
*/
|
||||
uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){
|
||||
uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear));
|
||||
vec2 tileSize = screenDimensions / gridSize.xy;
|
||||
uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile);
|
||||
return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y);
|
||||
}
|
||||
|
||||
|
||||
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){
|
||||
|
||||
// perform perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
|
||||
//transform to NDC
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
//get closest depth from light's POV
|
||||
float closestDepth = texture(shadowMap, projCoords.xy).r;
|
||||
|
||||
//get depth of current fragment
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
//calculate bias
|
||||
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||
|
||||
//calculate shadow value
|
||||
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
|
||||
|
||||
if(projCoords.z > 1.0){
|
||||
shadow = 0.0;
|
||||
}
|
||||
|
||||
//calculate dot product, if it is >0 we know they're parallel-ish therefore should disregard the shadow mapping
|
||||
//ie the fragment is already facing away from the light source
|
||||
float dotprod = dot(normalize(lightDir),normalize(normal));
|
||||
|
||||
if(dotprod > 0.0){
|
||||
shadow = 0.0;
|
||||
}
|
||||
|
||||
// shadow = currentDepth;
|
||||
|
||||
return clamp(1.0 - shadow, 0.0, 0.7);
|
||||
}
|
||||
58
assets/Shaders/entities/block/block.vs
Normal file
58
assets/Shaders/entities/block/block.vs
Normal file
@ -0,0 +1,58 @@
|
||||
//Vertex Shader
|
||||
#version 330 core
|
||||
|
||||
//defines
|
||||
#define TEXTURE_MAP_SCALE 1.0
|
||||
#define MODEL_TOTAL_DIM 16.0
|
||||
|
||||
|
||||
//input buffers
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 4) in vec2 aTex;
|
||||
layout (location = 5) in int samplerIndices;
|
||||
|
||||
|
||||
//coordinate space transformation matrices
|
||||
uniform mat4 transform;
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
uniform mat4 lightSpaceMatrix;
|
||||
|
||||
|
||||
|
||||
//output buffers
|
||||
out vec3 Normal;
|
||||
out vec3 FragPos;
|
||||
out vec3 ViewFragPos;
|
||||
out vec2 uv;
|
||||
out vec4 FragPosLightSpace;
|
||||
flat out int samplerIndexVec;
|
||||
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
//normalize posiiton and normal
|
||||
vec4 FinalVertex = vec4(aPos, 1.0);
|
||||
vec4 FinalNormal = vec4(aNormal, 1.0);
|
||||
|
||||
|
||||
//push frag, normal, and texture positions to fragment shader
|
||||
FragPos = vec3(model * FinalVertex);
|
||||
ViewFragPos = vec3(view * model * FinalVertex);
|
||||
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||
uv = aTex;
|
||||
|
||||
//pass through what atlas'd textures to sample
|
||||
samplerIndexVec = samplerIndices;
|
||||
|
||||
|
||||
//shadow map stuff
|
||||
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
|
||||
|
||||
//set final position with opengl space
|
||||
gl_Position = projection * view * model * FinalVertex;
|
||||
}
|
||||
@ -1,3 +1,3 @@
|
||||
#maven.buildNumber.plugin properties file
|
||||
#Sat Nov 23 20:49:19 EST 2024
|
||||
buildNumber=403
|
||||
#Sun Nov 24 15:46:03 EST 2024
|
||||
buildNumber=404
|
||||
|
||||
@ -1154,6 +1154,7 @@ Convert PhysicsEntityUtils to use generic interface to load tri geom rigid bodie
|
||||
|
||||
(11/24/2024)
|
||||
Fix winding order on block meshes
|
||||
Add texture atlasing to blocks
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@ -299,6 +299,7 @@ public class Globals {
|
||||
|
||||
public static VisualShader defaultMeshShader;
|
||||
public static VisualShader terrainShaderProgram;
|
||||
public static VisualShader blockShader;
|
||||
|
||||
//
|
||||
// Particle stuff
|
||||
@ -365,7 +366,7 @@ public class Globals {
|
||||
public static ClientDrawCellManager clientDrawCellManager;
|
||||
public static VoxelTextureAtlas voxelTextureAtlas = new VoxelTextureAtlas();
|
||||
public static ClientBlockCellManager clientBlockCellManager;
|
||||
public static BlockTextureAtlas blockTextureAtlas = null;
|
||||
public static BlockTextureAtlas blockTextureAtlas = new BlockTextureAtlas();
|
||||
|
||||
//fluid cell manager
|
||||
public static FluidCellManager fluidCellManager;
|
||||
@ -649,6 +650,7 @@ public class Globals {
|
||||
defaultMeshShader = VisualShader.smart_assemble_shader(false,true);
|
||||
//init terrain shader program
|
||||
terrainShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/terrain2/terrain2.vs", "/Shaders/entities/terrain2/terrain2.fs");
|
||||
blockShader = VisualShader.loadSpecificShader("/Shaders/entities/block/block.vs", "/Shaders/entities/block/block.fs");
|
||||
//init fluid shader program
|
||||
FluidChunkModelGeneration.fluidChunkShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/fluid2/fluid2.vs", "/Shaders/entities/fluid2/fluid2.fs");
|
||||
//init models
|
||||
|
||||
@ -9,10 +9,13 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import electrosphere.client.block.cells.BlockTextureAtlas;
|
||||
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||
import electrosphere.engine.assetmanager.queue.QueuedTexture;
|
||||
import electrosphere.game.data.block.BlockData;
|
||||
import electrosphere.game.data.block.BlockType;
|
||||
import electrosphere.game.data.voxel.VoxelData;
|
||||
import electrosphere.game.data.voxel.VoxelType;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
@ -37,14 +40,15 @@ public class InitialAssetLoading {
|
||||
*/
|
||||
protected static void loadData(){
|
||||
|
||||
loadVoxelTextureAtlas();
|
||||
loadParticleAtlas();
|
||||
InitialAssetLoading.loadVoxelTextureAtlas();
|
||||
InitialAssetLoading.loadBlockTextureAtlas();
|
||||
InitialAssetLoading.loadParticleAtlas();
|
||||
LoggerInterface.loggerEngine.INFO("Finished loading texture atlas");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the texture atlas
|
||||
* Loads the voxel texture atlas
|
||||
*/
|
||||
private static void loadVoxelTextureAtlas(){
|
||||
//terrain texture atlas
|
||||
@ -95,7 +99,58 @@ public class InitialAssetLoading {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the texture atlas
|
||||
* Loads the block texture atlas
|
||||
*/
|
||||
private static void loadBlockTextureAtlas(){
|
||||
//terrain texture atlas
|
||||
Globals.profiler.beginCpuSample("createBlockTextureAtlas");
|
||||
BlockData data = Globals.gameConfigCurrent.getBlockData();
|
||||
int iterator = 0;
|
||||
BufferedImage image = new BufferedImage(BlockTextureAtlas.ATLAS_DIM, BlockTextureAtlas.ATLAS_DIM, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
Graphics graphics = image.getGraphics();
|
||||
for(BlockType type : data.getTypes()){
|
||||
if(type.getTexture() != null){
|
||||
int offX = iterator % BlockTextureAtlas.ELEMENTS_PER_ROW;
|
||||
int offY = iterator / BlockTextureAtlas.ELEMENTS_PER_ROW;
|
||||
try {
|
||||
BufferedImage newType = ImageIO.read(FileUtils.getAssetFile(type.getTexture()));
|
||||
int drawX = BlockTextureAtlas.ATLAS_ELEMENT_DIM * offX;
|
||||
int drawY = BlockTextureAtlas.ATLAS_DIM - BlockTextureAtlas.ATLAS_ELEMENT_DIM - BlockTextureAtlas.ATLAS_ELEMENT_DIM * offY;
|
||||
graphics.drawImage(newType, drawX, drawY, null);
|
||||
} catch (IOException e) {
|
||||
LoggerInterface.loggerRenderer.ERROR("Texture atlas failed to find texture " + type.getTexture(), e);
|
||||
}
|
||||
//put coords in map
|
||||
Globals.blockTextureAtlas.putTypeCoord(type.getId(),iterator);
|
||||
|
||||
//iterate
|
||||
iterator++;
|
||||
}
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
|
||||
//queue to asset manager
|
||||
atlasQueuedTexture = new QueuedTexture(image);
|
||||
Globals.assetManager.queuedAsset(atlasQueuedTexture);
|
||||
|
||||
|
||||
//wait the texture to be loaded
|
||||
while(!atlasQueuedTexture.hasLoaded()){
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
LoggerInterface.loggerEngine.ERROR("failed to sleep", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//construct texture atlas from buffered image
|
||||
Globals.blockTextureAtlas.setSpecular(atlasQueuedTexture.getTexture());
|
||||
Globals.blockTextureAtlas.setNormal(atlasQueuedTexture.getTexture());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the particle texture atlas
|
||||
*/
|
||||
private static void loadParticleAtlas(){
|
||||
//terrain texture atlas
|
||||
|
||||
@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import electrosphere.game.data.audio.SurfaceAudioCollection;
|
||||
import electrosphere.game.data.biome.BiomeTypeMap;
|
||||
import electrosphere.game.data.block.BlockData;
|
||||
import electrosphere.game.data.common.CommonEntityLoader;
|
||||
import electrosphere.game.data.common.CommonEntityMap;
|
||||
import electrosphere.game.data.common.CommonEntityType;
|
||||
@ -45,6 +46,11 @@ public class Config {
|
||||
//data about every voxel type
|
||||
VoxelData voxelData;
|
||||
|
||||
/**
|
||||
* The block data
|
||||
*/
|
||||
BlockData blockData;
|
||||
|
||||
//the hints that are defined
|
||||
HintDefinition hintData;
|
||||
|
||||
@ -86,6 +92,7 @@ public class Config {
|
||||
config.symbolMap = FileUtils.loadObjectFromAssetPath("Data/game/symbolism.json", SymbolMap.class);
|
||||
config.raceMap = FileUtils.loadObjectFromAssetPath("Data/game/races.json", RaceMap.class);
|
||||
config.voxelData = FileUtils.loadObjectFromAssetPath("Data/game/voxelTypes.json", VoxelData.class);
|
||||
config.blockData = FileUtils.loadObjectFromAssetPath("Data/game/blockTypes.json", BlockData.class);
|
||||
config.projectileTypeHolder = FileUtils.loadObjectFromAssetPath("Data/entity/projectile.json", ProjectileTypeHolder.class);
|
||||
config.hintData = FileUtils.loadObjectFromAssetPath("Data/tutorial/hints.json", HintDefinition.class);
|
||||
config.surfaceAudioCollection = FileUtils.loadObjectFromAssetPath("Data/audio/surface.json", SurfaceAudioCollection.class);
|
||||
@ -250,6 +257,14 @@ public class Config {
|
||||
return voxelData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block data
|
||||
* @return The block data
|
||||
*/
|
||||
public BlockData getBlockData(){
|
||||
return blockData;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tutorial hints data
|
||||
* @return The hints
|
||||
|
||||
47
src/main/java/electrosphere/game/data/block/BlockData.java
Normal file
47
src/main/java/electrosphere/game/data/block/BlockData.java
Normal file
@ -0,0 +1,47 @@
|
||||
package electrosphere.game.data.block;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A list of all block types in game
|
||||
*/
|
||||
public class BlockData {
|
||||
//The set of all voxel types
|
||||
Set<BlockType> types;
|
||||
|
||||
/**
|
||||
* Gets all block types
|
||||
* @return The set of all block types
|
||||
*/
|
||||
public Set<BlockType> getTypes(){
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block type by its name, or null if that type does not exist
|
||||
* @param name The name of the block type
|
||||
* @return The block type or null
|
||||
*/
|
||||
public BlockType getTypeFromName(String name){
|
||||
for(BlockType type : types){
|
||||
if(type.name.contains(name)){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block type by its id, or null if that type does not exist
|
||||
* @param id The id of the block type
|
||||
* @return The block type or null
|
||||
*/
|
||||
public BlockType getTypeFromId(int id){
|
||||
for(BlockType type : types){
|
||||
if(type.id == id){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
37
src/main/java/electrosphere/game/data/block/BlockType.java
Normal file
37
src/main/java/electrosphere/game/data/block/BlockType.java
Normal file
@ -0,0 +1,37 @@
|
||||
package electrosphere.game.data.block;
|
||||
|
||||
/**
|
||||
* Data about a particular type of block
|
||||
*/
|
||||
public class BlockType {
|
||||
//the id of this block type
|
||||
int id;
|
||||
//the name of the type
|
||||
String name;
|
||||
//the texture for the block type
|
||||
String texture;
|
||||
|
||||
/**
|
||||
* Gets the id of the block type
|
||||
* @return The id
|
||||
*/
|
||||
public int getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the block type
|
||||
* @return The name
|
||||
*/
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the texture of this block types
|
||||
* @return the texture
|
||||
*/
|
||||
public String getTexture(){
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@ import org.lwjgl.opengl.GL40;
|
||||
import electrosphere.client.block.BlockChunkData;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.state.collidable.TriGeomData;
|
||||
import electrosphere.renderer.model.Material;
|
||||
import electrosphere.renderer.model.Mesh;
|
||||
import electrosphere.renderer.model.Model;
|
||||
|
||||
@ -51,6 +52,16 @@ public class BlockMeshgen {
|
||||
4, 5, 7
|
||||
};
|
||||
|
||||
/**
|
||||
* Position of the sampler data in the buffer
|
||||
*/
|
||||
static final int SAMPLER_SHADER_POSITION = 5;
|
||||
|
||||
/**
|
||||
* The size of the sampler data per-vertex
|
||||
*/
|
||||
static final int SAMPLER_DATA_SIZE = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the quad meshes for the provided chunk data
|
||||
@ -88,6 +99,7 @@ public class BlockMeshgen {
|
||||
currentQuad.z = z;
|
||||
currentQuad.w = 1;
|
||||
currentQuad.h = 1;
|
||||
currentQuad.type = chunkData.getType(x, y, z);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -103,10 +115,12 @@ public class BlockMeshgen {
|
||||
* @param normals The list of normals to store into
|
||||
* @param uvs The list of uvs to store into
|
||||
* @param indices The list of indices to store into
|
||||
* @param samplers The sampler for a given vertex
|
||||
* @param quad The quad
|
||||
* @param depth The depth of the box
|
||||
* @param blockType The type of block
|
||||
*/
|
||||
protected static void meshifyBox(List<Vector3f> verts, List<Vector3f> normals, List<Vector2f> uvs, List<Integer> indices, QuadMesh quad, int depth){
|
||||
protected static void meshifyBox(List<Vector3f> verts, List<Vector3f> normals, List<Vector2f> uvs, List<Integer> indices, List<Integer> samplers, QuadMesh quad, int depth, int blockType){
|
||||
//
|
||||
//face 1
|
||||
//
|
||||
@ -291,6 +305,7 @@ public class BlockMeshgen {
|
||||
List<Vector3f> normals = new LinkedList<Vector3f>();
|
||||
List<Vector2f> uvs = new LinkedList<Vector2f>();
|
||||
List<Integer> indices = new LinkedList<Integer>();
|
||||
List<Integer> samplers = new LinkedList<Integer>(); //the texture to sample for this quad
|
||||
|
||||
//sort
|
||||
Collections.sort(quadMeshes);
|
||||
@ -307,7 +322,7 @@ public class BlockMeshgen {
|
||||
if(quad1.x == quad2.x && quad1.y == quad2.y && quad1.w == quad2.w && quad1.h == quad2.h && quad1.z + zEnd == quad2.z){
|
||||
zEnd++;
|
||||
} else {
|
||||
BlockMeshgen.meshifyBox(verts,normals,uvs,indices,quad1,zEnd);
|
||||
BlockMeshgen.meshifyBox(verts,normals,uvs,indices,samplers,quad1,zEnd,quad1.type);
|
||||
quad1 = quad2;
|
||||
zEnd = 1;
|
||||
break;
|
||||
@ -316,7 +331,7 @@ public class BlockMeshgen {
|
||||
i = i + zEnd;
|
||||
}
|
||||
if(quad1 != null){
|
||||
BlockMeshgen.meshifyBox(verts,normals,uvs,indices,quad1,zEnd);
|
||||
BlockMeshgen.meshifyBox(verts,normals,uvs,indices,samplers,quad1,zEnd,quad1.type);
|
||||
}
|
||||
|
||||
//
|
||||
@ -363,6 +378,14 @@ public class BlockMeshgen {
|
||||
rVal.uvBuffer = BufferUtils.createFloatBuffer(rVal.uvs.length);
|
||||
rVal.uvBuffer.put(rVal.uvs);
|
||||
|
||||
//samplers
|
||||
rVal.samplers = new int[samplers.size()];
|
||||
for(int i = 0; i < samplers.size(); i++){
|
||||
rVal.samplers[i] = samplers.get(i);
|
||||
}
|
||||
rVal.samplerBuffer = BufferUtils.createIntBuffer(rVal.samplers.length);
|
||||
rVal.samplerBuffer.put(rVal.samplers);
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@ -387,6 +410,7 @@ public class BlockMeshgen {
|
||||
FloatBuffer normalArrayBufferData = meshData.normalBuffer;
|
||||
FloatBuffer textureArrayBufferData = meshData.uvBuffer;
|
||||
IntBuffer elementArrayBufferData = meshData.faceBuffer;
|
||||
IntBuffer samplerArrayBufferData = meshData.samplerBuffer;
|
||||
|
||||
|
||||
|
||||
@ -416,6 +440,11 @@ public class BlockMeshgen {
|
||||
elementArrayBufferData.flip();
|
||||
mesh.bufferFaces(elementArrayBufferData, elementCount);
|
||||
}
|
||||
//buffer sampler indices
|
||||
if(samplerArrayBufferData != null && samplerArrayBufferData.position() > 0){
|
||||
samplerArrayBufferData.flip();
|
||||
mesh.bufferCustomIntAttribArray(samplerArrayBufferData, SAMPLER_DATA_SIZE, SAMPLER_SHADER_POSITION);
|
||||
}
|
||||
} catch (NullPointerException ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@ -448,13 +477,13 @@ public class BlockMeshgen {
|
||||
Mesh m = BlockMeshgen.generateBlockMesh(meshData);
|
||||
|
||||
//construct the material for the chunk
|
||||
// Material groundMat = new Material();
|
||||
// groundMat.setTexturePointer(Globals.defaultMeshShader);
|
||||
// groundMat.setNormalTexturePointer(atlas.getNormal().getTexturePointer());
|
||||
// m.setMaterial(groundMat);
|
||||
Material groundMat = new Material();
|
||||
groundMat.setTexturePointer(Globals.blockTextureAtlas.getSpecular().getTexturePointer());
|
||||
groundMat.setNormalTexturePointer(Globals.blockTextureAtlas.getNormal().getTexturePointer());
|
||||
m.setMaterial(groundMat);
|
||||
|
||||
//shader logic
|
||||
m.setShader(Globals.defaultMeshShader);
|
||||
m.setShader(Globals.blockShader);
|
||||
m.setParent(rVal);
|
||||
|
||||
rVal.getMeshes().add(m);
|
||||
@ -476,11 +505,14 @@ public class BlockMeshgen {
|
||||
int[] faceElements;
|
||||
//UVs
|
||||
float[] uvs;
|
||||
//The samplers for each quad
|
||||
int[] samplers;
|
||||
|
||||
FloatBuffer vertBuffer;
|
||||
FloatBuffer normalBuffer;
|
||||
IntBuffer faceBuffer;
|
||||
FloatBuffer uvBuffer;
|
||||
IntBuffer samplerBuffer;
|
||||
|
||||
@Override
|
||||
public float[] getVertices() {
|
||||
@ -501,13 +533,15 @@ public class BlockMeshgen {
|
||||
int z;
|
||||
int w;
|
||||
int h;
|
||||
int type;
|
||||
public QuadMesh(){}
|
||||
public QuadMesh(int x, int y, int z, int w, int h){
|
||||
public QuadMesh(int x, int y, int z, int w, int h, int type){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -28,7 +28,7 @@ public class BlockMeshgenTests {
|
||||
|
||||
//expected data
|
||||
QuadMesh[] expectedData = new QuadMesh[]{
|
||||
new QuadMesh(0,0,0,1,1),
|
||||
new QuadMesh(0,0,0,1,1,1),
|
||||
};
|
||||
|
||||
//setup data
|
||||
@ -65,7 +65,7 @@ public class BlockMeshgenTests {
|
||||
public void test_fillQuadMeshes_2(){
|
||||
//expected data
|
||||
QuadMesh[] expectedData = new QuadMesh[]{
|
||||
new QuadMesh(0,0,0,1,2),
|
||||
new QuadMesh(0,0,0,1,2,1),
|
||||
};
|
||||
|
||||
//setup data
|
||||
@ -103,7 +103,7 @@ public class BlockMeshgenTests {
|
||||
public void test_fillQuadMeshes_3(){
|
||||
//expected data
|
||||
QuadMesh[] expectedData = new QuadMesh[]{
|
||||
new QuadMesh(0,0,0,2,2),
|
||||
new QuadMesh(0,0,0,2,2,1),
|
||||
};
|
||||
|
||||
//setup data
|
||||
@ -143,8 +143,8 @@ public class BlockMeshgenTests {
|
||||
public void test_fillQuadMeshes_4(){
|
||||
//expected data
|
||||
QuadMesh[] expectedData = new QuadMesh[]{
|
||||
new QuadMesh(0,0,0,1,1),
|
||||
new QuadMesh(0,2,0,1,1),
|
||||
new QuadMesh(0,0,0,1,1,1),
|
||||
new QuadMesh(0,2,0,1,1,1),
|
||||
};
|
||||
|
||||
//setup data
|
||||
@ -236,10 +236,11 @@ public class BlockMeshgenTests {
|
||||
List<Vector3f> normals = new LinkedList<Vector3f>();
|
||||
List<Vector2f> uvs = new LinkedList<Vector2f>();
|
||||
List<Integer> indices = new LinkedList<Integer>();
|
||||
QuadMesh quad = new QuadMesh(0, 0, 0, 1, 1);
|
||||
List<Integer> samplers = new LinkedList<Integer>();
|
||||
QuadMesh quad = new QuadMesh(0, 0, 0, 1, 1,1);
|
||||
|
||||
//call
|
||||
BlockMeshgen.meshifyBox(verts, normals, uvs, indices, quad, 1);
|
||||
BlockMeshgen.meshifyBox(verts, normals, uvs, indices, samplers, quad, 1, 1);
|
||||
|
||||
|
||||
//error check result
|
||||
@ -296,10 +297,11 @@ public class BlockMeshgenTests {
|
||||
List<Vector3f> normals = new LinkedList<Vector3f>();
|
||||
List<Vector2f> uvs = new LinkedList<Vector2f>();
|
||||
List<Integer> indices = new LinkedList<Integer>();
|
||||
QuadMesh quad = new QuadMesh(0, 0, 0, 1, 1);
|
||||
List<Integer> samplers = new LinkedList<Integer>();
|
||||
QuadMesh quad = new QuadMesh(0, 0, 0, 1, 1, 1);
|
||||
|
||||
//call
|
||||
BlockMeshgen.meshifyBox(verts, normals, uvs, indices, quad, 1);
|
||||
BlockMeshgen.meshifyBox(verts, normals, uvs, indices, samplers, quad, 1, 1);
|
||||
|
||||
|
||||
//error check result
|
||||
@ -354,10 +356,11 @@ public class BlockMeshgenTests {
|
||||
List<Vector3f> normals = new LinkedList<Vector3f>();
|
||||
List<Vector2f> uvs = new LinkedList<Vector2f>();
|
||||
List<Integer> indices = new LinkedList<Integer>();
|
||||
QuadMesh quad = new QuadMesh(0, 0, 0, 1, 1);
|
||||
List<Integer> samplers = new LinkedList<Integer>();
|
||||
QuadMesh quad = new QuadMesh(0, 0, 0, 1, 1, 1);
|
||||
|
||||
//call
|
||||
BlockMeshgen.meshifyBox(verts, normals, uvs, indices, quad, 1);
|
||||
BlockMeshgen.meshifyBox(verts, normals, uvs, indices, samplers, quad, 1, 1);
|
||||
|
||||
|
||||
//error check result
|
||||
|
||||
Loading…
Reference in New Issue
Block a user