package com.team.futurecraft.space; import static org.lwjgl.opengl.GL11.GL_CULL_FACE; import static org.lwjgl.opengl.GL11.GL_ONE; import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; import static org.lwjgl.opengl.GL11.GL_QUAD_STRIP; import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; import static org.lwjgl.opengl.GL11.GL_TRIANGLES; import static org.lwjgl.opengl.GL11.glBegin; import static org.lwjgl.opengl.GL11.glColor3f; import static org.lwjgl.opengl.GL11.glDisable; import static org.lwjgl.opengl.GL11.glEnd; import static org.lwjgl.opengl.GL11.glNormal3d; import static org.lwjgl.opengl.GL11.glRotatef; import static org.lwjgl.opengl.GL11.glScalef; import static org.lwjgl.opengl.GL11.glTexCoord2d; import static org.lwjgl.opengl.GL11.glTexCoord2f; import static org.lwjgl.opengl.GL11.glVertex2f; import static org.lwjgl.opengl.GL11.glVertex3d; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.nio.IntBuffer; import javax.imageio.ImageIO; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; import org.lwjgl.util.glu.GLU; import org.lwjgl.util.glu.Sphere; import com.team.futurecraft.Mat4f; import com.team.futurecraft.Vec3f; import com.team.futurecraft.Vec4f; import com.team.futurecraft.rendering.Camera; import com.team.futurecraft.rendering.Shader; import com.team.futurecraft.rendering.SpaceRenderer; import com.team.futurecraft.rendering.Textures; import net.minecraft.client.Minecraft; import net.minecraft.util.ResourceLocation; /** * Represents any planet (this includes moons too... there was no point making a Moon class... oh wait... I did... but that's THE moon). * * @author Joseph */ public abstract class Planet extends CelestialObject { public int[] turfmap; public int[] stonemap; /** The ring diameter (in kilometers)*/ public float ringSize = 0; public PlanetType type = new PlanetTypeFrozen(); public Vec4f atmosphere = new Vec4f(1, 1, 1, 0); private boolean hasSurfacemap = false; private boolean hasCloudmap = false; private boolean hasLightmap = false; private boolean hasOceanmap = false; private boolean hasRingmap = false; private IntBuffer intBuf; private String surfacePath; private String nightPath; private String oceanPath; private String cloudPath; private String ringPath; private Shader planetShader; private Shader atmosphereShader; private Shader cloudShader; private Shader ringShader; public Planet(CelestialObject parent) { super(parent); intBuf = BufferUtils.createIntBuffer(3); intBuf.put(0); intBuf.put(1); intBuf.put(2); intBuf.flip(); } public void init() { planetShader = Shader.loadShader("planet"); atmosphereShader = Shader.loadShader("atmosphere"); cloudShader = Shader.loadShader("clouds"); ringShader = Shader.loadShader("rings"); this.readColormap(); surfacePath = "textures/planets/" + this.name + "/surface.png"; nightPath = "textures/planets/" + this.name + "/night.png"; oceanPath = "textures/planets/" + this.name + "/ocean.png"; cloudPath = "textures/planets/" + this.name + "/clouds.png"; ringPath = "textures/planets/" + this.name + "/rings.png"; if (Textures.exists(surfacePath)) hasSurfacemap = true; if (Textures.exists(nightPath)) hasLightmap = true; if (Textures.exists(oceanPath)) hasOceanmap = true; if (Textures.exists(cloudPath)) hasCloudmap = true; if (Textures.exists(ringPath)) hasRingmap = true; super.init(); } /** * Internal stuff that sets up the terrain colormap */ private void readColormap() { InputStream in; BufferedImage image; String mapPath = "textures/planets/" + this.name + "/colormap.png"; if (Textures.exists(mapPath)) { try { in = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation("futurecraft", mapPath)).getInputStream(); image = ImageIO.read(in); AffineTransform transform = AffineTransform.getScaleInstance(1f, -1f); transform.translate(0, -image.getHeight()); AffineTransformOp operation = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); image = operation.filter(image, null); int height = image.getHeight(); int[] pixels = new int[height]; image.getRGB(0, 0, 1, height, pixels, 0, 1); turfmap = pixels; int[] pixels2 = new int[height]; image.getRGB(1, 0, 1, height, pixels2, 0, 1); stonemap = pixels2; } catch (IOException e) { turfmap = new int[] {0xFFFFFF}; } } else { turfmap = new int[] {0xFFFFFF}; } } /** * Tells everything that this is indeed a planet. */ public EnumCelestialType getType() { return EnumCelestialType.PLANET; } public boolean isLandable() { return true; } public boolean hasRings() { return false; } public float getNightMultiplier() { return 1.0f; } /** * Renders the planet by itself without calculating orbits or anything. * Used for rendering planets on gui buttons. */ public void renderStatic(Minecraft mc) { ResourceLocation img = new ResourceLocation("futurecraft", surfacePath); mc.getTextureManager().bindTexture(img); glColor3f(1, 1, 1); Sphere sphere = new Sphere(); sphere.setTextureFlag(true); sphere.draw(10, 25, 25); } private void bindTextures() { if (hasLightmap) { GL13.glActiveTexture(GL13.GL_TEXTURE2); Textures.loadTexture(nightPath); } else { GL13.glActiveTexture(GL13.GL_TEXTURE2); GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); } if (hasOceanmap) { GL13.glActiveTexture(GL13.GL_TEXTURE1); Textures.loadTexture(oceanPath); } else { GL13.glActiveTexture(GL13.GL_TEXTURE1); GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); } if (hasSurfacemap) { GL13.glActiveTexture(GL13.GL_TEXTURE0); Textures.loadTexture(surfacePath); } else { GL13.glActiveTexture(GL13.GL_TEXTURE1); GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); } } /** * This covers the render function from Celestial object. But if you have a SUPER * special planet, you could override it and have custom rendering. */ public void render(Camera cam, float time) { Vec3f PlanetPos = this.getPosition(time); this.renderChildren(cam, time); double distance = cam.pos.distanceTo(PlanetPos); int lod = 100; if (distance < 5) { //bind all the needed textures bindTextures(); Mat4f model = new Mat4f(); model = model.multiply(Mat4f.translate(PlanetPos.x - cam.pos.x, PlanetPos.y - cam.pos.y, PlanetPos.z - cam.pos.z)); model = model.multiply(Mat4f.rotate(this.physical.eqAscNode, 0F, 1F, 0F)); model = model.multiply(Mat4f.rotate(this.physical.obliquity, 0F, 0F, 1F)); model = model.multiply(Mat4f.rotate(90, 1F, 0F, 0F)); model = model.multiply(Mat4f.rotate(-90, 0F, 0F, 1F)); model = model.multiply(Mat4f.rotate(-(((time - this.orbit.epoch) / 86400) / this.physical.rotationPeriod * 360) - this.physical.rotationOffset, 0F, 0F, 1F)); Mat4f realModel = new Mat4f(); realModel = realModel.multiply(Mat4f.translate(PlanetPos.x, PlanetPos.y, PlanetPos.z)); realModel = realModel.multiply(Mat4f.rotate(this.physical.eqAscNode, 0F, 1F, 0F)); realModel = realModel.multiply(Mat4f.rotate(this.physical.obliquity, 0F, 0F, 1F)); realModel = realModel.multiply(Mat4f.rotate(90, 1F, 0F, 0F)); realModel = realModel.multiply(Mat4f.rotate(-90, 0F, 0F, 1F)); realModel = realModel.multiply(Mat4f.rotate(-(((time - this.orbit.epoch) / 86400) / this.physical.rotationPeriod * 360) - this.physical.rotationOffset, 0F, 0F, 1F)); planetShader.bind(); planetShader.uniformMat4(model, "model"); planetShader.uniformMat4(realModel, "realModel"); planetShader.uniformMat4(SpaceRenderer.getViewMatrix(new Vec3f(0, 0, 0), cam.rot), "view"); planetShader.uniformMat4(SpaceRenderer.getViewMatrix(cam.pos, cam.rot), "realView"); planetShader.uniformMat4(SpaceRenderer.getProjectionMatrix(), "projection"); planetShader.uniformVec3f(cam.pos, "eyePos"); planetShader.uniformVec3f(new Vec3f(atmosphere.x, atmosphere.y, atmosphere.z), "atmosphereColor"); planetShader.uniformFloat((float)atmosphere.w, "atmosphereDensity"); planetShader.uniformFloat(this.getNightMultiplier(), "nightMultiplier"); int uniform = GL20.glGetUniformLocation(planetShader.id, "texture"); GL20.glUniform1(uniform, intBuf); Sphere sphere = new Sphere(); sphere.setTextureFlag(true); sphere.draw((this.physical.diameter / 1000000) / 2, lod, lod); atmosphereShader.bind(); atmosphereShader.uniformMat4(model, "model"); atmosphereShader.uniformMat4(realModel, "realModel"); atmosphereShader.uniformMat4(SpaceRenderer.getViewMatrix(new Vec3f(0, 0, 0), cam.rot), "view"); atmosphereShader.uniformMat4(SpaceRenderer.getViewMatrix(cam.pos, cam.rot), "realView"); atmosphereShader.uniformMat4(SpaceRenderer.getProjectionMatrix(), "projection"); atmosphereShader.uniformVec3f(new Vec3f(atmosphere.x, atmosphere.y, atmosphere.z), "atmosphereColor"); atmosphereShader.uniformFloat((float)atmosphere.w, "atmosphereDensity"); atmosphereShader.uniformFloat(this.getNightMultiplier(), "nightMultiplier"); GL11.glBlendFunc(GL_ONE, GL_ONE); Sphere sphere2 = new Sphere(); sphere2.setTextureFlag(true); sphere2.setOrientation(GLU.GLU_INSIDE); sphere2.draw(((this.physical.diameter / 1000000) / 2) * 1.02f, lod, lod); GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (hasCloudmap) { cloudShader.bind(); cloudShader.uniformMat4(model, "model"); cloudShader.uniformMat4(realModel, "realModel"); cloudShader.uniformMat4(SpaceRenderer.getViewMatrix(new Vec3f(0, 0, 0), cam.rot), "view"); cloudShader.uniformMat4(SpaceRenderer.getViewMatrix(cam.pos, cam.rot), "realView"); cloudShader.uniformMat4(SpaceRenderer.getProjectionMatrix(), "projection"); cloudShader.uniformVec3f(new Vec3f(atmosphere.x, atmosphere.y, atmosphere.z), "atmosphereColor"); cloudShader.uniformFloat((float)atmosphere.w, "atmosphereDensity"); cloudShader.uniformFloat(this.getNightMultiplier(), "nightMultiplier"); Textures.loadTexture(cloudPath); Sphere sphere3 = new Sphere(); sphere3.setTextureFlag(true); sphere3.draw(((this.physical.diameter / 1000000) / 2) * 1.01f, lod, lod); } if (this.ringSize > 0 && this.hasRingmap) { ringShader.bind(); ringShader.uniformMat4(model, "model"); ringShader.uniformMat4(realModel, "realModel"); ringShader.uniformMat4(SpaceRenderer.getViewMatrix(new Vec3f(0, 0, 0), cam.rot), "view"); ringShader.uniformMat4(SpaceRenderer.getViewMatrix(cam.pos, cam.rot), "realView"); ringShader.uniformMat4(SpaceRenderer.getProjectionMatrix(), "projection"); Textures.loadTexture(this.ringPath); drawRing(0, this.ringSize / 1000000, 1, 300); } GL20.glUseProgram(0); } } @SuppressWarnings("unused") private void drawPlanet(float scale) { glDisable(GL_CULL_FACE); for (int i = 0; i < 6; i++) { if ( i == 1 ) glRotatef(90, 0, 1, 0); if ( i == 2 ) glRotatef(-90, 0, 1, 0); if ( i == 3 ) glRotatef(180, 0, 1, 0); if ( i == 4 ) glRotatef(90, 1, 0, 0); if ( i == 5 ) glRotatef(-90, 1, 0, 0); glScalef(scale - (1/5), scale - (1/5), scale - (1/5)); glBegin(GL_TRIANGLES); for (int x = -5; x < 5; x++) { for (int y = -5; y < 5; y++) { Vec3f corner1 = new Vec3f(x, y, 5).normalize(); Vec3f normal1 = new Vec3f(x, y, 5).normalize(); Vec3f corner2 = new Vec3f(x + 1, y, 5).normalize(); Vec3f normal2 = new Vec3f(x + 1, y, 5).normalize(); Vec3f corner3 = new Vec3f(x + 1, y + 1, 5).normalize(); Vec3f normal3 = new Vec3f(x + 1, y + 1, 5).normalize(); Vec3f corner4 = new Vec3f(x, y + 1, 5).normalize(); Vec3f normal4 = new Vec3f(x, y + 1, 5).normalize(); glVertex3d(corner1.x, corner1.y, corner1.z); glTexCoord2d(x + 5, y + 5); glNormal3d(-normal1.x, -normal1.y, -normal1.z); glVertex3d(corner2.x, corner2.y, corner2.z); glTexCoord2d(x + 5, y + 5); glNormal3d(-normal2.x, -normal2.y, -normal2.z); glVertex3d(corner3.x, corner3.y, corner3.z); glTexCoord2d(x + 5, y + 5); glNormal3d(-normal3.x, -normal3.y, -normal3.z); glVertex3d(corner1.x, corner1.y, corner1.z); glTexCoord2d(x + 5, y + 5); glNormal3d(-normal1.x, -normal1.y, -normal1.z); glVertex3d(corner3.x, corner3.y, corner3.z); glTexCoord2d(x + 5, y + 5); glNormal3d(-normal3.x, -normal3.y, -normal3.z); glVertex3d(corner4.x, corner4.y, corner4.z); glTexCoord2d(x + 5, y + 5); glNormal3d(-normal4.x, -normal4.y, -normal4.z); } } glEnd(); } } private void drawRing(float innerRadius, float outerRadius, int loops, int slices) { float da, dr; da = (float) (2.0f * Math.PI / slices); dr = (outerRadius - innerRadius) / loops; /* * texture of a gluDisk is a cut out of the texture unit square x, y in * [-outerRadius, +outerRadius]; s, t in [0, 1] (linear mapping) */ float sa, ca; float r1 = innerRadius; int l; for (l = 0; l < loops; l++) { float r2 = r1 + dr; if (true) { int s; glBegin(GL_QUAD_STRIP); for (s = 0; s <= slices; s++) { float a; if (s == slices) a = 0.0f; else a = s * da; sa = (float) Math.sin(a); ca = (float) Math.cos(a); glTexCoord2f(1, 0); glVertex2f(r2 * sa, r2 * ca); glTexCoord2f(0, 0); glVertex2f(r1 * sa, r1 * ca); } glEnd(); } if (true) { int s; glBegin(GL_QUAD_STRIP); for (s = slices; s >= 0; s--) { float a; if (s == slices) a = 0.0f; else a = s * da; sa = (float) Math.sin(a); ca = (float) Math.cos(a); glTexCoord2f(1, 0); glVertex2f(r2 * sa, r2 * ca); glTexCoord2f(0, 0); glVertex2f(r1 * sa, r1 * ca); } glEnd(); } r1 = r2; } } }