<commit_before>package sed.sky;

import java.nio.ByteBuffer;

import org.apache.log4j.Logger;

import ssim.util.MathExt;

import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture2D;
import com.jme3.ui.Picture;
import com.jme3.util.BufferUtils;

/**
 * This processor hooks into the render process to use preFrame to render
 * the clouds.
 * 
 * @author cn
 */
public class CloudProcessor implements SceneProcessor {

    private static final Logger logger = Logger.getLogger(CloudProcessor.class);
    
    private static final int TexSize = 256;
    private static final int MaxSteps = 30;
    private static final int NumOctaves = 8;
    
    public enum Mode {
        /**
         * HeightField generation and rendering are done on CPU
         * (slow, fall back)
         */
        AllCPU,
        /**
         * HeightField generation is done on CPU, but rendering will be GPU task
         * (faster)
         */
        RenderGPU;
    }
    
    // state
    private boolean init = false;
    private float time = 0;
    private Mode mode;
    private float updateInterval; // in seconds
    
    // main part of final scene
    private AssetManager assetManager;
    private RenderManager renderManager;
    private ViewPort mainViewPort;
    
    // view ports
    private ViewPort tempViewPort;
    
    // textures
    private Texture2D heightFieldTex;
    private Texture2D cloudTex;
    
    // height field
    private CloudHeightField cloudHeightField;
    
    // (weather) variables
    private float cloudSharpness;
    private float wayFactor;
    private Vector3f sunPosition;
    private ColorRGBA sunLightColor;
    
    public CloudProcessor(AssetManager assetManager, Mode mode, float updateInterval) {
        this.assetManager = assetManager;
        this.mode = mode;
        this.updateInterval = updateInterval;
        
        heightFieldTex = new Texture2D(TexSize, TexSize, Format.RGBA8);
        cloudTex = new Texture2D(TexSize, TexSize, Format.RGBA8);
        
        cloudHeightField = new CloudHeightField(TexSize, NumOctaves);
    }
    
    // create heightfield (different algos: CPU GPU)
    // create pre-texture (different algos: CPU GPU [in mini scene with pre-appearance])
    // create final appearance -> done by user of this processor?
    
    @Override
    public void initialize(RenderManager rm, ViewPort vp) {
        renderManager = rm;
        mainViewPort = vp;
        
        if(mode == Mode.AllCPU) {
            // nothing
        } else {
            Camera cam = new Camera(TexSize, TexSize);
            
            tempViewPort = new ViewPort("Cloud-Render-ViewPort", cam);
            tempViewPort.setClearFlags(true, true, true);
            tempViewPort.setBackgroundColor(ColorRGBA.Black);
            
            FrameBuffer fb = new FrameBuffer(TexSize, TexSize, 1);
            fb.setColorTexture(cloudTex);
            
            // --- mini scene ---
            Picture quad = new Picture("Cloud-Render-Target");
            quad.setPosition(0, 0);
            quad.setWidth(TexSize);
            quad.setHeight(TexSize);
            
            // this shader does the real work... later
            //Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            //mat.setColor("Color", ColorRGBA.Orange.mult(new ColorRGBA(1f, 1f, 1f, 0.5f)));
            //mat.setTexture("ColorMap", heightFieldTex);
            Material mat = new Material(assetManager, "shaders/CloudRender.j3md");
            mat.setFloat("ImageSize", TexSize);
            mat.setFloat("MaxSteps", MaxSteps);
            mat.setFloat("CloudSharpness", cloudSharpness);
            mat.setFloat("WayFactor", wayFactor);
            mat.setVector3("SunPosition", sunPosition);
            mat.setColor("SunLightColor", sunLightColor);
            mat.setTexture("HeightField", heightFieldTex);
            quad.setMaterial(mat);
            quad.updateGeometricState();
            
            tempViewPort.attachScene(quad);
            tempViewPort.setOutputFrameBuffer(fb);
            // --- end ---
        }
        
        updateAndRender();
        init = true;
    }

    @Override
    public boolean isInitialized() {
        return init;
    }

    @Override
    public void preFrame(float tpf) {
        if(time >= updateInterval) {
            time -= updateInterval;
            updateAndRender();
        }
        time += tpf;
    }

    @Override
    public void postQueue(RenderQueue rq) {
        // nothing
    }

    @Override
    public void postFrame(FrameBuffer out) {
        // nothing
    }

    @Override
    public void reshape(ViewPort vp, int w, int h) {
        // nothing
    }

    @Override
    public void cleanup() {
        // nothing
        tempViewPort.clearScenes();
        tempViewPort.setOutputFrameBuffer(null);
        tempViewPort = null;
        cloudTex = null;
    }
    
    public float getCloudCover() {
        return cloudHeightField.getCloudCover();
    }

    public void setCloudCover(float cloudCover) {
        cloudHeightField.setCloudCover(cloudCover);
    }
    
    public Vector3f getShift() {
        return cloudHeightField.getShift();
    }
    
    public void setShift(Vector3f shift) {
        cloudHeightField.setShift(shift);
    }
    
    public float getZoom() {<commit_msg>Fix NPE in CloudProcessor.cleanup() preventing clean exit in AllCPU mode<commit_after>package sed.sky;

import java.nio.ByteBuffer;

import org.apache.log4j.Logger;

import ssim.util.MathExt;

import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture2D;
import com.jme3.ui.Picture;
import com.jme3.util.BufferUtils;

/**
 * This processor hooks into the render process to use preFrame to render
 * the clouds.
 * 
 * @author cn
 */
public class CloudProcessor implements SceneProcessor {

    private static final Logger logger = Logger.getLogger(CloudProcessor.class);
    
    private static final int TexSize = 256;
    private static final int MaxSteps = 30;
    private static final int NumOctaves = 8;
    
    public enum Mode {
        /**
         * HeightField generation and rendering are done on CPU
         * (slow, fall back)
         */
        AllCPU,
        /**
         * HeightField generation is done on CPU, but rendering will be GPU task
         * (faster)
         */
        RenderGPU;
    }
    
    // state
    private boolean init = false;
    private float time = 0;
    private Mode mode;
    private float updateInterval; // in seconds
    
    // main part of final scene
    private AssetManager assetManager;
    private RenderManager renderManager;
    private ViewPort mainViewPort;
    
    // view ports
    private ViewPort tempViewPort;
    
    // textures
    private Texture2D heightFieldTex;
    private Texture2D cloudTex;
    
    // height field
    private CloudHeightField cloudHeightField;
    
    // (weather) variables
    private float cloudSharpness;
    private float wayFactor;
    private Vector3f sunPosition;
    private ColorRGBA sunLightColor;
    
    public CloudProcessor(AssetManager assetManager, Mode mode, float updateInterval) {
        this.assetManager = assetManager;
        this.mode = mode;
        this.updateInterval = updateInterval;
        
        heightFieldTex = new Texture2D(TexSize, TexSize, Format.RGBA8);
        cloudTex = new Texture2D(TexSize, TexSize, Format.RGBA8);
        
        cloudHeightField = new CloudHeightField(TexSize, NumOctaves);
    }
    
    // create heightfield (different algos: CPU GPU)
    // create pre-texture (different algos: CPU GPU [in mini scene with pre-appearance])
    // create final appearance -> done by user of this processor?
    
    @Override
    public void initialize(RenderManager rm, ViewPort vp) {
        renderManager = rm;
        mainViewPort = vp;
        
        if(mode == Mode.AllCPU) {
            // nothing
        } else {
            Camera cam = new Camera(TexSize, TexSize);
            
            tempViewPort = new ViewPort("Cloud-Render-ViewPort", cam);
            tempViewPort.setClearFlags(true, true, true);
            tempViewPort.setBackgroundColor(ColorRGBA.Black);
            
            FrameBuffer fb = new FrameBuffer(TexSize, TexSize, 1);
            fb.setColorTexture(cloudTex);
            
            // --- mini scene ---
            Picture quad = new Picture("Cloud-Render-Target");
            quad.setPosition(0, 0);
            quad.setWidth(TexSize);
            quad.setHeight(TexSize);
            
            //Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
            //mat.setColor("Color", ColorRGBA.Orange.mult(new ColorRGBA(1f, 1f, 1f, 0.5f)));
            //mat.setTexture("ColorMap", heightFieldTex);
            Material mat = new Material(assetManager, "shaders/CloudRender.j3md");
            mat.setFloat("ImageSize", TexSize);
            mat.setFloat("MaxSteps", MaxSteps);
            mat.setFloat("CloudSharpness", cloudSharpness);
            mat.setFloat("WayFactor", wayFactor);
            mat.setVector3("SunPosition", sunPosition);
            mat.setColor("SunLightColor", sunLightColor);
            mat.setTexture("HeightField", heightFieldTex);
            quad.setMaterial(mat);
            quad.updateGeometricState();
            
            tempViewPort.attachScene(quad);
            tempViewPort.setOutputFrameBuffer(fb);
            // --- end ---
        }
        
        updateAndRender();
        init = true;
    }

    @Override
    public boolean isInitialized() {
        return init;
    }

    @Override
    public void preFrame(float tpf) {
        if(time >= updateInterval) {
            time -= updateInterval;
            updateAndRender();
        }
        time += tpf;
    }

    @Override
    public void postQueue(RenderQueue rq) {
        // nothing
    }

    @Override
    public void postFrame(FrameBuffer out) {
        // nothing
    }

    @Override
    public void reshape(ViewPort vp, int w, int h) {
        // nothing
    }

    @Override
    public void cleanup() {
        if(mode == Mode.AllCPU) {
            // nothing
        } else {
            tempViewPort.clearScenes();
            tempViewPort.setOutputFrameBuffer(null);
            tempViewPort = null;
        }
        heightFieldTex = null;
        cloudTex = null;
        cloudHeightField = null;
    }
    
    public float getCloudCover() {
        return cloudHeightField.getCloudCover();
    }

    public void setCloudCover(float cloudCover) {
        cloudHeightField.setCloudCover(cloudCover);
    }
    
    public Vector3f getShift() {
        return cloudHeightField.getShift();
    }
    
    public void setShift(Vector3f shift) {
        cloudHeightField.setShift(shift);
    }
    
    public float getZoom() {
{'fraction_non_alphanumeric': 0.09221329185031545, 'fraction_numerical': 0.007605219946417769, 'mean_word_length': 2.1852463528764106, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7225963', 'n_tokens_mistral': 3294, 'n_tokens_neox': 3214, 'n_words': 791}