legacy code reorg
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
92bdb54108
commit
21fb8b0e3a
@ -2053,6 +2053,7 @@ Scaffolding towns and character jobs data
|
|||||||
Properly async-ify inventory/item related tests
|
Properly async-ify inventory/item related tests
|
||||||
Fix viewport interaction with lod emitter service
|
Fix viewport interaction with lod emitter service
|
||||||
Fix most tests
|
Fix most tests
|
||||||
|
Rendering engine legacy code reorganization
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import electrosphere.data.entity.graphics.NonproceduralModel;
|
|||||||
import electrosphere.data.voxel.VoxelType;
|
import electrosphere.data.voxel.VoxelType;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
import electrosphere.renderer.RenderUtils;
|
import electrosphere.renderer.meshgen.GeometryModelGen;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data on a given item
|
* Data on a given item
|
||||||
@ -177,7 +177,7 @@ public class Item extends CommonEntityType {
|
|||||||
Map<String,Map<String,Object>> meshUniformMap = new HashMap<String,Map<String,Object>>();
|
Map<String,Map<String,Object>> meshUniformMap = new HashMap<String,Map<String,Object>>();
|
||||||
Map<String,Object> uniforms = new HashMap<String,Object>();
|
Map<String,Object> uniforms = new HashMap<String,Object>();
|
||||||
uniforms.put("blockAtlasIndex",Globals.blockTextureAtlas.getVoxelTypeOffset(blockType.getId()));
|
uniforms.put("blockAtlasIndex",Globals.blockTextureAtlas.getVoxelTypeOffset(blockType.getId()));
|
||||||
meshUniformMap.put(RenderUtils.MESH_NAME_BLOCK_SINGLE,uniforms);
|
meshUniformMap.put(GeometryModelGen.MESH_NAME_BLOCK_SINGLE,uniforms);
|
||||||
modelData.setUniforms(meshUniformMap);
|
modelData.setUniforms(meshUniformMap);
|
||||||
|
|
||||||
//set item class
|
//set item class
|
||||||
|
|||||||
@ -20,11 +20,12 @@ import electrosphere.engine.profiler.Profiler;
|
|||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.net.config.NetConfig;
|
import electrosphere.net.config.NetConfig;
|
||||||
import electrosphere.net.monitor.NetMonitor;
|
import electrosphere.net.monitor.NetMonitor;
|
||||||
import electrosphere.renderer.RenderUtils;
|
|
||||||
import electrosphere.renderer.RenderingEngine;
|
import electrosphere.renderer.RenderingEngine;
|
||||||
import electrosphere.renderer.actor.instance.InstanceManager;
|
import electrosphere.renderer.actor.instance.InstanceManager;
|
||||||
import electrosphere.renderer.loading.ModelPretransforms;
|
import electrosphere.renderer.loading.ModelPretransforms;
|
||||||
|
import electrosphere.renderer.meshgen.EngineMeshgen;
|
||||||
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
|
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
|
||||||
|
import electrosphere.renderer.meshgen.GeometryModelGen;
|
||||||
import electrosphere.renderer.shader.ShaderOptionMap;
|
import electrosphere.renderer.shader.ShaderOptionMap;
|
||||||
import electrosphere.renderer.shader.VisualShader;
|
import electrosphere.renderer.shader.VisualShader;
|
||||||
import electrosphere.renderer.texture.TextureMap;
|
import electrosphere.renderer.texture.TextureMap;
|
||||||
@ -279,9 +280,9 @@ public class Globals {
|
|||||||
//create font manager
|
//create font manager
|
||||||
fontManager = new FontManager();
|
fontManager = new FontManager();
|
||||||
fontManager.loadFonts();
|
fontManager.loadFonts();
|
||||||
assetManager.registerModelWithPath(RenderUtils.createBitmapCharacter(), AssetDataStrings.BITMAP_CHARACTER_MODEL);
|
assetManager.registerModelWithPath(EngineMeshgen.createBitmapCharacter(), AssetDataStrings.BITMAP_CHARACTER_MODEL);
|
||||||
//particle billboard model
|
//particle billboard model
|
||||||
assetManager.registerModelWithPath(RenderUtils.createParticleModel(), AssetDataStrings.MODEL_PARTICLE);
|
assetManager.registerModelWithPath(EngineMeshgen.createParticleModel(), AssetDataStrings.MODEL_PARTICLE);
|
||||||
//initialize required windows
|
//initialize required windows
|
||||||
WindowUtils.initBaseWindows();
|
WindowUtils.initBaseWindows();
|
||||||
//init default shaderProgram
|
//init default shaderProgram
|
||||||
@ -292,15 +293,15 @@ public class Globals {
|
|||||||
//init fluid shader program
|
//init fluid shader program
|
||||||
FluidChunkModelGeneration.fluidChunkShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/fluid2/fluid2.vs", "/Shaders/entities/fluid2/fluid2.fs");
|
FluidChunkModelGeneration.fluidChunkShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/fluid2/fluid2.vs", "/Shaders/entities/fluid2/fluid2.fs");
|
||||||
//init models
|
//init models
|
||||||
assetManager.registerModelWithPath(RenderUtils.createUnitsphere(), AssetDataStrings.UNITSPHERE);
|
assetManager.registerModelWithPath(GeometryModelGen.createUnitsphere(), AssetDataStrings.UNITSPHERE);
|
||||||
assetManager.registerModelWithPath(RenderUtils.createUnitCylinder(), AssetDataStrings.UNITCYLINDER);
|
assetManager.registerModelWithPath(GeometryModelGen.createUnitCylinder(), AssetDataStrings.UNITCYLINDER);
|
||||||
assetManager.registerModelWithPath(RenderUtils.createUnitCube(), AssetDataStrings.UNITCUBE);
|
assetManager.registerModelWithPath(GeometryModelGen.createUnitCube(), AssetDataStrings.UNITCUBE);
|
||||||
assetManager.registerModelWithPath(RenderUtils.createBlockSingleModel(), AssetDataStrings.MODEL_BLOCK_SINGLE);
|
assetManager.registerModelWithPath(GeometryModelGen.createBlockSingleModel(), AssetDataStrings.MODEL_BLOCK_SINGLE);
|
||||||
assetManager.addModelPathToQueue("Models/basic/geometry/SmallCube.fbx");
|
assetManager.addModelPathToQueue("Models/basic/geometry/SmallCube.fbx");
|
||||||
assetManager.addModelPathToQueue("Models/basic/geometry/unitcapsule.glb");
|
assetManager.addModelPathToQueue("Models/basic/geometry/unitcapsule.glb");
|
||||||
assetManager.addModelPathToQueue("Models/basic/geometry/unitplane.fbx");
|
assetManager.addModelPathToQueue("Models/basic/geometry/unitplane.fbx");
|
||||||
assetManager.addModelPathToQueue("Models/basic/geometry/unitcube.fbx");
|
assetManager.addModelPathToQueue("Models/basic/geometry/unitcube.fbx");
|
||||||
assetManager.registerModelWithPath(RenderUtils.createPlaneModel("Shaders/core/plane/plane.vs", "Shaders/core/plane/plane.fs"), AssetDataStrings.MODEL_IMAGE_PLANE);
|
assetManager.registerModelWithPath(GeometryModelGen.createPlaneModel("Shaders/core/plane/plane.vs", "Shaders/core/plane/plane.fs"), AssetDataStrings.MODEL_IMAGE_PLANE);
|
||||||
assetManager.addShaderToQueue("Shaders/core/plane/plane.vs", "Shaders/core/plane/plane.fs");
|
assetManager.addShaderToQueue("Shaders/core/plane/plane.vs", "Shaders/core/plane/plane.fs");
|
||||||
|
|
||||||
//init pose models for basic shapes
|
//init pose models for basic shapes
|
||||||
@ -310,7 +311,7 @@ public class Globals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//image panel
|
//image panel
|
||||||
ImagePanel.imagePanelModelPath = assetManager.registerModel(RenderUtils.createPlaneModel("Shaders/core/imagepanel/imagepanel.vs", "Shaders/core/imagepanel/imagepanel.fs"));
|
ImagePanel.imagePanelModelPath = assetManager.registerModel(GeometryModelGen.createPlaneModel("Shaders/core/imagepanel/imagepanel.vs", "Shaders/core/imagepanel/imagepanel.fs"));
|
||||||
|
|
||||||
Globals.assetManager.addShaderToQueue("Shaders/ui/plainBox/plainBox.vs", "Shaders/ui/plainBox/plainBox.fs");
|
Globals.assetManager.addShaderToQueue("Shaders/ui/plainBox/plainBox.vs", "Shaders/ui/plainBox/plainBox.fs");
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import electrosphere.engine.Globals;
|
|||||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
import electrosphere.engine.assetmanager.queue.QueuedTexture;
|
import electrosphere.engine.assetmanager.queue.QueuedTexture;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.renderer.RenderUtils;
|
import electrosphere.renderer.meshgen.GeometryModelGen;
|
||||||
import electrosphere.renderer.texture.TextureAtlas;
|
import electrosphere.renderer.texture.TextureAtlas;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ public class InitialAssetLoading {
|
|||||||
//if items have been created, must update the hard-coded shader values to reflect the actual atlas values
|
//if items have been created, must update the hard-coded shader values to reflect the actual atlas values
|
||||||
if(Globals.gameConfigCurrent.getItemMap().getItem(type.getName()) != null){
|
if(Globals.gameConfigCurrent.getItemMap().getItem(type.getName()) != null){
|
||||||
Item item = Globals.gameConfigCurrent.getItemMap().getItem(type.getName());
|
Item item = Globals.gameConfigCurrent.getItemMap().getItem(type.getName());
|
||||||
item.getGraphicsTemplate().getModel().getUniforms().get(RenderUtils.MESH_NAME_BLOCK_SINGLE).put("blockAtlasIndex",iterator);
|
item.getGraphicsTemplate().getModel().getUniforms().get(GeometryModelGen.MESH_NAME_BLOCK_SINGLE).put("blockAtlasIndex",iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//iterate
|
//iterate
|
||||||
@ -161,7 +161,7 @@ public class InitialAssetLoading {
|
|||||||
for(BlockType blockType : Globals.gameConfigCurrent.getBlockData().getTypes()){
|
for(BlockType blockType : Globals.gameConfigCurrent.getBlockData().getTypes()){
|
||||||
String typeId = "block:" + blockType.getName();
|
String typeId = "block:" + blockType.getName();
|
||||||
Item item = Globals.gameConfigCurrent.getItemMap().getItem(typeId);
|
Item item = Globals.gameConfigCurrent.getItemMap().getItem(typeId);
|
||||||
item.getGraphicsTemplate().getModel().getUniforms().get(RenderUtils.MESH_NAME_BLOCK_SINGLE).put("blockAtlasIndex",Globals.blockTextureAtlas.getVoxelTypeOffset(blockType.getId()));
|
item.getGraphicsTemplate().getModel().getUniforms().get(GeometryModelGen.MESH_NAME_BLOCK_SINGLE).put("blockAtlasIndex",Globals.blockTextureAtlas.getVoxelTypeOffset(blockType.getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,5 @@
|
|||||||
package electrosphere.renderer;
|
package electrosphere.renderer;
|
||||||
|
|
||||||
import static electrosphere.renderer.RenderUtils.createScreenTextureVAO;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
|
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||||
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
|
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
|
||||||
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
|
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
|
||||||
@ -38,6 +37,7 @@ import electrosphere.renderer.framebuffer.FramebufferUtils;
|
|||||||
import electrosphere.renderer.framebuffer.Renderbuffer;
|
import electrosphere.renderer.framebuffer.Renderbuffer;
|
||||||
import electrosphere.renderer.hw.HardwareData;
|
import electrosphere.renderer.hw.HardwareData;
|
||||||
import electrosphere.renderer.light.LightManager;
|
import electrosphere.renderer.light.LightManager;
|
||||||
|
import electrosphere.renderer.meshgen.EngineMeshgen;
|
||||||
import electrosphere.renderer.model.Material;
|
import electrosphere.renderer.model.Material;
|
||||||
import electrosphere.renderer.pipelines.CompositePipeline;
|
import electrosphere.renderer.pipelines.CompositePipeline;
|
||||||
import electrosphere.renderer.pipelines.FirstPersonItemsPipeline;
|
import electrosphere.renderer.pipelines.FirstPersonItemsPipeline;
|
||||||
@ -373,7 +373,7 @@ public class RenderingEngine {
|
|||||||
|
|
||||||
|
|
||||||
//init screen rendering quadrant
|
//init screen rendering quadrant
|
||||||
screenTextureVAO = createScreenTextureVAO(this.openGLState);
|
screenTextureVAO = EngineMeshgen.createScreenTextureVAO(this.openGLState);
|
||||||
screenTextureShaders = VisualShader.loadSpecificShader("/Shaders/core/screentexture/simple1/simple1.vs", "/Shaders/core/screentexture/simple1/simple1.fs");
|
screenTextureShaders = VisualShader.loadSpecificShader("/Shaders/core/screentexture/simple1/simple1.vs", "/Shaders/core/screentexture/simple1/simple1.fs");
|
||||||
|
|
||||||
//default framebuffer
|
//default framebuffer
|
||||||
|
|||||||
463
src/main/java/electrosphere/renderer/meshgen/EngineMeshgen.java
Normal file
463
src/main/java/electrosphere/renderer/meshgen/EngineMeshgen.java
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
package electrosphere.renderer.meshgen;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
|
import electrosphere.renderer.OpenGLState;
|
||||||
|
import electrosphere.renderer.model.Material;
|
||||||
|
import electrosphere.renderer.model.Mesh;
|
||||||
|
import electrosphere.renderer.model.Model;
|
||||||
|
import electrosphere.renderer.shader.VisualShader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates core engine models
|
||||||
|
*/
|
||||||
|
public class EngineMeshgen {
|
||||||
|
|
||||||
|
public static int createScreenTextureVAO(OpenGLState openGLState){
|
||||||
|
int rVal = GL45.glGenVertexArrays();
|
||||||
|
openGLState.glBindVertexArray(rVal);
|
||||||
|
//vertices
|
||||||
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
vertexArrayBufferData.put(-1.0f);
|
||||||
|
vertexArrayBufferData.put( 1.0f);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put(-1.0f);
|
||||||
|
vertexArrayBufferData.put(-1.0f);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1.0f);
|
||||||
|
vertexArrayBufferData.put(-1.0f);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put(-1.0f);
|
||||||
|
vertexArrayBufferData.put( 1.0f);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1.0f);
|
||||||
|
vertexArrayBufferData.put(-1.0f);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1.0f);
|
||||||
|
vertexArrayBufferData.put( 1.0f);
|
||||||
|
vertexArrayBufferData.flip();
|
||||||
|
int vertexBuffer = GL45.glGenBuffers();
|
||||||
|
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, vertexBuffer);
|
||||||
|
GL45.glBufferData(GL45.GL_ARRAY_BUFFER, vertexArrayBufferData, GL45.GL_STATIC_DRAW);
|
||||||
|
GL45.glVertexAttribPointer(0, 2, GL45.GL_FLOAT, false, 0, 0);
|
||||||
|
GL45.glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
FloatBuffer textureArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
textureArrayBufferData.put(0.0f);
|
||||||
|
textureArrayBufferData.put(1.0f);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0.0f);
|
||||||
|
textureArrayBufferData.put(0.0f);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1.0f);
|
||||||
|
textureArrayBufferData.put(0.0f);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0.0f);
|
||||||
|
textureArrayBufferData.put(1.0f);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1.0f);
|
||||||
|
textureArrayBufferData.put(0.0f);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1.0f);
|
||||||
|
textureArrayBufferData.put(1.0f);
|
||||||
|
textureArrayBufferData.flip();
|
||||||
|
int textureCoordBuffer = GL45.glGenBuffers();
|
||||||
|
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, textureCoordBuffer);
|
||||||
|
GL45.glBufferData(GL45.GL_ARRAY_BUFFER, textureArrayBufferData, GL45.GL_STATIC_DRAW);
|
||||||
|
GL45.glVertexAttribPointer(1, 2, GL45.GL_FLOAT, false, 0, 0);
|
||||||
|
GL45.glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Model createParticleModel(){
|
||||||
|
Model particleModel = new Model();
|
||||||
|
|
||||||
|
|
||||||
|
Mesh particleMesh = new Mesh("particleBillboard");
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// VAO
|
||||||
|
//
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
particleMesh.generateVAO(openGLState);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
float[] vertexcoords = {
|
||||||
|
-1.0f, 1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f, 0.0f,
|
||||||
|
-1.0f, -1.0f, 0.0f,
|
||||||
|
1.0f, -1.0f, 0.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
//Buffer data to GPU
|
||||||
|
//
|
||||||
|
|
||||||
|
try {
|
||||||
|
int vertexCount = vertexcoords.length / 3;
|
||||||
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(vertexCount * 3);
|
||||||
|
float[] temp = new float[3];
|
||||||
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
|
temp[0] = vertexcoords[i * 3 + 0];
|
||||||
|
temp[1] = vertexcoords[i * 3 + 1];
|
||||||
|
temp[2] = vertexcoords[i * 3 + 2];
|
||||||
|
vertexArrayBufferData.put(temp);
|
||||||
|
}
|
||||||
|
vertexArrayBufferData.flip();
|
||||||
|
particleMesh.bufferVertices(vertexArrayBufferData, 3);
|
||||||
|
} catch (NullPointerException ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] facedata = {
|
||||||
|
0,1,2,
|
||||||
|
1,2,3,
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// FACES
|
||||||
|
//
|
||||||
|
int faceCount = facedata.length / 3;
|
||||||
|
int elementCount = facedata.length;
|
||||||
|
IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(elementCount);
|
||||||
|
for(int i = 0; i < faceCount; i++){
|
||||||
|
int[] temp = new int[3];
|
||||||
|
temp[0] = facedata[i * 3 + 0];
|
||||||
|
temp[1] = facedata[i * 3 + 1];
|
||||||
|
temp[2] = facedata[i * 3 + 2];
|
||||||
|
elementArrayBufferData.put(temp);
|
||||||
|
}
|
||||||
|
elementArrayBufferData.flip();
|
||||||
|
particleMesh.bufferFaces(elementArrayBufferData,elementCount);
|
||||||
|
|
||||||
|
//
|
||||||
|
// TEXTURE COORDS
|
||||||
|
//
|
||||||
|
FloatBuffer texture_coords = BufferUtils.createFloatBuffer(8);
|
||||||
|
float[] texturedata = {
|
||||||
|
0,1,
|
||||||
|
1,1,
|
||||||
|
0,0,
|
||||||
|
1,0
|
||||||
|
};
|
||||||
|
texture_coords.put(texturedata);
|
||||||
|
texture_coords.flip();
|
||||||
|
particleMesh.bufferTextureCoords(texture_coords, 2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VisualShader shader = VisualShader.smartAssembleOITProgram();
|
||||||
|
particleMesh.setShader(shader);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
particleMesh.setMaterial(Material.createExisting(AssetDataStrings.TEXTURE_PARTICLE));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
particleMesh.setParent(particleModel);
|
||||||
|
|
||||||
|
|
||||||
|
particleModel.getMeshes().add(particleMesh);
|
||||||
|
|
||||||
|
|
||||||
|
return particleModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static Model createBitmapDisplay(){
|
||||||
|
|
||||||
|
Model rVal = new Model();
|
||||||
|
Mesh m = new Mesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME);
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
m.generateVAO(openGLState);
|
||||||
|
//vertices
|
||||||
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
vertexArrayBufferData.put( 0);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 0);
|
||||||
|
vertexArrayBufferData.put( 0);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put( 0);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 0);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put( 0);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
IntBuffer faceArrayBufferData = BufferUtils.createIntBuffer(6);
|
||||||
|
faceArrayBufferData.put(0);
|
||||||
|
faceArrayBufferData.put(1);
|
||||||
|
faceArrayBufferData.put(2);
|
||||||
|
|
||||||
|
faceArrayBufferData.put(3);
|
||||||
|
faceArrayBufferData.put(4);
|
||||||
|
faceArrayBufferData.put(5);
|
||||||
|
faceArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
FloatBuffer textureArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
//buffer vertices
|
||||||
|
m.bufferVertices(vertexArrayBufferData, 2);
|
||||||
|
//buffer normals
|
||||||
|
m.bufferNormals(vertexArrayBufferData, 2);
|
||||||
|
//buffer faces
|
||||||
|
m.bufferFaces(faceArrayBufferData, 2);
|
||||||
|
//buffer texture coords
|
||||||
|
m.bufferTextureCoords(textureArrayBufferData, 2);
|
||||||
|
|
||||||
|
|
||||||
|
m.setShader(VisualShader.loadSpecificShader("/Shaders/ui/font/basicbitmap/basicbitmap.vs", "/Shaders/ui/font/basicbitmap/basicbitmap.fs"));
|
||||||
|
|
||||||
|
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
m.setParent(rVal);
|
||||||
|
|
||||||
|
Material uiMat = Material.create("/Textures/Fonts/myfont1-harsher.png");
|
||||||
|
m.setMaterial(uiMat);
|
||||||
|
rVal.getMaterials().add(uiMat);
|
||||||
|
|
||||||
|
rVal.getMeshes().add(m);
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a model to use to show bitmap characters
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model createBitmapCharacter(){
|
||||||
|
|
||||||
|
Model rVal = new Model();
|
||||||
|
Mesh m = new Mesh(AssetDataStrings.ASSET_STRING_BITMAP_FONT_MESH_NAME);
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
m.generateVAO(openGLState);
|
||||||
|
//vertices
|
||||||
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
IntBuffer faceArrayBufferData = BufferUtils.createIntBuffer(6);
|
||||||
|
faceArrayBufferData.put(0);
|
||||||
|
faceArrayBufferData.put(1);
|
||||||
|
faceArrayBufferData.put(2);
|
||||||
|
|
||||||
|
faceArrayBufferData.put(3);
|
||||||
|
faceArrayBufferData.put(4);
|
||||||
|
faceArrayBufferData.put(5);
|
||||||
|
faceArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
FloatBuffer textureArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
//buffer vertices
|
||||||
|
m.bufferVertices(vertexArrayBufferData, 2);
|
||||||
|
//buffer normals
|
||||||
|
m.bufferNormals(vertexArrayBufferData, 2);
|
||||||
|
//buffer faces
|
||||||
|
m.bufferFaces(faceArrayBufferData, 6);
|
||||||
|
//buffer texture coords
|
||||||
|
m.bufferTextureCoords(textureArrayBufferData, 2);
|
||||||
|
|
||||||
|
|
||||||
|
m.setShader(VisualShader.loadSpecificShader("/Shaders/ui/font/bitmapchar/bitmapchar.vs", "/Shaders/ui/font/bitmapchar/bitmapchar.fs"));
|
||||||
|
|
||||||
|
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
m.setParent(rVal);
|
||||||
|
|
||||||
|
rVal.getMeshes().add(m);
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Model createInWindowPanel(String vertexShader, String fragmentShader){
|
||||||
|
|
||||||
|
Model rVal = new Model();
|
||||||
|
Mesh m = new Mesh("plane");
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
m.generateVAO(openGLState);
|
||||||
|
//vertices
|
||||||
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put(-1);
|
||||||
|
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.put( 1);
|
||||||
|
vertexArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
IntBuffer faceArrayBufferData = BufferUtils.createIntBuffer(6);
|
||||||
|
faceArrayBufferData.put(0);
|
||||||
|
faceArrayBufferData.put(1);
|
||||||
|
faceArrayBufferData.put(2);
|
||||||
|
|
||||||
|
faceArrayBufferData.put(3);
|
||||||
|
faceArrayBufferData.put(4);
|
||||||
|
faceArrayBufferData.put(5);
|
||||||
|
faceArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
FloatBuffer textureArrayBufferData = BufferUtils.createFloatBuffer(12);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(0);
|
||||||
|
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.put(1);
|
||||||
|
textureArrayBufferData.flip();
|
||||||
|
|
||||||
|
|
||||||
|
//buffer vertices
|
||||||
|
m.bufferVertices(vertexArrayBufferData, 2);
|
||||||
|
//buffer normals
|
||||||
|
m.bufferNormals(vertexArrayBufferData, 2);
|
||||||
|
//buffer faces
|
||||||
|
m.bufferFaces(faceArrayBufferData, 2);
|
||||||
|
//buffer texture coords
|
||||||
|
m.bufferTextureCoords(textureArrayBufferData, 2);
|
||||||
|
|
||||||
|
|
||||||
|
m.setShader(VisualShader.loadSpecificShader(vertexShader, fragmentShader));
|
||||||
|
|
||||||
|
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
m.setParent(rVal);
|
||||||
|
|
||||||
|
rVal.getMeshes().add(m);
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,402 @@
|
|||||||
|
package electrosphere.renderer.meshgen;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.util.par.ParShapes;
|
||||||
|
import org.lwjgl.util.par.ParShapesMesh;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
|
import electrosphere.renderer.OpenGLState;
|
||||||
|
import electrosphere.renderer.model.Material;
|
||||||
|
import electrosphere.renderer.model.Mesh;
|
||||||
|
import electrosphere.renderer.model.Model;
|
||||||
|
import electrosphere.renderer.shader.VisualShader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates full models of basic geometry
|
||||||
|
*/
|
||||||
|
public class GeometryModelGen {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the mesh for the single block model
|
||||||
|
*/
|
||||||
|
public static final String MESH_NAME_BLOCK_SINGLE = "cube";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a plane model
|
||||||
|
* @param vertexShader The vertex shader
|
||||||
|
* @param fragmentShader The fragment shader
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model createPlaneModel(String vertexShader, String fragmentShader){
|
||||||
|
Model rVal = new Model();
|
||||||
|
Mesh planeMesh = new Mesh("plane");
|
||||||
|
//
|
||||||
|
// VAO
|
||||||
|
//
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
planeMesh.generateVAO(openGLState);
|
||||||
|
|
||||||
|
float[] vertexcoords = {
|
||||||
|
-1.0f, 1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f, 0.0f,
|
||||||
|
-1.0f, -1.0f, 0.0f,
|
||||||
|
1.0f, -1.0f, 0.0f,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
//Buffer data to GPU
|
||||||
|
//
|
||||||
|
|
||||||
|
try {
|
||||||
|
int vertexCount = vertexcoords.length / 3;
|
||||||
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(vertexCount * 3);
|
||||||
|
float[] temp = new float[3];
|
||||||
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
|
temp[0] = vertexcoords[i * 3 + 0];
|
||||||
|
temp[1] = vertexcoords[i * 3 + 1];
|
||||||
|
temp[2] = vertexcoords[i * 3 + 2];
|
||||||
|
vertexArrayBufferData.put(temp);
|
||||||
|
}
|
||||||
|
vertexArrayBufferData.flip();
|
||||||
|
planeMesh.bufferVertices(vertexArrayBufferData, 3);
|
||||||
|
} catch (NullPointerException ex){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] facedata = {
|
||||||
|
0,1,2,
|
||||||
|
1,2,3,
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// FACES
|
||||||
|
//
|
||||||
|
int faceCount = facedata.length / 3;
|
||||||
|
int elementCount = facedata.length;
|
||||||
|
IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(elementCount);
|
||||||
|
for(int i = 0; i < faceCount; i++){
|
||||||
|
int[] temp = new int[3];
|
||||||
|
temp[0] = facedata[i * 3 + 0];
|
||||||
|
temp[1] = facedata[i * 3 + 1];
|
||||||
|
temp[2] = facedata[i * 3 + 2];
|
||||||
|
elementArrayBufferData.put(temp);
|
||||||
|
}
|
||||||
|
elementArrayBufferData.flip();
|
||||||
|
planeMesh.bufferFaces(elementArrayBufferData,elementCount);
|
||||||
|
|
||||||
|
//
|
||||||
|
// TEXTURE COORDS
|
||||||
|
//
|
||||||
|
FloatBuffer texture_coords = BufferUtils.createFloatBuffer(8);
|
||||||
|
float[] texturedata = {
|
||||||
|
0,1,
|
||||||
|
1,1,
|
||||||
|
0,0,
|
||||||
|
1,0
|
||||||
|
};
|
||||||
|
texture_coords.put(texturedata);
|
||||||
|
texture_coords.flip();
|
||||||
|
planeMesh.bufferTextureCoords(texture_coords, 2);
|
||||||
|
|
||||||
|
|
||||||
|
planeMesh.setShader(VisualShader.loadSpecificShader(vertexShader,fragmentShader));
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
planeMesh.setParent(rVal);
|
||||||
|
rVal.getMeshes().add(planeMesh);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a unit sphere model
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model createUnitsphere(){
|
||||||
|
Model model = new Model();
|
||||||
|
Mesh sphereMesh = new Mesh("sphere");
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
sphereMesh.generateVAO(openGLState);
|
||||||
|
|
||||||
|
//buffer coords
|
||||||
|
ParShapesMesh data = ParShapes.par_shapes_create_parametric_sphere(10, 5);
|
||||||
|
int numPoints = data.npoints();
|
||||||
|
|
||||||
|
//verts
|
||||||
|
{
|
||||||
|
FloatBuffer verts = data.points(numPoints * 3);
|
||||||
|
FloatBuffer vertsFinal = BufferUtils.createFloatBuffer(verts.limit()); //reallocating to BufferUtils buffer to help minimize memory errors
|
||||||
|
vertsFinal.put(verts);
|
||||||
|
vertsFinal.flip();
|
||||||
|
sphereMesh.bufferVertices(vertsFinal, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//indices
|
||||||
|
{
|
||||||
|
IntBuffer indices = data.triangles(data.ntriangles() * 3);
|
||||||
|
IntBuffer indicesFinal = BufferUtils.createIntBuffer(indices.limit()); //reallocating to BufferUtils buffer to help minimize memory errors
|
||||||
|
indicesFinal.put(indices);
|
||||||
|
indicesFinal.flip();
|
||||||
|
sphereMesh.bufferFaces(indicesFinal, data.ntriangles() * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
{
|
||||||
|
FloatBuffer texCoords = data.tcoords(numPoints * 3);
|
||||||
|
FloatBuffer texCoordsFinal = BufferUtils.createFloatBuffer(texCoords.limit()); //reallocating to BufferUtils buffer to help minimize memory errors
|
||||||
|
texCoordsFinal.put(texCoords);
|
||||||
|
texCoordsFinal.flip();
|
||||||
|
sphereMesh.bufferTextureCoords(texCoordsFinal, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//setup extra structures
|
||||||
|
Material mat = Material.createExisting(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT);
|
||||||
|
sphereMesh.setMaterial(mat);
|
||||||
|
sphereMesh.setShader(VisualShader.smartAssembleShader());
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
sphereMesh.setParent(model);
|
||||||
|
model.getMeshes().add(sphereMesh);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a unit cylinder model
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model createUnitCylinder(){
|
||||||
|
Model model = new Model();
|
||||||
|
Mesh sphereMesh = new Mesh("cylinder");
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
sphereMesh.generateVAO(openGLState);
|
||||||
|
|
||||||
|
//buffer coords
|
||||||
|
ParShapesMesh data = ParShapes.par_shapes_create_cylinder(10, 2);
|
||||||
|
ParShapes.par_shapes_rotate(data, (float)(Math.PI / 2.0), new float[]{-1,0,0});
|
||||||
|
ParShapes.par_shapes_translate(data, 0, -0.5f, 0);
|
||||||
|
ParShapes.par_shapes_scale(data, -1.0f, 2.0f, 1.0f);
|
||||||
|
int numPoints = data.npoints();
|
||||||
|
|
||||||
|
//verts
|
||||||
|
{
|
||||||
|
FloatBuffer verts = data.points(numPoints * 3);
|
||||||
|
FloatBuffer vertsFinal = BufferUtils.createFloatBuffer(verts.limit()); //reallocating to BufferUtils buffer to help minimize memory errors
|
||||||
|
vertsFinal.put(verts);
|
||||||
|
vertsFinal.flip();
|
||||||
|
sphereMesh.bufferVertices(vertsFinal, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//indices
|
||||||
|
{
|
||||||
|
IntBuffer indices = data.triangles(data.ntriangles() * 3);
|
||||||
|
IntBuffer indicesFinal = BufferUtils.createIntBuffer(indices.limit()); //reallocating to BufferUtils buffer to help minimize memory errors
|
||||||
|
indicesFinal.put(indices);
|
||||||
|
indicesFinal.flip();
|
||||||
|
sphereMesh.bufferFaces(indicesFinal, data.ntriangles() * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
{
|
||||||
|
FloatBuffer texCoords = data.tcoords(numPoints * 3);
|
||||||
|
FloatBuffer texCoordsFinal = BufferUtils.createFloatBuffer(texCoords.limit()); //reallocating to BufferUtils buffer to help minimize memory errors
|
||||||
|
texCoordsFinal.put(texCoords);
|
||||||
|
texCoordsFinal.flip();
|
||||||
|
sphereMesh.bufferTextureCoords(texCoordsFinal, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//setup extra structures
|
||||||
|
Material mat = Material.createExisting(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT);
|
||||||
|
sphereMesh.setMaterial(mat);
|
||||||
|
sphereMesh.setShader(VisualShader.smartAssembleShader());
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
sphereMesh.setParent(model);
|
||||||
|
model.getMeshes().add(sphereMesh);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a unit cylinder model
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model createUnitCube(){
|
||||||
|
Model model = new Model();
|
||||||
|
Mesh sphereMesh = new Mesh("cube");
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
sphereMesh.generateVAO(openGLState);
|
||||||
|
|
||||||
|
//buffer coords
|
||||||
|
int numTriangles = 12;
|
||||||
|
|
||||||
|
//verts
|
||||||
|
BufferUtils.createFloatBuffer(3 * 8);
|
||||||
|
FloatBuffer verts = BufferUtils.createFloatBuffer(3 * 8);
|
||||||
|
verts.put(new float[]{
|
||||||
|
-0.5f,-0.5f,-0.5f,
|
||||||
|
0.5f,-0.5f,-0.5f,
|
||||||
|
-0.5f, 0.5f,-0.5f,
|
||||||
|
0.5f, 0.5f,-0.5f,
|
||||||
|
|
||||||
|
-0.5f,-0.5f, 0.5f,
|
||||||
|
0.5f,-0.5f, 0.5f,
|
||||||
|
-0.5f, 0.5f, 0.5f,
|
||||||
|
0.5f, 0.5f, 0.5f,
|
||||||
|
});
|
||||||
|
verts.flip();
|
||||||
|
sphereMesh.bufferVertices(verts, 3);
|
||||||
|
|
||||||
|
//indices
|
||||||
|
IntBuffer indices = BufferUtils.createIntBuffer(3*12);
|
||||||
|
indices.put(new int[]{
|
||||||
|
//Top
|
||||||
|
2, 6, 7,
|
||||||
|
2, 3, 7,
|
||||||
|
|
||||||
|
//Bottom
|
||||||
|
0, 4, 5,
|
||||||
|
0, 1, 5,
|
||||||
|
|
||||||
|
//Left
|
||||||
|
0, 2, 6,
|
||||||
|
0, 4, 6,
|
||||||
|
|
||||||
|
//Right
|
||||||
|
1, 3, 7,
|
||||||
|
1, 5, 7,
|
||||||
|
|
||||||
|
//Front
|
||||||
|
0, 2, 3,
|
||||||
|
0, 1, 3,
|
||||||
|
|
||||||
|
//Back
|
||||||
|
4, 6, 7,
|
||||||
|
4, 5, 7
|
||||||
|
});
|
||||||
|
indices.flip();
|
||||||
|
sphereMesh.bufferFaces(indices, numTriangles * 3);
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
FloatBuffer texCoords = BufferUtils.createFloatBuffer(2*8);
|
||||||
|
texCoords.put(new float[]{
|
||||||
|
0,0,
|
||||||
|
1,0,
|
||||||
|
0,1,
|
||||||
|
1,1,
|
||||||
|
|
||||||
|
0,0,
|
||||||
|
0,1,
|
||||||
|
1,0,
|
||||||
|
1,1,
|
||||||
|
});
|
||||||
|
texCoords.flip();
|
||||||
|
sphereMesh.bufferTextureCoords(texCoords, 2);
|
||||||
|
|
||||||
|
//setup extra structures
|
||||||
|
Material mat = Material.createExisting(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT);
|
||||||
|
sphereMesh.setMaterial(mat);
|
||||||
|
sphereMesh.setShader(VisualShader.smartAssembleShader());
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
sphereMesh.setParent(model);
|
||||||
|
model.getMeshes().add(sphereMesh);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a unit cylinder model
|
||||||
|
* @return The model
|
||||||
|
*/
|
||||||
|
public static Model createBlockSingleModel(){
|
||||||
|
Model model = new Model();
|
||||||
|
Mesh cubeMesh = new Mesh(GeometryModelGen.MESH_NAME_BLOCK_SINGLE);
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
cubeMesh.generateVAO(openGLState);
|
||||||
|
|
||||||
|
//buffer coords
|
||||||
|
int numTriangles = 12;
|
||||||
|
|
||||||
|
//verts
|
||||||
|
BufferUtils.createFloatBuffer(3 * 8);
|
||||||
|
FloatBuffer verts = BufferUtils.createFloatBuffer(3 * 8);
|
||||||
|
verts.put(new float[]{
|
||||||
|
-0.1f,-0.1f,-0.1f,
|
||||||
|
0.1f,-0.1f,-0.1f,
|
||||||
|
-0.1f, 0.1f,-0.1f,
|
||||||
|
0.1f, 0.1f,-0.1f,
|
||||||
|
|
||||||
|
-0.1f,-0.1f, 0.1f,
|
||||||
|
0.1f,-0.1f, 0.1f,
|
||||||
|
-0.1f, 0.1f, 0.1f,
|
||||||
|
0.1f, 0.1f, 0.1f,
|
||||||
|
});
|
||||||
|
verts.flip();
|
||||||
|
cubeMesh.bufferVertices(verts, 3);
|
||||||
|
|
||||||
|
//indices
|
||||||
|
IntBuffer indices = BufferUtils.createIntBuffer(3*12);
|
||||||
|
indices.put(new int[]{
|
||||||
|
//Top
|
||||||
|
2, 6, 7,
|
||||||
|
2, 3, 7,
|
||||||
|
|
||||||
|
//Bottom
|
||||||
|
0, 4, 5,
|
||||||
|
0, 1, 5,
|
||||||
|
|
||||||
|
//Left
|
||||||
|
0, 2, 6,
|
||||||
|
0, 4, 6,
|
||||||
|
|
||||||
|
//Right
|
||||||
|
1, 3, 7,
|
||||||
|
1, 5, 7,
|
||||||
|
|
||||||
|
//Front
|
||||||
|
0, 2, 3,
|
||||||
|
0, 1, 3,
|
||||||
|
|
||||||
|
//Back
|
||||||
|
4, 6, 7,
|
||||||
|
4, 5, 7
|
||||||
|
});
|
||||||
|
indices.flip();
|
||||||
|
cubeMesh.bufferFaces(indices, numTriangles * 3);
|
||||||
|
|
||||||
|
//texture coords
|
||||||
|
FloatBuffer texCoords = BufferUtils.createFloatBuffer(2*8);
|
||||||
|
texCoords.put(new float[]{
|
||||||
|
0,0,
|
||||||
|
1,0,
|
||||||
|
0,1,
|
||||||
|
1,1,
|
||||||
|
|
||||||
|
0,0,
|
||||||
|
0,1,
|
||||||
|
1,0,
|
||||||
|
1,1,
|
||||||
|
});
|
||||||
|
texCoords.flip();
|
||||||
|
cubeMesh.bufferTextureCoords(texCoords, 2);
|
||||||
|
|
||||||
|
//setup extra structures
|
||||||
|
Material mat = Material.createExisting(AssetDataStrings.TEXTURE_BLOCK_ATLAS);
|
||||||
|
cubeMesh.setMaterial(mat);
|
||||||
|
cubeMesh.setShader(VisualShader.loadSpecificShader(AssetDataStrings.SHADER_BLOCK_SINGLE_VERT, AssetDataStrings.SHADER_BLOCK_SINGLE_FRAG));
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
cubeMesh.setParent(model);
|
||||||
|
model.getMeshes().add(cubeMesh);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,801 @@
|
|||||||
|
package electrosphere.renderer.meshgen;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.renderer.OpenGLState;
|
||||||
|
import electrosphere.renderer.model.Material;
|
||||||
|
import electrosphere.renderer.model.Mesh;
|
||||||
|
import electrosphere.renderer.model.Model;
|
||||||
|
import electrosphere.renderer.shader.VisualShader;
|
||||||
|
|
||||||
|
public class HeightmapMeshgen {
|
||||||
|
|
||||||
|
public static Model createTerrainModelPrecomputedShader(OpenGLState openGLState, float[][] heightfield, float[][] texturemap, VisualShader program, int stride){
|
||||||
|
Model rVal = new Model();
|
||||||
|
Mesh m = new Mesh("terrain");
|
||||||
|
int width = heightfield.length;
|
||||||
|
int height = heightfield[0].length;
|
||||||
|
|
||||||
|
int actualWidth = (int)Math.ceil(1.0f * width / (1.0f * stride));
|
||||||
|
int actualHeight = (int)Math.ceil(1.0f * height / (1.0f * stride));
|
||||||
|
|
||||||
|
|
||||||
|
// System.out.println(actualWidth + " " + actualHeight);
|
||||||
|
|
||||||
|
// System.out.println((actualWidth - 1) * (actualHeight - 1));
|
||||||
|
|
||||||
|
FloatBuffer vertices;
|
||||||
|
FloatBuffer normals;
|
||||||
|
IntBuffer faces;
|
||||||
|
FloatBuffer texture_coords;
|
||||||
|
FloatBuffer textureIndices;
|
||||||
|
if(stride * actualWidth > width){
|
||||||
|
int drawWidth = actualWidth + 1;
|
||||||
|
int drawHeight = actualHeight + 1;
|
||||||
|
vertices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 12);
|
||||||
|
normals = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 12);
|
||||||
|
faces = BufferUtils.createIntBuffer((drawWidth - 1) * (drawHeight - 1) * 2 * 3);
|
||||||
|
texture_coords = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 8);
|
||||||
|
textureIndices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 16);
|
||||||
|
} else {
|
||||||
|
vertices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 12);
|
||||||
|
normals = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 12);
|
||||||
|
faces = BufferUtils.createIntBuffer((actualWidth - 1) * (actualHeight - 1) * 2 * 3);
|
||||||
|
texture_coords = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 8);
|
||||||
|
textureIndices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int incrementer = 0;
|
||||||
|
// int numFaces = (actualWidth - 1) * (actualHeight - 1) * 2 * 3;
|
||||||
|
for(int x = 0; x < width - 1; x = x + stride){
|
||||||
|
for(int y = 0; y < height - 1; y = y + stride){
|
||||||
|
//deal with vertex
|
||||||
|
//0,0
|
||||||
|
vertices.put(x);
|
||||||
|
vertices.put(heightfield[x][y]);
|
||||||
|
vertices.put(y);
|
||||||
|
//1,0
|
||||||
|
vertices.put(x + stride);
|
||||||
|
vertices.put(heightfield[x+stride][y]);
|
||||||
|
vertices.put(y);
|
||||||
|
//0,1
|
||||||
|
vertices.put(x);
|
||||||
|
vertices.put(heightfield[x][y+stride]);
|
||||||
|
vertices.put(y + stride);
|
||||||
|
//1,1
|
||||||
|
vertices.put(x + stride);
|
||||||
|
vertices.put(heightfield[x+stride][y+stride]);
|
||||||
|
vertices.put(y + stride);
|
||||||
|
//deal with normal
|
||||||
|
Vector3f normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x, y);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x + stride, y);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x, y + stride);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x + stride, y + stride);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
//deal with texture coordinates
|
||||||
|
// if(x / stride % 2 == 0){
|
||||||
|
// if(y / stride % 2 == 0){
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// } else {
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if(y / stride % 2 == 0){
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// } else {
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(1);
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(1);
|
||||||
|
texture_coords.put(1);
|
||||||
|
texture_coords.put(1);
|
||||||
|
|
||||||
|
if(x + stride < width - 1 && y + stride < height - 1){
|
||||||
|
// texturemap[x+stride][y+stride];
|
||||||
|
for(int i = 0; i < 4 ; i++){
|
||||||
|
// textureIndices.put(1);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
textureIndices.put(texturemap[x][y]);
|
||||||
|
textureIndices.put(texturemap[x+stride][y]);
|
||||||
|
textureIndices.put(texturemap[x][y+stride]);
|
||||||
|
textureIndices.put(texturemap[x+stride][y+stride]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < 4 ; i++){
|
||||||
|
textureIndices.put(0);
|
||||||
|
textureIndices.put(0);
|
||||||
|
textureIndices.put(0);
|
||||||
|
textureIndices.put(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//deal with faces
|
||||||
|
if(1.0f * x / stride < actualWidth - 1 && 1.0f * y / stride < actualHeight - 1){
|
||||||
|
faces.put(incrementer * 4 + 0);
|
||||||
|
faces.put(incrementer * 4 + 1);
|
||||||
|
faces.put(incrementer * 4 + 2);
|
||||||
|
faces.put(incrementer * 4 + 1);
|
||||||
|
faces.put(incrementer * 4 + 2);
|
||||||
|
faces.put(incrementer * 4 + 3);
|
||||||
|
}
|
||||||
|
incrementer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices.flip();
|
||||||
|
normals.flip();
|
||||||
|
faces.flip();
|
||||||
|
texture_coords.flip();
|
||||||
|
textureIndices.flip();
|
||||||
|
|
||||||
|
m.generateVAO(openGLState);
|
||||||
|
//buffer vertices
|
||||||
|
m.bufferVertices(vertices, 3);
|
||||||
|
//buffer normals
|
||||||
|
m.bufferNormals(normals, 3);
|
||||||
|
//buffer faces
|
||||||
|
m.bufferFaces(faces,incrementer*2);
|
||||||
|
//buffer texture coords
|
||||||
|
m.bufferTextureCoords(texture_coords, 2);
|
||||||
|
//texture indices
|
||||||
|
m.bufferCustomFloatAttribArray(textureIndices, 4, 5);
|
||||||
|
m.setShader(program);
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
m.setParent(rVal);
|
||||||
|
|
||||||
|
Material groundMat = Material.create("/Textures/Ground/Dirt1.png");
|
||||||
|
m.setMaterial(groundMat);
|
||||||
|
|
||||||
|
rVal.getMeshes().add(m);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float MINIMIZATION_DIFF_MAX = 0.001f;
|
||||||
|
|
||||||
|
public static Model createMinimizedTerrainModelPrecomputedShader(float[][] heightfield, float[][] texturemap, VisualShader program, int stride){
|
||||||
|
|
||||||
|
class QuadToGenerate {
|
||||||
|
//coords are inclusive
|
||||||
|
int startX;
|
||||||
|
int endX;
|
||||||
|
int startY;
|
||||||
|
int endY;
|
||||||
|
float min;
|
||||||
|
float max;
|
||||||
|
float texture;
|
||||||
|
boolean homogeneousTexture;
|
||||||
|
|
||||||
|
QuadToGenerate(int startX, int startY, int endX, int endY, float diff, float min, float max, boolean homogeneousTexture, float texture){
|
||||||
|
this.startX = startX;
|
||||||
|
this.startY = startY;
|
||||||
|
this.endX = endX;
|
||||||
|
this.endY = endY;
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
this.texture = texture;
|
||||||
|
this.homogeneousTexture = homogeneousTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Model rVal = new Model();
|
||||||
|
Mesh m = new Mesh("terrain");
|
||||||
|
OpenGLState openGLState = Globals.renderingEngine.getOpenGLState();
|
||||||
|
int width = heightfield.length;
|
||||||
|
int height = heightfield[0].length;
|
||||||
|
|
||||||
|
int actualWidth = (int)Math.ceil(1.0f * width / (1.0f * stride));
|
||||||
|
int actualHeight = (int)Math.ceil(1.0f * height / (1.0f * stride));
|
||||||
|
|
||||||
|
|
||||||
|
// System.out.println(actualWidth + " " + actualHeight);
|
||||||
|
|
||||||
|
// System.out.println((actualWidth - 1) * (actualHeight - 1));
|
||||||
|
|
||||||
|
FloatBuffer vertices;
|
||||||
|
FloatBuffer normals;
|
||||||
|
IntBuffer faces;
|
||||||
|
FloatBuffer texture_coords;
|
||||||
|
FloatBuffer textureIndices;
|
||||||
|
if(stride * actualWidth > width){
|
||||||
|
int drawWidth = actualWidth + 1;
|
||||||
|
int drawHeight = actualHeight + 1;
|
||||||
|
vertices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 12);
|
||||||
|
normals = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 12);
|
||||||
|
faces = BufferUtils.createIntBuffer((drawWidth - 1) * (drawHeight - 1) * 2 * 3);
|
||||||
|
texture_coords = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 8);
|
||||||
|
textureIndices = BufferUtils.createFloatBuffer(drawWidth * drawHeight * 16);
|
||||||
|
} else {
|
||||||
|
vertices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 12);
|
||||||
|
normals = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 12);
|
||||||
|
faces = BufferUtils.createIntBuffer((actualWidth - 1) * (actualHeight - 1) * 2 * 3);
|
||||||
|
texture_coords = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 8);
|
||||||
|
textureIndices = BufferUtils.createFloatBuffer(actualWidth * actualHeight * 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//merge along y
|
||||||
|
|
||||||
|
List<QuadToGenerate> firstPhaseQuads = new LinkedList<QuadToGenerate>();
|
||||||
|
QuadToGenerate quadCurrent = null;
|
||||||
|
float minVal = 0;
|
||||||
|
float maxVal = 0;
|
||||||
|
for(int x = 0; x < width - 1; x = x + stride){
|
||||||
|
quadCurrent = null;
|
||||||
|
for(int y = 0; y < height - 1; y = y + stride){
|
||||||
|
if((x == 5 && y == 2)){
|
||||||
|
// System.out.println(quadCurrent);
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
|
if(quadCurrent == null){
|
||||||
|
minVal = 100000000;
|
||||||
|
maxVal = 0;
|
||||||
|
//minval
|
||||||
|
if(heightfield[x][y] < minVal){
|
||||||
|
minVal = heightfield[x][y];
|
||||||
|
}
|
||||||
|
if(heightfield[x+stride][y] < minVal){
|
||||||
|
minVal = heightfield[x+stride][y];
|
||||||
|
}
|
||||||
|
if(heightfield[x][y+stride] < minVal){
|
||||||
|
minVal = heightfield[x][y+stride];
|
||||||
|
}
|
||||||
|
if(heightfield[x+stride][y+stride] < minVal){
|
||||||
|
minVal = heightfield[x+stride][y+stride];
|
||||||
|
}
|
||||||
|
//maxval
|
||||||
|
if(heightfield[x][y] > maxVal){
|
||||||
|
maxVal = heightfield[x][y];
|
||||||
|
}
|
||||||
|
if(heightfield[x+stride][y] > maxVal){
|
||||||
|
maxVal = heightfield[x+stride][y];
|
||||||
|
}
|
||||||
|
if(heightfield[x][y+stride] > maxVal){
|
||||||
|
maxVal = heightfield[x][y+stride];
|
||||||
|
}
|
||||||
|
if(heightfield[x+stride][y+stride] > maxVal){
|
||||||
|
maxVal = heightfield[x+stride][y+stride];
|
||||||
|
}
|
||||||
|
boolean textureMatch = false;
|
||||||
|
float texture = -1;
|
||||||
|
if(x+stride < width - 1 && y+stride < height - 1 &&
|
||||||
|
texturemap[x][y] == texturemap[x+stride][y] &&
|
||||||
|
texturemap[x][y] == texturemap[x][y+stride] &&
|
||||||
|
texturemap[x][y] == texturemap[x+stride][y+stride]){
|
||||||
|
|
||||||
|
textureMatch = true;
|
||||||
|
texture = texturemap[x][y];
|
||||||
|
} else {
|
||||||
|
// if(x > 8 && (x+stride < width - 1) && (y+stride < height -1)){
|
||||||
|
// System.out.println(
|
||||||
|
// (x+stride < width - 1) + " " +
|
||||||
|
// (y+stride < height -1) + " " +
|
||||||
|
// (texturemap[x][y] == texturemap[x+stride][y]) + " " +
|
||||||
|
// (texturemap[x][y] == texturemap[x][y+stride]) + " " +
|
||||||
|
// (texturemap[x][y] == texturemap[x+stride][y+stride])
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if(textureMatch){
|
||||||
|
quadCurrent = new QuadToGenerate(x,y,x+stride,y+stride,maxVal - minVal,minVal,maxVal,textureMatch,texture);
|
||||||
|
} else {
|
||||||
|
firstPhaseQuads.add(new QuadToGenerate(x,y,x+stride,y+stride,maxVal - minVal,minVal,maxVal,textureMatch,texture));
|
||||||
|
// quadCurrent = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float newMin = minVal;
|
||||||
|
float newMax = maxVal;
|
||||||
|
//min
|
||||||
|
if(heightfield[x][y+stride] < newMin){
|
||||||
|
newMin = heightfield[x][y+stride];
|
||||||
|
}
|
||||||
|
if(heightfield[x+stride][y+stride] < newMin){
|
||||||
|
newMin = heightfield[x+stride][y+stride];
|
||||||
|
}
|
||||||
|
//max
|
||||||
|
if(heightfield[x][y+stride] > newMax){
|
||||||
|
newMax = heightfield[x][y+stride];
|
||||||
|
}
|
||||||
|
if(heightfield[x+stride][y+stride] > newMax){
|
||||||
|
newMax = heightfield[x+stride][y+stride];
|
||||||
|
}
|
||||||
|
if(y+stride < height - 1 && x+stride < width - 1){
|
||||||
|
if(newMax - newMin < MINIMIZATION_DIFF_MAX &&
|
||||||
|
quadCurrent.texture == texturemap[x+stride][y] &&
|
||||||
|
quadCurrent.texture == texturemap[x ][y+stride] &&
|
||||||
|
quadCurrent.texture == texturemap[x+stride][y+stride] &&
|
||||||
|
quadCurrent.homogeneousTexture
|
||||||
|
){
|
||||||
|
//add to quad
|
||||||
|
quadCurrent.endY = y + stride;
|
||||||
|
quadCurrent.min = newMax;
|
||||||
|
quadCurrent.max = newMax;
|
||||||
|
} else {
|
||||||
|
//push quad
|
||||||
|
firstPhaseQuads.add(quadCurrent);
|
||||||
|
firstPhaseQuads.add(new QuadToGenerate(x,y,x+stride,y+stride,maxVal - minVal,minVal,maxVal,false,0));
|
||||||
|
quadCurrent = null;
|
||||||
|
// System.out.println("Push");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(newMax - newMin < MINIMIZATION_DIFF_MAX){
|
||||||
|
//add to quad
|
||||||
|
quadCurrent.endY = y + stride;
|
||||||
|
quadCurrent.min = newMax;
|
||||||
|
quadCurrent.max = newMax;
|
||||||
|
} else {
|
||||||
|
//push quad that we were building
|
||||||
|
firstPhaseQuads.add(quadCurrent);
|
||||||
|
// quadCurrent = null;
|
||||||
|
//create new quad from what we were just analyzing
|
||||||
|
boolean textureMatch = false;
|
||||||
|
float texture = -1;
|
||||||
|
quadCurrent = new QuadToGenerate(x,y,x+stride,y+stride,maxVal - minVal,minVal,maxVal,textureMatch,texture);
|
||||||
|
// System.out.println("Push");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(quadCurrent != null){
|
||||||
|
firstPhaseQuads.add(quadCurrent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<QuadToGenerate> finalQuads = new LinkedList<QuadToGenerate>();
|
||||||
|
// for(QuadToGenerate current : firstPhaseQuads){
|
||||||
|
// finalQuads.add(current);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// System.out.println(finalQuads.size());
|
||||||
|
|
||||||
|
//merge along x
|
||||||
|
|
||||||
|
// QuadToGenerate currentQuad = null;
|
||||||
|
List<QuadToGenerate> toSkip = new LinkedList<QuadToGenerate>();
|
||||||
|
for(QuadToGenerate currentQuad : firstPhaseQuads){
|
||||||
|
// toRemove.clear();
|
||||||
|
if(toSkip.contains(currentQuad)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for(QuadToGenerate currentPotentialMatch : firstPhaseQuads){
|
||||||
|
if(currentPotentialMatch.startX <= currentQuad.startX){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(currentPotentialMatch.startX > currentQuad.endX){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(currentPotentialMatch.startY != currentQuad.startY){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(currentPotentialMatch.endY != currentQuad.endY){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(
|
||||||
|
!(currentQuad.homogeneousTexture &&
|
||||||
|
currentPotentialMatch.homogeneousTexture &&
|
||||||
|
currentQuad.texture == currentPotentialMatch.texture)
|
||||||
|
){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(currentQuad.min < currentPotentialMatch.min && currentQuad.max < currentPotentialMatch.max){
|
||||||
|
float min = currentQuad.min;
|
||||||
|
float max = currentPotentialMatch.max;
|
||||||
|
if(max - min < MINIMIZATION_DIFF_MAX){
|
||||||
|
currentQuad.endX = currentPotentialMatch.endX;
|
||||||
|
currentQuad.max = currentPotentialMatch.max;
|
||||||
|
toSkip.add(currentPotentialMatch);
|
||||||
|
}
|
||||||
|
} else if(currentQuad.min > currentPotentialMatch.min && currentQuad.max > currentPotentialMatch.max){
|
||||||
|
float min = currentPotentialMatch.min;
|
||||||
|
float max = currentQuad.max;
|
||||||
|
if(max - min < MINIMIZATION_DIFF_MAX){
|
||||||
|
currentQuad.endX = currentPotentialMatch.endX;
|
||||||
|
currentQuad.min = currentPotentialMatch.min;
|
||||||
|
toSkip.add(currentPotentialMatch);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(currentQuad.min < currentPotentialMatch.min){
|
||||||
|
currentQuad.endX = currentPotentialMatch.endX;
|
||||||
|
} else {
|
||||||
|
currentQuad.endX = currentPotentialMatch.endX;
|
||||||
|
currentQuad.min = currentPotentialMatch.min;
|
||||||
|
currentQuad.max = currentPotentialMatch.max;
|
||||||
|
}
|
||||||
|
toSkip.add(currentPotentialMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finalQuads.add(currentQuad);
|
||||||
|
}
|
||||||
|
// for(QuadToGenerate currentIteration : firstPhaseQuads){
|
||||||
|
// if(currentQuad == null){
|
||||||
|
// currentQuad = currentIteration;
|
||||||
|
// } else {
|
||||||
|
// //if should merge:
|
||||||
|
// if(
|
||||||
|
// currentQuad.homogeneousTexture &&
|
||||||
|
// currentIteration.homogeneousTexture &&
|
||||||
|
// currentQuad.texture == currentIteration.texture
|
||||||
|
// ){
|
||||||
|
// if(currentQuad.min < currentIteration.min && currentQuad.max < currentIteration.max){
|
||||||
|
// float min = currentQuad.min;
|
||||||
|
// float max = currentIteration.max;
|
||||||
|
// if(max - min < MINIMIZATION_DIFF_MAX){
|
||||||
|
// currentQuad.endX = currentIteration.endX;
|
||||||
|
// currentQuad.max = currentIteration.max;
|
||||||
|
// } else {
|
||||||
|
// finalQuads.add(currentQuad);
|
||||||
|
// currentQuad = currentIteration;
|
||||||
|
// }
|
||||||
|
// } else if(currentQuad.min > currentIteration.min && currentQuad.max > currentIteration.max){
|
||||||
|
// float min = currentIteration.min;
|
||||||
|
// float max = currentQuad.max;
|
||||||
|
// if(max - min < MINIMIZATION_DIFF_MAX){
|
||||||
|
// currentQuad.endX = currentIteration.endX;
|
||||||
|
// currentQuad.min = currentIteration.min;
|
||||||
|
// } else {
|
||||||
|
// finalQuads.add(currentQuad);
|
||||||
|
// currentQuad = currentIteration;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if(currentQuad.min < currentIteration.min){
|
||||||
|
// currentQuad.endX = currentIteration.endX;
|
||||||
|
// } else {
|
||||||
|
// currentQuad.endX = currentIteration.endX;
|
||||||
|
// currentQuad.min = currentIteration.min;
|
||||||
|
// currentQuad.max = currentIteration.max;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// finalQuads.add(currentQuad);
|
||||||
|
// currentQuad = currentIteration;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// finalQuads.add(currentQuad);
|
||||||
|
|
||||||
|
// for(QuadToGenerate current : finalQuads){
|
||||||
|
// if(current.startX > 0 && current.startY > 0 && current.endX < 99 && current.endY < 99){
|
||||||
|
// System.out.println(current.startX + " " + current.startY + " " + current.endX + " " + current.endY);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// System.out.println("AAAAAAAAAAAAAAAAAA");
|
||||||
|
// System.out.println(finalQuads.size());
|
||||||
|
|
||||||
|
int incrementer = 0;
|
||||||
|
|
||||||
|
for(QuadToGenerate current : finalQuads){
|
||||||
|
//deal with vertex
|
||||||
|
//0,0
|
||||||
|
vertices.put(current.startX);
|
||||||
|
vertices.put(heightfield[current.startX][current.startY]);
|
||||||
|
vertices.put(current.startY);
|
||||||
|
//1,0
|
||||||
|
vertices.put(current.endX);
|
||||||
|
vertices.put(heightfield[current.endX][current.startY]);
|
||||||
|
vertices.put(current.startY);
|
||||||
|
//0,1
|
||||||
|
vertices.put(current.startX);
|
||||||
|
vertices.put(heightfield[current.startX][current.endY]);
|
||||||
|
vertices.put(current.endY);
|
||||||
|
//1,1
|
||||||
|
vertices.put(current.endX);
|
||||||
|
vertices.put(heightfield[current.endX][current.endY]);
|
||||||
|
vertices.put(current.endY);
|
||||||
|
//deal with normal
|
||||||
|
Vector3f normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.startX, current.startY);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.endX, current.startY);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.startX, current.endY);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, current.endX, current.endY);
|
||||||
|
normals.put(normal.x);
|
||||||
|
normals.put(normal.y);
|
||||||
|
normals.put(normal.z);
|
||||||
|
//deal with texture coordinates
|
||||||
|
// if(x / stride % 2 == 0){
|
||||||
|
// if(y / stride % 2 == 0){
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// } else {
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if(y / stride % 2 == 0){
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// } else {
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(current.endX - current.startX);
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(0);
|
||||||
|
texture_coords.put(current.endY - current.startY);
|
||||||
|
texture_coords.put(current.endX - current.startX);
|
||||||
|
texture_coords.put(current.endY - current.startY);
|
||||||
|
|
||||||
|
if(current.endX < width - 1 && current.endY < height - 1){
|
||||||
|
// texturemap[x+stride][y+stride];
|
||||||
|
for(int i = 0; i < 4 ; i++){
|
||||||
|
// textureIndices.put(1);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
textureIndices.put(texturemap[current.startX][current.startY]);
|
||||||
|
textureIndices.put(texturemap[current.endX][current.startY]);
|
||||||
|
textureIndices.put(texturemap[current.startX][current.endY]);
|
||||||
|
textureIndices.put(texturemap[current.endX][current.endY]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < 4 ; i++){
|
||||||
|
textureIndices.put(0);
|
||||||
|
textureIndices.put(0);
|
||||||
|
textureIndices.put(0);
|
||||||
|
textureIndices.put(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//deal with faces
|
||||||
|
faces.put(incrementer * 4 + 0);
|
||||||
|
faces.put(incrementer * 4 + 1);
|
||||||
|
faces.put(incrementer * 4 + 2);
|
||||||
|
faces.put(incrementer * 4 + 1);
|
||||||
|
faces.put(incrementer * 4 + 2);
|
||||||
|
faces.put(incrementer * 4 + 3);
|
||||||
|
|
||||||
|
incrementer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// int numFaces = (actualWidth - 1) * (actualHeight - 1) * 2 * 3;
|
||||||
|
// for(int x = 0; x < width - 1; x = x + stride){
|
||||||
|
// for(int y = 0; y < height - 1; y = y + stride){
|
||||||
|
// //deal with vertex
|
||||||
|
// //0,0
|
||||||
|
// vertices.put(x);
|
||||||
|
// vertices.put(heightfield[x][y]);
|
||||||
|
// vertices.put(y);
|
||||||
|
// //1,0
|
||||||
|
// vertices.put(x + stride);
|
||||||
|
// vertices.put(heightfield[x+stride][y]);
|
||||||
|
// vertices.put(y);
|
||||||
|
// //0,1
|
||||||
|
// vertices.put(x);
|
||||||
|
// vertices.put(heightfield[x][y+stride]);
|
||||||
|
// vertices.put(y + stride);
|
||||||
|
// //1,1
|
||||||
|
// vertices.put(x + stride);
|
||||||
|
// vertices.put(heightfield[x+stride][y+stride]);
|
||||||
|
// vertices.put(y + stride);
|
||||||
|
// //deal with normal
|
||||||
|
// Vector3f normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x, y);
|
||||||
|
// normals.put(normal.x);
|
||||||
|
// normals.put(normal.y);
|
||||||
|
// normals.put(normal.z);
|
||||||
|
// normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x + stride, y);
|
||||||
|
// normals.put(normal.x);
|
||||||
|
// normals.put(normal.y);
|
||||||
|
// normals.put(normal.z);
|
||||||
|
// normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x, y + stride);
|
||||||
|
// normals.put(normal.x);
|
||||||
|
// normals.put(normal.y);
|
||||||
|
// normals.put(normal.z);
|
||||||
|
// normal = calculateTerrainNormal(heightfield, actualWidth, actualHeight, stride, x + stride, y + stride);
|
||||||
|
// normals.put(normal.x);
|
||||||
|
// normals.put(normal.y);
|
||||||
|
// normals.put(normal.z);
|
||||||
|
// //deal with texture coordinates
|
||||||
|
//// if(x / stride % 2 == 0){
|
||||||
|
//// if(y / stride % 2 == 0){
|
||||||
|
//// texture_coords.put(0);
|
||||||
|
//// texture_coords.put(0);
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// texture_coords.put(0);
|
||||||
|
//// texture_coords.put(0);
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// } else {
|
||||||
|
//// texture_coords.put(0);
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// }
|
||||||
|
//// } else {
|
||||||
|
//// if(y / stride % 2 == 0){
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// texture_coords.put(0);
|
||||||
|
//// } else {
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// texture_coords.put(1);
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(0);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
// texture_coords.put(1);
|
||||||
|
//
|
||||||
|
// if(x + stride < width - 1 && y + stride < height - 1){
|
||||||
|
//// texturemap[x+stride][y+stride];
|
||||||
|
// for(int i = 0; i < 4 ; i++){
|
||||||
|
//// textureIndices.put(1);
|
||||||
|
//// textureIndices.put(0);
|
||||||
|
//// textureIndices.put(0);
|
||||||
|
//// textureIndices.put(0);
|
||||||
|
// textureIndices.put(texturemap[x][y]);
|
||||||
|
// textureIndices.put(texturemap[x+stride][y]);
|
||||||
|
// textureIndices.put(texturemap[x][y+stride]);
|
||||||
|
// textureIndices.put(texturemap[x+stride][y+stride]);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// for(int i = 0; i < 4 ; i++){
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// textureIndices.put(0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// //deal with faces
|
||||||
|
// if(1.0f * x / stride < actualWidth - 1 && 1.0f * y / stride < actualHeight - 1){
|
||||||
|
// faces.put(incrementer * 4 + 0);
|
||||||
|
// faces.put(incrementer * 4 + 1);
|
||||||
|
// faces.put(incrementer * 4 + 2);
|
||||||
|
// faces.put(incrementer * 4 + 1);
|
||||||
|
// faces.put(incrementer * 4 + 2);
|
||||||
|
// faces.put(incrementer * 4 + 3);
|
||||||
|
// }
|
||||||
|
// incrementer++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// System.out.println(incrementer + " quads");
|
||||||
|
|
||||||
|
vertices.flip();
|
||||||
|
normals.flip();
|
||||||
|
faces.flip();
|
||||||
|
texture_coords.flip();
|
||||||
|
textureIndices.flip();
|
||||||
|
|
||||||
|
m.generateVAO(openGLState);
|
||||||
|
//buffer vertices
|
||||||
|
m.bufferVertices(vertices, 3);
|
||||||
|
//buffer normals
|
||||||
|
m.bufferNormals(normals, 3);
|
||||||
|
//buffer faces
|
||||||
|
m.bufferFaces(faces,incrementer*2);
|
||||||
|
//buffer texture coords
|
||||||
|
m.bufferTextureCoords(texture_coords, 2);
|
||||||
|
//texture indices
|
||||||
|
m.bufferCustomFloatAttribArray(textureIndices, 4, 5);
|
||||||
|
m.setShader(program);
|
||||||
|
openGLState.glBindVertexArray(0);
|
||||||
|
m.setParent(rVal);
|
||||||
|
|
||||||
|
Material groundMat = Material.create("/Textures/Ground/Dirt1.png");
|
||||||
|
m.setMaterial(groundMat);
|
||||||
|
|
||||||
|
rVal.getMeshes().add(m);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vector3f calculateTerrainNormal(float[][] heightfield, int actualWidth, int actualHeight, int stride, int x, int y){
|
||||||
|
Vector3f rVal = new Vector3f();
|
||||||
|
if(x / stride < actualWidth - 1){
|
||||||
|
if(y / stride < actualHeight - 1){
|
||||||
|
float hL;
|
||||||
|
if(x > 0){
|
||||||
|
hL = heightfield[x-1][y];
|
||||||
|
} else {
|
||||||
|
hL = heightfield[x][y];
|
||||||
|
}
|
||||||
|
float hR = heightfield[x+1][y];
|
||||||
|
float hD = heightfield[x][y+1];
|
||||||
|
float hU;
|
||||||
|
if(y > 0){
|
||||||
|
hU = heightfield[x][y-1];
|
||||||
|
} else {
|
||||||
|
hU = heightfield[x][y];
|
||||||
|
}
|
||||||
|
rVal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
rVal.normalize();
|
||||||
|
} else {
|
||||||
|
float hL;
|
||||||
|
if(x > 0){
|
||||||
|
hL = heightfield[x-1][y];
|
||||||
|
} else {
|
||||||
|
hL = heightfield[x][y];
|
||||||
|
}
|
||||||
|
float hR = heightfield[x+1][y];
|
||||||
|
float hD = heightfield[x][y];
|
||||||
|
float hU = heightfield[x][y-1];
|
||||||
|
rVal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
rVal.normalize();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(y / stride < actualHeight - 1){
|
||||||
|
float hL = heightfield[x-1][y];
|
||||||
|
float hR = heightfield[x][y];
|
||||||
|
float hD = heightfield[x][y+1];
|
||||||
|
float hU;
|
||||||
|
if(y > 0){
|
||||||
|
hU = heightfield[x][y-1];
|
||||||
|
} else {
|
||||||
|
hU = heightfield[x][y];
|
||||||
|
}
|
||||||
|
rVal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
rVal.normalize();
|
||||||
|
} else {
|
||||||
|
float hL = heightfield[x-1][y];
|
||||||
|
float hR = heightfield[x][y];
|
||||||
|
float hD = heightfield[x][y];
|
||||||
|
float hU = heightfield[x][y-1];
|
||||||
|
rVal = new Vector3f(hL - hR, 2.0f, hD - hU);
|
||||||
|
rVal.normalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user