001package com.fs.starfarer.api.impl.campaign.terrain; 002 003import java.awt.Color; 004 005import org.lwjgl.opengl.GL11; 006import org.lwjgl.util.vector.Vector2f; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.graphics.SpriteAPI; 010import com.fs.starfarer.api.util.Misc; 011 012public class AuroraRenderer { 013 public static interface AuroraRendererDelegate { 014 float getAuroraInnerRadius(); 015 float getAuroraOuterRadius(); 016 Vector2f getAuroraCenterLoc(); 017 018 Color getAuroraColorForAngle(float angle); 019 float getAuroraAlphaMultForAngle(float angle); 020 021 float getAuroraShortenMult(float angle); 022 float getAuroraInnerOffsetMult(float angle); 023 024 float getAuroraThicknessMult(float angle); 025 float getAuroraThicknessFlat(float angle); 026 027 028 float getAuroraTexPerSegmentMult(); 029 float getAuroraBandWidthInTexture(); 030 031 SpriteAPI getAuroraTexture(); 032 RangeBlockerUtil getAuroraBlocker(); 033 } 034 035 private AuroraRendererDelegate delegate; 036 private float phaseAngle; 037 public AuroraRenderer(AuroraRendererDelegate delegate) { 038 this.delegate = delegate; 039 } 040 041 042 public void advance(float amount) { 043 float days = Global.getSector().getClock().convertToDays(amount); 044 phaseAngle += days * 360f * 0.5f; 045 phaseAngle = Misc.normalizeAngle(phaseAngle); 046 } 047 048 049 public void render(float alphaMult) { 050 if (alphaMult <= 0) return; 051 052 float bandWidthInTexture = delegate.getAuroraBandWidthInTexture(); 053 float bandIndex; 054 055 float radStart = delegate.getAuroraInnerRadius(); 056 float radEnd = delegate.getAuroraOuterRadius();; 057 058 if (radEnd < radStart + 10f) radEnd = radStart + 10f; 059 060 float circ = (float) (Math.PI * 2f * (radStart + radEnd) / 2f); 061 float pixelsPerSegment = 50f; 062 float segments = Math.round(circ / pixelsPerSegment); 063 064 float startRad = (float) Math.toRadians(0); 065 float endRad = (float) Math.toRadians(360f); 066 float spanRad = Math.abs(endRad - startRad); 067 float anglePerSegment = spanRad / segments; 068 069 Vector2f loc = delegate.getAuroraCenterLoc(); 070 float x = loc.x; 071 float y = loc.y; 072 073 074 GL11.glPushMatrix(); 075 GL11.glTranslatef(x, y, 0); 076 077 GL11.glEnable(GL11.GL_TEXTURE_2D); 078 //GL11.glDisable(GL11.GL_TEXTURE_2D); 079 080 delegate.getAuroraTexture().bindTexture(); 081 082 GL11.glEnable(GL11.GL_BLEND); 083 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); 084 085 float thickness = (radEnd - radStart) * 1f; 086 float radius = radStart; 087 088 float texProgress = 0f; 089 float texHeight = delegate.getAuroraTexture().getTextureHeight(); 090 float imageHeight = delegate.getAuroraTexture().getHeight(); 091 float texPerSegment = pixelsPerSegment * texHeight / imageHeight * bandWidthInTexture / thickness; 092 093 texPerSegment *= delegate.getAuroraTexPerSegmentMult(); 094 095 float totalTex = Math.max(1f, Math.round(texPerSegment * segments)); 096 texPerSegment = totalTex / segments; 097 098 float texWidth = delegate.getAuroraTexture().getTextureWidth(); 099 float imageWidth = delegate.getAuroraTexture().getWidth(); 100 101// GL11.glDisable(GL11.GL_TEXTURE_2D); 102// GL11.glDisable(GL11.GL_BLEND); 103// GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE); 104// GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); 105 106// CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 107// SectorEntityToken star = ((StarSystemAPI)playerFleet.getContainingLocation()).getStar(); 108// float distToStar = Misc.getDistance(playerFleet.getLocation(), star.getLocation());// - star.getRadius(); 109// System.out.println("Dist to outer star: " + distToStar); 110// System.out.println("Aurora outer: " + delegate.getAuroraOuterRadius()); 111 112 RangeBlockerUtil blocker = delegate.getAuroraBlocker(); 113 114 for (int iter = 0; iter < 2; iter++) { 115 if (iter == 0) { 116 bandIndex = 1; 117 } else { 118 bandIndex = 0; 119 } 120 121 float leftTX = (float) bandIndex * texWidth * bandWidthInTexture / imageWidth; 122 float rightTX = (float) (bandIndex + 1f) * texWidth * bandWidthInTexture / imageWidth - 0.001f; 123 124 GL11.glBegin(GL11.GL_QUAD_STRIP); 125 for (float i = 0; i < segments + 1; i++) { 126 127 float segIndex = i % (int) segments; 128 129 //float phaseAngleRad = (float) Math.toRadians(phaseAngle + segIndex * 10) + (segIndex * anglePerSegment * 10f); 130 float phaseAngleRad; 131 if (iter == 0) { 132 phaseAngleRad = (float) Math.toRadians(phaseAngle) + (segIndex * anglePerSegment * 10f); 133 } else { //if (iter == 1) { 134 phaseAngleRad = (float) Math.toRadians(-phaseAngle) + (segIndex * anglePerSegment * 5f); 135 } 136 137 138 float angle = (float) Math.toDegrees(segIndex * anglePerSegment); 139 if (iter == 1) angle += 180; 140 141 float blockerMax = 100000f; 142 if (blocker != null) { 143 blockerMax = blocker.getCurrMaxAt(angle); 144 //blockerMax *= 1.5f; 145 blockerMax *= 0.75f; 146 if (blockerMax > blocker.getMaxRange()) { 147 blockerMax = blocker.getMaxRange(); 148 } 149 //blockerMax += 1500f; 150 } 151 152 float pulseSin = (float) Math.sin(phaseAngleRad); 153 //if (delegate instanceof PulsarBeamTerrainPlugin) pulseSin += 1f; 154 float pulseMax = thickness * delegate.getAuroraShortenMult(angle); 155// if (pulseMax < 0) { 156// pulseMax = -pulseMax; 157// //pulseSin += 1f; 158// } 159 if (pulseMax > blockerMax * 0.5f) { 160 pulseMax = blockerMax * 0.5f; 161 } 162 float pulseAmount = pulseSin * pulseMax; 163 float pulseInner = pulseAmount * 0.1f; 164 pulseInner *= delegate.getAuroraInnerOffsetMult(angle); 165 //pulseInner *= Math.max(0, pulseSin - 0.5f); 166 //pulseInner *= 0f; 167 168 float r = radius; 169 170 float thicknessMult = delegate.getAuroraThicknessMult(angle); 171 float thicknessFlat = delegate.getAuroraThicknessFlat(angle); 172 173 float theta = anglePerSegment * segIndex;; 174 float cos = (float) Math.cos(theta); 175 float sin = (float) Math.sin(theta); 176 177 float rInner = r - pulseInner; 178 if (rInner < r * 0.9f) rInner = r * 0.9f; 179 180 float rOuter = (r + thickness * thicknessMult - pulseAmount + thicknessFlat); 181 182 if (blocker != null) { 183 if (rOuter > blockerMax - pulseAmount) { 184// float fraction = rOuter / (r + thickness * thicknessMult + thicknessFlat); 185// rOuter = blockerMax * fraction; 186 rOuter = blockerMax - pulseAmount; 187 //rOuter = blockerMax; 188 if (rOuter < r) rOuter = r; 189 } 190 if (rInner > rOuter) { 191 rInner = rOuter; 192 } 193 } 194 195 float x1 = cos * rInner; 196 float y1 = sin * rInner; 197 float x2 = cos * rOuter; 198 float y2 = sin * rOuter; 199 200 x2 += (float) (Math.cos(phaseAngleRad) * pixelsPerSegment * 0.33f); 201 y2 += (float) (Math.sin(phaseAngleRad) * pixelsPerSegment * 0.33f); 202 203 Color color = delegate.getAuroraColorForAngle(angle); 204 float alpha = delegate.getAuroraAlphaMultForAngle(angle); 205 if (blocker != null) { 206 alpha *= blocker.getAlphaAt(angle); 207 } 208// color = Color.white; 209// alphaMult = alpha = 1f; 210 GL11.glColor4ub((byte)color.getRed(), 211 (byte)color.getGreen(), 212 (byte)color.getBlue(), 213 (byte)((float) color.getAlpha() * alphaMult * alpha)); 214 215 GL11.glTexCoord2f(leftTX, texProgress); 216 GL11.glVertex2f(x1, y1); 217 GL11.glTexCoord2f(rightTX, texProgress); 218 GL11.glVertex2f(x2, y2); 219 220 texProgress += texPerSegment * 1f; 221 } 222 GL11.glEnd(); 223 224 GL11.glRotatef(180, 0, 0, 1); 225 } 226 GL11.glPopMatrix(); 227 228// GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); 229 } 230 231 232 233 public float getRenderDistMax(float angle) { 234 float radStart = delegate.getAuroraInnerRadius(); 235 float radEnd = delegate.getAuroraOuterRadius(); 236 if (radEnd < radStart + 10f) radEnd = radStart + 10f; 237 238 float angleRad = (float) Math.toRadians(angle); 239 240 float thickness = (radEnd - radStart) * 1f; 241 float radius = radStart; 242 RangeBlockerUtil blocker = delegate.getAuroraBlocker(); 243 244 float max = 0; 245 for (int i = 0; i < 2; i++) { 246 float phaseAngleRad; 247 if (i == 0) { 248 phaseAngleRad = (float) Math.toRadians(phaseAngle) + (angleRad * 10f); 249 } else { 250 phaseAngleRad = (float) Math.toRadians(-phaseAngle) + (angle * 5f); 251 angle += 180; 252 } 253 254 float blockerMax = 100000f; 255 if (blocker != null) { 256 blockerMax = blocker.getCurrMaxAt(angle); 257 blockerMax *= 1.5f; 258 if (blockerMax > blocker.getMaxRange()) { 259 blockerMax = blocker.getMaxRange(); 260 } 261 } 262 263 float pulseSin = (float) Math.sin(phaseAngleRad); 264 float pulseMax = thickness * delegate.getAuroraShortenMult(angle); 265 if (pulseMax > blockerMax * 0.5f) { 266 pulseMax = blockerMax * 0.5f; 267 } 268 float pulseAmount = pulseSin * pulseMax; 269 270 float thicknessMult = delegate.getAuroraThicknessMult(angle); 271 float thicknessFlat = delegate.getAuroraThicknessFlat(angle); 272 273 float rOuter = (radius + thickness * thicknessMult - pulseAmount + thicknessFlat); 274 275 if (blocker != null) { 276 if (rOuter > blockerMax - pulseAmount) { 277 rOuter = blockerMax - pulseAmount; 278 if (rOuter < radius) rOuter = radius; 279 } 280 } 281 if (rOuter > max) max = rOuter; 282 } 283 284 return max; 285 } 286 287} 288 289