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