From 22c77b954ce3efeab3986b4e2c0517a64d989fa6 Mon Sep 17 00:00:00 2001 From: "nor..67" Date: Thu, 13 Feb 2014 18:26:12 +0000 Subject: [PATCH] Update 3.0.5 - add pre-alpha ios renderer - fix FilterExplorer property updates - add support for blender 2.69 - prepare for new installer git-svn-id: https://jmonkeyengine.googlecode.com/svn/branches/3.0final@11043 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../jme3/font/plugins/BitmapFontLoader.java | 9 +- .../com/jme3/shader/plugins/GLSLLoader.java | 4 +- .../src/core/com/jme3/system/JmeVersion.java | 2 +- engine/src/ios/com/jme3/audio/android/AL.java | 1054 +++++++ .../jme3/audio/android/AndroidAudioData.java | 67 + .../audio/android/AndroidAudioRenderer.java | 24 + .../AndroidOpenALSoftAudioRenderer.java | 1423 +++++++++ .../audio/plugins/AndroidAudioLoader.java | 20 + .../renderer/ios/IGLESShaderRenderer.java | 2571 +++++++++++++++++ .../ios/com/jme3/renderer/ios/JmeIosGLES.java | 273 ++ .../com/jme3/renderer/ios/TextureUtil.java | 591 ++++ .../ios/com/jme3/system/ios/IGLESContext.java | 201 ++ .../com/jme3/system/ios/IosAssetManager.java | 5 +- .../ios/com/jme3/system/ios/IosHarness.java | 7 + .../ios/com/jme3/system/ios/JmeIosSystem.java | 5 +- .../src/com/jme3/gde/blender/BlenderTool.java | 5 +- .../filetypes/Blender3dsDataObject.java | 97 +- .../filetypes/BlenderFbxDataObject.java | 93 + .../com/jme3/gde/blender/scripts/Scripts.java | 1 + .../jme3/gde/blender/scripts/import_fbx.py | 83 + .../gde/core/filters/AbstractFilterNode.java | 19 +- .../blender-linux-x64/build.properties | 6 +- .../blender-linux-x86/build.properties | 6 +- .../products/blender-macosx/build.properties | 2 +- .../blender-windows-x64/build.properties | 4 +- .../blender-windows-x86/build.properties | 4 +- sdk/nbproject/project.properties | 2 +- 27 files changed, 6503 insertions(+), 75 deletions(-) create mode 100644 engine/src/ios/com/jme3/audio/android/AL.java create mode 100644 engine/src/ios/com/jme3/audio/android/AndroidAudioData.java create mode 100644 engine/src/ios/com/jme3/audio/android/AndroidAudioRenderer.java create mode 100644 engine/src/ios/com/jme3/audio/android/AndroidOpenALSoftAudioRenderer.java create mode 100644 engine/src/ios/com/jme3/audio/plugins/AndroidAudioLoader.java create mode 100644 engine/src/ios/com/jme3/renderer/ios/IGLESShaderRenderer.java create mode 100644 engine/src/ios/com/jme3/renderer/ios/JmeIosGLES.java create mode 100644 engine/src/ios/com/jme3/renderer/ios/TextureUtil.java create mode 100644 engine/src/ios/com/jme3/system/ios/IGLESContext.java create mode 100644 sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/BlenderFbxDataObject.java create mode 100644 sdk/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py diff --git a/engine/src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java b/engine/src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java index 5c4e89fc1..93d8bb5f0 100644 --- a/engine/src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java +++ b/engine/src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java @@ -43,23 +43,22 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; public class BitmapFontLoader implements AssetLoader { private BitmapFont load(AssetManager assetManager, String folder, InputStream in) throws IOException{ MaterialDef spriteMat = (MaterialDef) assetManager.loadAsset(new AssetKey("Common/MatDefs/Misc/Unshaded.j3md")); - BitmapCharacterSet charSet = new BitmapCharacterSet(); Material[] matPages = null; BitmapFont font = new BitmapFont(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - String regex = "[\\s=]+"; - + String regex = "[\\s=]+"; font.setCharSet(charSet); - while (reader.ready()){ - String line = reader.readLine(); + String line; + while ((line = reader.readLine())!=null){ String[] tokens = line.split(regex); if (tokens[0].equals("info")){ // Get rendered size diff --git a/engine/src/core-plugins/com/jme3/shader/plugins/GLSLLoader.java b/engine/src/core-plugins/com/jme3/shader/plugins/GLSLLoader.java index ce891df4b..fbd4d4b95 100644 --- a/engine/src/core-plugins/com/jme3/shader/plugins/GLSLLoader.java +++ b/engine/src/core-plugins/com/jme3/shader/plugins/GLSLLoader.java @@ -82,8 +82,8 @@ public class GLSLLoader implements AssetLoader { StringBuilder sb = new StringBuilder(); BufferedReader bufReader = new BufferedReader(reader); try { - while (bufReader.ready()) { - String ln = bufReader.readLine(); + String ln; + while ((ln = bufReader.readLine()) != null) { if (ln.trim().startsWith("#import ")) { ln = ln.trim().substring(8).trim(); if (ln.startsWith("\"") && ln.endsWith("\"") && ln.length() > 3) { diff --git a/engine/src/core/com/jme3/system/JmeVersion.java b/engine/src/core/com/jme3/system/JmeVersion.java index ba4c165af..615f697b2 100644 --- a/engine/src/core/com/jme3/system/JmeVersion.java +++ b/engine/src/core/com/jme3/system/JmeVersion.java @@ -32,5 +32,5 @@ package com.jme3.system; public class JmeVersion { - public static final String FULL_NAME = "jMonkeyEngine 3.0.4"; + public static final String FULL_NAME = "jMonkeyEngine 3.0.5"; } diff --git a/engine/src/ios/com/jme3/audio/android/AL.java b/engine/src/ios/com/jme3/audio/android/AL.java new file mode 100644 index 000000000..d8fea3933 --- /dev/null +++ b/engine/src/ios/com/jme3/audio/android/AL.java @@ -0,0 +1,1054 @@ +package com.jme3.audio.android; + +/** + * + * @author iwgeric + */ +public class AL { + + + + /* ********** */ + /* FROM ALC.h */ + /* ********** */ + +// typedef struct ALCdevice_struct ALCdevice; +// typedef struct ALCcontext_struct ALCcontext; + + + /** + * No error + */ + static final int ALC_NO_ERROR = 0; + + /** + * No device + */ + static final int ALC_INVALID_DEVICE = 0xA001; + + /** + * invalid context ID + */ + static final int ALC_INVALID_CONTEXT = 0xA002; + + /** + * bad enum + */ + static final int ALC_INVALID_ENUM = 0xA003; + + /** + * bad value + */ + static final int ALC_INVALID_VALUE = 0xA004; + + /** + * Out of memory. + */ + static final int ALC_OUT_OF_MEMORY = 0xA005; + + + /** + * The Specifier string for default device + */ + static final int ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004; + static final int ALC_DEVICE_SPECIFIER = 0x1005; + static final int ALC_EXTENSIONS = 0x1006; + + static final int ALC_MAJOR_VERSION = 0x1000; + static final int ALC_MINOR_VERSION = 0x1001; + + static final int ALC_ATTRIBUTES_SIZE = 0x1002; + static final int ALC_ALL_ATTRIBUTES = 0x1003; + + + /** + * Capture extension + */ + static final int ALC_EXT_CAPTURE = 1; + static final int ALC_CAPTURE_DEVICE_SPECIFIER = 0x310; + static final int ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311; + static final int ALC_CAPTURE_SAMPLES = 0x312; + + + /** + * ALC_ENUMERATE_ALL_EXT enums + */ + static final int ALC_ENUMERATE_ALL_EXT = 1; + static final int ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012; + static final int ALC_ALL_DEVICES_SPECIFIER = 0x1013; + + + /* ********** */ + /* FROM AL.h */ + /* ********** */ + +/** Boolean False. */ + static final int AL_FALSE = 0; + +/** Boolean True. */ + static final int AL_TRUE = 1; + +/* "no distance model" or "no buffer" */ + static final int AL_NONE = 0; + +/** Indicate Source has relative coordinates. */ + static final int AL_SOURCE_RELATIVE = 0x202; + + + +/** + * Directional source, inner cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ + static final int AL_CONE_INNER_ANGLE = 0x1001; + +/** + * Directional source, outer cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ + static final int AL_CONE_OUTER_ANGLE = 0x1002; + +/** + * Specify the pitch to be applied at source. + * Range: [0.5-2.0] + * Default: 1.0 + */ + static final int AL_PITCH = 0x1003; + +/** + * Specify the current location in three dimensional space. + * OpenAL, like OpenGL, uses a right handed coordinate system, + * where in a frontal default view X (thumb) points right, + * Y points up (index finger), and Z points towards the + * viewer/camera (middle finger). + * To switch from a left handed coordinate system, flip the + * sign on the Z coordinate. + * Listener position is always in the world coordinate system. + */ + static final int AL_POSITION = 0x1004; + +/** Specify the current direction. */ + static final int AL_DIRECTION = 0x1005; + +/** Specify the current velocity in three dimensional space. */ + static final int AL_VELOCITY = 0x1006; + +/** + * Indicate whether source is looping. + * Type: ALboolean? + * Range: [AL_TRUE, AL_FALSE] + * Default: FALSE. + */ + static final int AL_LOOPING = 0x1007; + +/** + * Indicate the buffer to provide sound samples. + * Type: ALuint. + * Range: any valid Buffer id. + */ + static final int AL_BUFFER = 0x1009; + +/** + * Indicate the gain (volume amplification) applied. + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * Each division by 2 equals an attenuation of -6dB. + * Each multiplicaton with 2 equals an amplification of +6dB. + * A value of 0.0 is meaningless with respect to a logarithmic + * scale; it is interpreted as zero volume - the channel + * is effectively disabled. + */ + static final int AL_GAIN = 0x100A; + +/* + * Indicate minimum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ + static final int AL_MIN_GAIN = 0x100D; + +/** + * Indicate maximum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ + static final int AL_MAX_GAIN = 0x100E; + +/** + * Indicate listener orientation. + * + * at/up + */ + static final int AL_ORIENTATION = 0x100F; + +/** + * Source state information. + */ + static final int AL_SOURCE_STATE = 0x1010; + static final int AL_INITIAL = 0x1011; + static final int AL_PLAYING = 0x1012; + static final int AL_PAUSED = 0x1013; + static final int AL_STOPPED = 0x1014; + +/** + * Buffer Queue params + */ + static final int AL_BUFFERS_QUEUED = 0x1015; + static final int AL_BUFFERS_PROCESSED = 0x1016; + +/** + * Source buffer position information + */ + static final int AL_SEC_OFFSET = 0x1024; + static final int AL_SAMPLE_OFFSET = 0x1025; + static final int AL_BYTE_OFFSET = 0x1026; + +/* + * Source type (Static, Streaming or undetermined) + * Source is Static if a Buffer has been attached using AL_BUFFER + * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers + * Source is undetermined when it has the NULL buffer attached + */ + static final int AL_SOURCE_TYPE = 0x1027; + static final int AL_STATIC = 0x1028; + static final int AL_STREAMING = 0x1029; + static final int AL_UNDETERMINED = 0x1030; + +/** Sound samples: format specifier. */ + static final int AL_FORMAT_MONO8 = 0x1100; + static final int AL_FORMAT_MONO16 = 0x1101; + static final int AL_FORMAT_STEREO8 = 0x1102; + static final int AL_FORMAT_STEREO16 = 0x1103; + +/** + * source specific reference distance + * Type: ALfloat + * Range: 0.0 - +inf + * + * At 0.0, no distance attenuation occurs. Default is + * 1.0. + */ + static final int AL_REFERENCE_DISTANCE = 0x1020; + +/** + * source specific rolloff factor + * Type: ALfloat + * Range: 0.0 - +inf + * + */ + static final int AL_ROLLOFF_FACTOR = 0x1021; + +/** + * Directional source, outer cone gain. + * + * Default: 0.0 + * Range: [0.0 - 1.0] + * Logarithmic + */ + static final int AL_CONE_OUTER_GAIN = 0x1022; + +/** + * Indicate distance above which sources are not + * attenuated using the inverse clamped distance model. + * + * Default: +inf + * Type: ALfloat + * Range: 0.0 - +inf + */ + static final int AL_MAX_DISTANCE = 0x1023; + +/** + * Sound samples: frequency, in units of Hertz [Hz]. + * This is the number of samples per second. Half of the + * sample frequency marks the maximum significant + * frequency component. + */ + static final int AL_FREQUENCY = 0x2001; + static final int AL_BITS = 0x2002; + static final int AL_CHANNELS = 0x2003; + static final int AL_SIZE = 0x2004; + +/** + * Buffer state. + * + * Not supported for public use (yet). + */ + static final int AL_UNUSED = 0x2010; + static final int AL_PENDING = 0x2011; + static final int AL_PROCESSED = 0x2012; + + +/** Errors: No Error. */ + static final int AL_NO_ERROR = 0; + +/** + * Invalid Name paramater passed to AL call. + */ + static final int AL_INVALID_NAME = 0xA001; + +/** + * Invalid parameter passed to AL call. + */ + static final int AL_INVALID_ENUM = 0xA002; + +/** + * Invalid enum parameter value. + */ + static final int AL_INVALID_VALUE = 0xA003; + +/** + * Illegal call. + */ + static final int AL_INVALID_OPERATION = 0xA004; + + +/** + * No mojo. + */ + static final int AL_OUT_OF_MEMORY = 0xA005; + + +/** Context strings: Vendor Name. */ + static final int AL_VENDOR = 0xB001; + static final int AL_VERSION = 0xB002; + static final int AL_RENDERER = 0xB003; + static final int AL_EXTENSIONS = 0xB004; + +/** Global tweakage. */ + +/** + * Doppler scale. Default 1.0 + */ + static final int AL_DOPPLER_FACTOR = 0xC000; + +/** + * Tweaks speed of propagation. + */ + static final int AL_DOPPLER_VELOCITY = 0xC001; + +/** + * Speed of Sound in units per second + */ + static final int AL_SPEED_OF_SOUND = 0xC003; + +/** + * Distance models + * + * used in conjunction with DistanceModel + * + * implicit: NONE, which disances distance attenuation. + */ + static final int AL_DISTANCE_MODEL = 0xD000; + static final int AL_INVERSE_DISTANCE = 0xD001; + static final int AL_INVERSE_DISTANCE_CLAMPED = 0xD002; + static final int AL_LINEAR_DISTANCE = 0xD003; + static final int AL_LINEAR_DISTANCE_CLAMPED = 0xD004; + static final int AL_EXPONENT_DISTANCE = 0xD005; + static final int AL_EXPONENT_DISTANCE_CLAMPED = 0xD006; + + /* ********** */ + /* FROM efx.h */ + /* ********** */ + + static final String ALC_EXT_EFX_NAME = "ALC_EXT_EFX"; + + static final int ALC_EFX_MAJOR_VERSION = 0x20001; + static final int ALC_EFX_MINOR_VERSION = 0x20002; + static final int ALC_MAX_AUXILIARY_SENDS = 0x20003; + + +///* Listener properties. */ +//#define AL_METERS_PER_UNIT 0x20004 +// +///* Source properties. */ + static final int AL_DIRECT_FILTER = 0x20005; + static final int AL_AUXILIARY_SEND_FILTER = 0x20006; +//#define AL_AIR_ABSORPTION_FACTOR 0x20007 +//#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +//#define AL_CONE_OUTER_GAINHF 0x20009 + static final int AL_DIRECT_FILTER_GAINHF_AUTO = 0x2000A; +//#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +//#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C +// +// +///* Effect properties. */ +// +///* Reverb effect parameters */ + static final int AL_REVERB_DENSITY = 0x0001; + static final int AL_REVERB_DIFFUSION = 0x0002; + static final int AL_REVERB_GAIN = 0x0003; + static final int AL_REVERB_GAINHF = 0x0004; + static final int AL_REVERB_DECAY_TIME = 0x0005; + static final int AL_REVERB_DECAY_HFRATIO = 0x0006; + static final int AL_REVERB_REFLECTIONS_GAIN = 0x0007; + static final int AL_REVERB_REFLECTIONS_DELAY = 0x0008; + static final int AL_REVERB_LATE_REVERB_GAIN = 0x0009; + static final int AL_REVERB_LATE_REVERB_DELAY = 0x000A; + static final int AL_REVERB_AIR_ABSORPTION_GAINHF = 0x000B; + static final int AL_REVERB_ROOM_ROLLOFF_FACTOR = 0x000C; + static final int AL_REVERB_DECAY_HFLIMIT = 0x000D; + +///* EAX Reverb effect parameters */ +//#define AL_EAXREVERB_DENSITY 0x0001 +//#define AL_EAXREVERB_DIFFUSION 0x0002 +//#define AL_EAXREVERB_GAIN 0x0003 +//#define AL_EAXREVERB_GAINHF 0x0004 +//#define AL_EAXREVERB_GAINLF 0x0005 +//#define AL_EAXREVERB_DECAY_TIME 0x0006 +//#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +//#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +//#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +//#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +//#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +//#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +//#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +//#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +//#define AL_EAXREVERB_ECHO_TIME 0x000F +//#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +//#define AL_EAXREVERB_MODULATION_TIME 0x0011 +//#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +//#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +//#define AL_EAXREVERB_HFREFERENCE 0x0014 +//#define AL_EAXREVERB_LFREFERENCE 0x0015 +//#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +//#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 +// +///* Chorus effect parameters */ +//#define AL_CHORUS_WAVEFORM 0x0001 +//#define AL_CHORUS_PHASE 0x0002 +//#define AL_CHORUS_RATE 0x0003 +//#define AL_CHORUS_DEPTH 0x0004 +//#define AL_CHORUS_FEEDBACK 0x0005 +//#define AL_CHORUS_DELAY 0x0006 +// +///* Distortion effect parameters */ +//#define AL_DISTORTION_EDGE 0x0001 +//#define AL_DISTORTION_GAIN 0x0002 +//#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +//#define AL_DISTORTION_EQCENTER 0x0004 +//#define AL_DISTORTION_EQBANDWIDTH 0x0005 +// +///* Echo effect parameters */ +//#define AL_ECHO_DELAY 0x0001 +//#define AL_ECHO_LRDELAY 0x0002 +//#define AL_ECHO_DAMPING 0x0003 +//#define AL_ECHO_FEEDBACK 0x0004 +//#define AL_ECHO_SPREAD 0x0005 +// +///* Flanger effect parameters */ +//#define AL_FLANGER_WAVEFORM 0x0001 +//#define AL_FLANGER_PHASE 0x0002 +//#define AL_FLANGER_RATE 0x0003 +//#define AL_FLANGER_DEPTH 0x0004 +//#define AL_FLANGER_FEEDBACK 0x0005 +//#define AL_FLANGER_DELAY 0x0006 +// +///* Frequency shifter effect parameters */ +//#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +//#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +//#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 +// +///* Vocal morpher effect parameters */ +//#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +//#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +//#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +//#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +//#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +//#define AL_VOCAL_MORPHER_RATE 0x0006 +// +///* Pitchshifter effect parameters */ +//#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +//#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 +// +///* Ringmodulator effect parameters */ +//#define AL_RING_MODULATOR_FREQUENCY 0x0001 +//#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +//#define AL_RING_MODULATOR_WAVEFORM 0x0003 +// +///* Autowah effect parameters */ +//#define AL_AUTOWAH_ATTACK_TIME 0x0001 +//#define AL_AUTOWAH_RELEASE_TIME 0x0002 +//#define AL_AUTOWAH_RESONANCE 0x0003 +//#define AL_AUTOWAH_PEAK_GAIN 0x0004 +// +///* Compressor effect parameters */ +//#define AL_COMPRESSOR_ONOFF 0x0001 +// +///* Equalizer effect parameters */ +//#define AL_EQUALIZER_LOW_GAIN 0x0001 +//#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +//#define AL_EQUALIZER_MID1_GAIN 0x0003 +//#define AL_EQUALIZER_MID1_CENTER 0x0004 +//#define AL_EQUALIZER_MID1_WIDTH 0x0005 +//#define AL_EQUALIZER_MID2_GAIN 0x0006 +//#define AL_EQUALIZER_MID2_CENTER 0x0007 +//#define AL_EQUALIZER_MID2_WIDTH 0x0008 +//#define AL_EQUALIZER_HIGH_GAIN 0x0009 +//#define AL_EQUALIZER_HIGH_CUTOFF 0x000A +// +///* Effect type */ +//#define AL_EFFECT_FIRST_PARAMETER 0x0000 +//#define AL_EFFECT_LAST_PARAMETER 0x8000 + static final int AL_EFFECT_TYPE = 0x8001; +// +///* Effect types, used with the AL_EFFECT_TYPE property */ +//#define AL_EFFECT_NULL 0x0000 + static final int AL_EFFECT_REVERB = 0x0001; +//#define AL_EFFECT_CHORUS 0x0002 +//#define AL_EFFECT_DISTORTION 0x0003 +//#define AL_EFFECT_ECHO 0x0004 +//#define AL_EFFECT_FLANGER 0x0005 +//#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +//#define AL_EFFECT_VOCAL_MORPHER 0x0007 +//#define AL_EFFECT_PITCH_SHIFTER 0x0008 +//#define AL_EFFECT_RING_MODULATOR 0x0009 +//#define AL_EFFECT_AUTOWAH 0x000A +//#define AL_EFFECT_COMPRESSOR 0x000B +//#define AL_EFFECT_EQUALIZER 0x000C +//#define AL_EFFECT_EAXREVERB 0x8000 +// +///* Auxiliary Effect Slot properties. */ + static final int AL_EFFECTSLOT_EFFECT = 0x0001; +//#define AL_EFFECTSLOT_GAIN 0x0002 +//#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 +// +///* NULL Auxiliary Slot ID to disable a source send. */ +//#define AL_EFFECTSLOT_NULL 0x0000 +// +// +///* Filter properties. */ +// +///* Lowpass filter parameters */ + static final int AL_LOWPASS_GAIN = 0x0001; + static final int AL_LOWPASS_GAINHF = 0x0002; +// +///* Highpass filter parameters */ +//#define AL_HIGHPASS_GAIN 0x0001 +//#define AL_HIGHPASS_GAINLF 0x0002 +// +///* Bandpass filter parameters */ +//#define AL_BANDPASS_GAIN 0x0001 +//#define AL_BANDPASS_GAINLF 0x0002 +//#define AL_BANDPASS_GAINHF 0x0003 +// +///* Filter type */ +//#define AL_FILTER_FIRST_PARAMETER 0x0000 +//#define AL_FILTER_LAST_PARAMETER 0x8000 + static final int AL_FILTER_TYPE = 0x8001; +// +///* Filter types, used with the AL_FILTER_TYPE property */ + static final int AL_FILTER_NULL = 0x0000; + static final int AL_FILTER_LOWPASS = 0x0001; + static final int AL_FILTER_HIGHPASS = 0x0002; +//#define AL_FILTER_BANDPASS 0x0003 +// +///* Filter ranges and defaults. */ +// +///* Lowpass filter */ +//#define AL_LOWPASS_MIN_GAIN (0.0f) +//#define AL_LOWPASS_MAX_GAIN (1.0f) +//#define AL_LOWPASS_DEFAULT_GAIN (1.0f) +// +//#define AL_LOWPASS_MIN_GAINHF (0.0f) +//#define AL_LOWPASS_MAX_GAINHF (1.0f) +//#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) +// +///* Highpass filter */ +//#define AL_HIGHPASS_MIN_GAIN (0.0f) +//#define AL_HIGHPASS_MAX_GAIN (1.0f) +//#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) +// +//#define AL_HIGHPASS_MIN_GAINLF (0.0f) +//#define AL_HIGHPASS_MAX_GAINLF (1.0f) +//#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) +// +///* Bandpass filter */ +//#define AL_BANDPASS_MIN_GAIN (0.0f) +//#define AL_BANDPASS_MAX_GAIN (1.0f) +//#define AL_BANDPASS_DEFAULT_GAIN (1.0f) +// +//#define AL_BANDPASS_MIN_GAINHF (0.0f) +//#define AL_BANDPASS_MAX_GAINHF (1.0f) +//#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) +// +//#define AL_BANDPASS_MIN_GAINLF (0.0f) +//#define AL_BANDPASS_MAX_GAINLF (1.0f) +//#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) +// +// +///* Effect parameter ranges and defaults. */ +// +///* Standard reverb effect */ +//#define AL_REVERB_MIN_DENSITY (0.0f) +//#define AL_REVERB_MAX_DENSITY (1.0f) +//#define AL_REVERB_DEFAULT_DENSITY (1.0f) +// +//#define AL_REVERB_MIN_DIFFUSION (0.0f) +//#define AL_REVERB_MAX_DIFFUSION (1.0f) +//#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) +// +//#define AL_REVERB_MIN_GAIN (0.0f) +//#define AL_REVERB_MAX_GAIN (1.0f) +//#define AL_REVERB_DEFAULT_GAIN (0.32f) +// +//#define AL_REVERB_MIN_GAINHF (0.0f) +//#define AL_REVERB_MAX_GAINHF (1.0f) +//#define AL_REVERB_DEFAULT_GAINHF (0.89f) +// +//#define AL_REVERB_MIN_DECAY_TIME (0.1f) +//#define AL_REVERB_MAX_DECAY_TIME (20.0f) +//#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) +// +//#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +//#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +//#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) +// +//#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +//#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +//#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) +// +//#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +//#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +//#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) +// +//#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +//#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +//#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) +// +//#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +//#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +//#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) +// +//#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +//#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +//#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) +// +//#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +//#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +//#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) +// +//#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +//#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +//#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE +// +///* EAX reverb effect */ +//#define AL_EAXREVERB_MIN_DENSITY (0.0f) +//#define AL_EAXREVERB_MAX_DENSITY (1.0f) +//#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) +// +//#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +//#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +//#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) +// +//#define AL_EAXREVERB_MIN_GAIN (0.0f) +//#define AL_EAXREVERB_MAX_GAIN (1.0f) +//#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) +// +//#define AL_EAXREVERB_MIN_GAINHF (0.0f) +//#define AL_EAXREVERB_MAX_GAINHF (1.0f) +//#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) +// +//#define AL_EAXREVERB_MIN_GAINLF (0.0f) +//#define AL_EAXREVERB_MAX_GAINLF (1.0f) +//#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) +// +//#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +//#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +//#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) +// +//#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +//#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +//#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) +// +//#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +//#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +//#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) +// +//#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +//#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +//#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) +// +//#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +//#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +//#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) +// +//#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) +// +//#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +//#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +//#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) +// +//#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +//#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +//#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) +// +//#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) +// +//#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +//#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +//#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) +// +//#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +//#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +//#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) +// +//#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +//#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +//#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) +// +//#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +//#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +//#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) +// +//#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +//#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +//#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) +// +//#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +//#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +//#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) +// +//#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +//#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +//#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) +// +//#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +//#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +//#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) +// +//#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +//#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +//#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE +// +///* Chorus effect */ +//#define AL_CHORUS_WAVEFORM_SINUSOID (0) +//#define AL_CHORUS_WAVEFORM_TRIANGLE (1) +// +//#define AL_CHORUS_MIN_WAVEFORM (0) +//#define AL_CHORUS_MAX_WAVEFORM (1) +//#define AL_CHORUS_DEFAULT_WAVEFORM (1) +// +//#define AL_CHORUS_MIN_PHASE (-180) +//#define AL_CHORUS_MAX_PHASE (180) +//#define AL_CHORUS_DEFAULT_PHASE (90) +// +//#define AL_CHORUS_MIN_RATE (0.0f) +//#define AL_CHORUS_MAX_RATE (10.0f) +//#define AL_CHORUS_DEFAULT_RATE (1.1f) +// +//#define AL_CHORUS_MIN_DEPTH (0.0f) +//#define AL_CHORUS_MAX_DEPTH (1.0f) +//#define AL_CHORUS_DEFAULT_DEPTH (0.1f) +// +//#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +//#define AL_CHORUS_MAX_FEEDBACK (1.0f) +//#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) +// +//#define AL_CHORUS_MIN_DELAY (0.0f) +//#define AL_CHORUS_MAX_DELAY (0.016f) +//#define AL_CHORUS_DEFAULT_DELAY (0.016f) +// +///* Distortion effect */ +//#define AL_DISTORTION_MIN_EDGE (0.0f) +//#define AL_DISTORTION_MAX_EDGE (1.0f) +//#define AL_DISTORTION_DEFAULT_EDGE (0.2f) +// +//#define AL_DISTORTION_MIN_GAIN (0.01f) +//#define AL_DISTORTION_MAX_GAIN (1.0f) +//#define AL_DISTORTION_DEFAULT_GAIN (0.05f) +// +//#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +//#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +//#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) +// +//#define AL_DISTORTION_MIN_EQCENTER (80.0f) +//#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +//#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) +// +//#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +//#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +//#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) +// +///* Echo effect */ +//#define AL_ECHO_MIN_DELAY (0.0f) +//#define AL_ECHO_MAX_DELAY (0.207f) +//#define AL_ECHO_DEFAULT_DELAY (0.1f) +// +//#define AL_ECHO_MIN_LRDELAY (0.0f) +//#define AL_ECHO_MAX_LRDELAY (0.404f) +//#define AL_ECHO_DEFAULT_LRDELAY (0.1f) +// +//#define AL_ECHO_MIN_DAMPING (0.0f) +//#define AL_ECHO_MAX_DAMPING (0.99f) +//#define AL_ECHO_DEFAULT_DAMPING (0.5f) +// +//#define AL_ECHO_MIN_FEEDBACK (0.0f) +//#define AL_ECHO_MAX_FEEDBACK (1.0f) +//#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) +// +//#define AL_ECHO_MIN_SPREAD (-1.0f) +//#define AL_ECHO_MAX_SPREAD (1.0f) +//#define AL_ECHO_DEFAULT_SPREAD (-1.0f) +// +///* Flanger effect */ +//#define AL_FLANGER_WAVEFORM_SINUSOID (0) +//#define AL_FLANGER_WAVEFORM_TRIANGLE (1) +// +//#define AL_FLANGER_MIN_WAVEFORM (0) +//#define AL_FLANGER_MAX_WAVEFORM (1) +//#define AL_FLANGER_DEFAULT_WAVEFORM (1) +// +//#define AL_FLANGER_MIN_PHASE (-180) +//#define AL_FLANGER_MAX_PHASE (180) +//#define AL_FLANGER_DEFAULT_PHASE (0) +// +//#define AL_FLANGER_MIN_RATE (0.0f) +//#define AL_FLANGER_MAX_RATE (10.0f) +//#define AL_FLANGER_DEFAULT_RATE (0.27f) +// +//#define AL_FLANGER_MIN_DEPTH (0.0f) +//#define AL_FLANGER_MAX_DEPTH (1.0f) +//#define AL_FLANGER_DEFAULT_DEPTH (1.0f) +// +//#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +//#define AL_FLANGER_MAX_FEEDBACK (1.0f) +//#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) +// +//#define AL_FLANGER_MIN_DELAY (0.0f) +//#define AL_FLANGER_MAX_DELAY (0.004f) +//#define AL_FLANGER_DEFAULT_DELAY (0.002f) +// +///* Frequency shifter effect */ +//#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +//#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +//#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) +// +//#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +//#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +//#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) +// +//#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +//#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +//#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) +// +//#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +//#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +//#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) +// +///* Vocal morpher effect */ +//#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +//#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +//#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) +// +//#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +//#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +//#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) +// +//#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +//#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +//#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) +// +//#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +//#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +//#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) +// +//#define AL_VOCAL_MORPHER_PHONEME_A (0) +//#define AL_VOCAL_MORPHER_PHONEME_E (1) +//#define AL_VOCAL_MORPHER_PHONEME_I (2) +//#define AL_VOCAL_MORPHER_PHONEME_O (3) +//#define AL_VOCAL_MORPHER_PHONEME_U (4) +//#define AL_VOCAL_MORPHER_PHONEME_AA (5) +//#define AL_VOCAL_MORPHER_PHONEME_AE (6) +//#define AL_VOCAL_MORPHER_PHONEME_AH (7) +//#define AL_VOCAL_MORPHER_PHONEME_AO (8) +//#define AL_VOCAL_MORPHER_PHONEME_EH (9) +//#define AL_VOCAL_MORPHER_PHONEME_ER (10) +//#define AL_VOCAL_MORPHER_PHONEME_IH (11) +//#define AL_VOCAL_MORPHER_PHONEME_IY (12) +//#define AL_VOCAL_MORPHER_PHONEME_UH (13) +//#define AL_VOCAL_MORPHER_PHONEME_UW (14) +//#define AL_VOCAL_MORPHER_PHONEME_B (15) +//#define AL_VOCAL_MORPHER_PHONEME_D (16) +//#define AL_VOCAL_MORPHER_PHONEME_F (17) +//#define AL_VOCAL_MORPHER_PHONEME_G (18) +//#define AL_VOCAL_MORPHER_PHONEME_J (19) +//#define AL_VOCAL_MORPHER_PHONEME_K (20) +//#define AL_VOCAL_MORPHER_PHONEME_L (21) +//#define AL_VOCAL_MORPHER_PHONEME_M (22) +//#define AL_VOCAL_MORPHER_PHONEME_N (23) +//#define AL_VOCAL_MORPHER_PHONEME_P (24) +//#define AL_VOCAL_MORPHER_PHONEME_R (25) +//#define AL_VOCAL_MORPHER_PHONEME_S (26) +//#define AL_VOCAL_MORPHER_PHONEME_T (27) +//#define AL_VOCAL_MORPHER_PHONEME_V (28) +//#define AL_VOCAL_MORPHER_PHONEME_Z (29) +// +//#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +//#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +//#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) +// +//#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +//#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +//#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) +// +//#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +//#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +//#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) +// +///* Pitch shifter effect */ +//#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +//#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +//#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) +// +//#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +//#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +//#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) +// +///* Ring modulator effect */ +//#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +//#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +//#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) +// +//#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +//#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +//#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) +// +//#define AL_RING_MODULATOR_SINUSOID (0) +//#define AL_RING_MODULATOR_SAWTOOTH (1) +//#define AL_RING_MODULATOR_SQUARE (2) +// +//#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +//#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +//#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) +// +///* Autowah effect */ +//#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +//#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +//#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) +// +//#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +//#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +//#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) +// +//#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +//#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +//#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) +// +//#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +//#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +//#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) +// +///* Compressor effect */ +//#define AL_COMPRESSOR_MIN_ONOFF (0) +//#define AL_COMPRESSOR_MAX_ONOFF (1) +//#define AL_COMPRESSOR_DEFAULT_ONOFF (1) +// +///* Equalizer effect */ +//#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +//#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +//#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) +// +//#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +//#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +//#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) +// +//#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +//#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +//#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) +// +//#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +//#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +//#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) +// +//#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +//#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +//#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) +// +//#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +//#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +//#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) +// +//#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +//#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +//#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) +// +//#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +//#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +//#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) +// +//#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +//#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +//#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) +// +//#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +//#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +//#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) +// +// +///* Source parameter value ranges and defaults. */ +//#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +//#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +//#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) +// +//#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +//#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +//#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) +// +//#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +//#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +//#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) +// +//#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +//#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +//#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +// +//#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +//#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +//#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +// +//#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +//#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +//#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +// +// +///* Listener parameter value ranges and defaults. */ +//#define AL_MIN_METERS_PER_UNIT FLT_MIN +//#define AL_MAX_METERS_PER_UNIT FLT_MAX +//#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + + public static String GetALErrorMsg(int errorCode) { + String errorText; + switch (errorCode) { + case AL_NO_ERROR: + errorText = "No Error"; + break; + case AL_INVALID_NAME: + errorText = "Invalid Name"; + break; + case AL_INVALID_ENUM: + errorText = "Invalid Enum"; + break; + case AL_INVALID_VALUE: + errorText = "Invalid Value"; + break; + case AL_INVALID_OPERATION: + errorText = "Invalid Operation"; + break; + case AL_OUT_OF_MEMORY: + errorText = "Out of Memory"; + break; + default: + errorText = "Unknown Error Code: " + String.valueOf(errorCode); + } + return errorText; + } +} + diff --git a/engine/src/ios/com/jme3/audio/android/AndroidAudioData.java b/engine/src/ios/com/jme3/audio/android/AndroidAudioData.java new file mode 100644 index 000000000..e7f4a0f98 --- /dev/null +++ b/engine/src/ios/com/jme3/audio/android/AndroidAudioData.java @@ -0,0 +1,67 @@ +package com.jme3.audio.android; + +import com.jme3.asset.AssetKey; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioRenderer; +import com.jme3.util.NativeObject; + +public class AndroidAudioData extends AudioData { + + protected AssetKey assetKey; + protected float currentVolume = 0f; + + public AndroidAudioData(){ + super(); + } + + protected AndroidAudioData(int id){ + super(id); + } + + public AssetKey getAssetKey() { + return assetKey; + } + + public void setAssetKey(AssetKey assetKey) { + this.assetKey = assetKey; + } + + @Override + public DataType getDataType() { + return DataType.Buffer; + } + + @Override + public float getDuration() { + return 0; // TODO: ??? + } + + @Override + public void resetObject() { + this.id = -1; + setUpdateNeeded(); + } + + @Override + public void deleteObject(Object rendererObject) { + ((AudioRenderer)rendererObject).deleteAudioData(this); + } + + public float getCurrentVolume() { + return currentVolume; + } + + public void setCurrentVolume(float currentVolume) { + this.currentVolume = currentVolume; + } + + @Override + public NativeObject createDestructableClone() { + return new AndroidAudioData(id); + } + + @Override + public long getUniqueId() { + return ((long)OBJTYPE_AUDIOBUFFER << 32) | ((long)id); + } +} diff --git a/engine/src/ios/com/jme3/audio/android/AndroidAudioRenderer.java b/engine/src/ios/com/jme3/audio/android/AndroidAudioRenderer.java new file mode 100644 index 000000000..0cde16aa5 --- /dev/null +++ b/engine/src/ios/com/jme3/audio/android/AndroidAudioRenderer.java @@ -0,0 +1,24 @@ +package com.jme3.audio.android; + +import com.jme3.audio.AudioRenderer; + +/** + * Android specific AudioRenderer interface that supports pausing and resuming + * audio files when the app is minimized or placed in the background + * + * @author iwgeric + */ +public interface AndroidAudioRenderer extends AudioRenderer { + + /** + * Pauses all Playing audio. To be used when the app is placed in the + * background. + */ + public void pauseAll(); + + /** + * Resumes all Paused audio. To be used when the app is brought back to + * the foreground. + */ + public void resumeAll(); +} diff --git a/engine/src/ios/com/jme3/audio/android/AndroidOpenALSoftAudioRenderer.java b/engine/src/ios/com/jme3/audio/android/AndroidOpenALSoftAudioRenderer.java new file mode 100644 index 000000000..07591a425 --- /dev/null +++ b/engine/src/ios/com/jme3/audio/android/AndroidOpenALSoftAudioRenderer.java @@ -0,0 +1,1423 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.audio.android; + +import com.jme3.audio.*; +import com.jme3.audio.AudioSource.Status; +import com.jme3.math.Vector3f; +import com.jme3.util.BufferUtils; +import com.jme3.util.NativeObjectManager; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class AndroidOpenALSoftAudioRenderer implements AndroidAudioRenderer, Runnable { + + private static final Logger logger = Logger.getLogger(AndroidOpenALSoftAudioRenderer.class.getName()); + private final NativeObjectManager objManager = new NativeObjectManager(); + // When multiplied by STREAMING_BUFFER_COUNT, will equal 44100 * 2 * 2 + // which is exactly 1 second of audio. + private static final int BUFFER_SIZE = 35280; + private static final int STREAMING_BUFFER_COUNT = 5; + private final static int MAX_NUM_CHANNELS = 64; + private IntBuffer ib = BufferUtils.createIntBuffer(1); + private final FloatBuffer fb = BufferUtils.createVector3Buffer(2); + private final ByteBuffer nativeBuf = BufferUtils.createByteBuffer(BUFFER_SIZE); + private final byte[] arrayBuf = new byte[BUFFER_SIZE]; + private int[] channels; + private AudioSource[] chanSrcs; + private int nextChan = 0; + private ArrayList freeChans = new ArrayList(); + private Listener listener; + private boolean audioDisabled = false; + private boolean supportEfx = false; + private int auxSends = 0; + private int reverbFx = -1; + private int reverbFxSlot = -1; + // Update audio 20 times per second + private static final float UPDATE_RATE = 0.05f; + private final Thread audioThread = new Thread(this, "jME3 Audio Thread"); + private final AtomicBoolean threadLock = new AtomicBoolean(false); + private boolean initialized = false; + + public AndroidOpenALSoftAudioRenderer() { + } + + public void initialize() { + if (!audioThread.isAlive()) { + audioThread.setDaemon(true); + audioThread.setPriority(Thread.NORM_PRIORITY + 1); + audioThread.start(); + } else { + throw new IllegalStateException("Initialize already called"); + } + } + + private void checkDead() { + if (audioThread.getState() == Thread.State.TERMINATED) { + throw new IllegalStateException("Audio thread is terminated"); + } + } + + public void run() { + initInThread(); + synchronized (threadLock) { + threadLock.set(true); + threadLock.notifyAll(); + } + + initialized = true; + + long updateRateNanos = (long) (UPDATE_RATE * 1000000000); + mainloop: + while (true) { + long startTime = System.nanoTime(); + + if (Thread.interrupted()) { + break; + } + + synchronized (threadLock) { + updateInThread(UPDATE_RATE); + } + + long endTime = System.nanoTime(); + long diffTime = endTime - startTime; + + if (diffTime < updateRateNanos) { + long desiredEndTime = startTime + updateRateNanos; + while (System.nanoTime() < desiredEndTime) { + try { + Thread.sleep(1); + } catch (InterruptedException ex) { + break mainloop; + } + } + } + } + + initialized = false; + + synchronized (threadLock) { + cleanupInThread(); + } + } + + public void initInThread() { + try { + if (!alIsCreated()) { + //AL.create(); + alCreate(); + checkError(false); + } +// } catch (OpenALException ex) { +// logger.log(Level.SEVERE, "Failed to load audio library", ex); +// audioDisabled = true; +// return; +// } catch (LWJGLException ex) { +// logger.log(Level.SEVERE, "Failed to load audio library", ex); +// audioDisabled = true; +// return; + } catch (UnsatisfiedLinkError ex) { + logger.log(Level.SEVERE, "Failed to load audio library", ex); + audioDisabled = true; + return; + } + + //ALCdevice device = AL.getDevice(); /* device maintained in jni */ + //String deviceName = ALC10.alcGetString(device, ALC10.ALC_DEVICE_SPECIFIER); + String deviceName = alcGetString(AL.ALC_DEVICE_SPECIFIER); + + logger.log(Level.INFO, "Audio Device: {0}", deviceName); + //logger.log(Level.INFO, "Audio Vendor: {0}", alGetString(AL_VENDOR)); + //logger.log(Level.INFO, "Audio Renderer: {0}", alGetString(AL_RENDERER)); + //logger.log(Level.INFO, "Audio Version: {0}", alGetString(AL_VERSION)); + logger.log(Level.INFO, "Audio Vendor: {0}", alGetString(AL.AL_VENDOR)); + logger.log(Level.INFO, "Audio Renderer: {0}", alGetString(AL.AL_RENDERER)); + logger.log(Level.INFO, "Audio Version: {0}", alGetString(AL.AL_VERSION)); + + // Find maximum # of sources supported by this implementation + ArrayList channelList = new ArrayList(); + for (int i = 0; i < MAX_NUM_CHANNELS; i++) { + int chan = alGenSources(); + //if (alGetError() != 0) { + if (checkError(false) != 0) { + break; + } else { + channelList.add(chan); + } + } + + channels = new int[channelList.size()]; + for (int i = 0; i < channels.length; i++) { + channels[i] = channelList.get(i); + } + + ib = BufferUtils.createIntBuffer(channels.length); + chanSrcs = new AudioSource[channels.length]; + + logger.log(Level.INFO, "AudioRenderer supports {0} channels", channels.length); + + //supportEfx = alcIsExtensionPresent(device, "ALC_EXT_EFX"); + supportEfx = alcIsExtensionPresent(AL.ALC_EXT_EFX_NAME); + + if (supportEfx) { + ib.position(0).limit(1); + //ALC10.alcGetInteger(device, EFX10.ALC_EFX_MAJOR_VERSION, ib); + alcGetInteger(AL.ALC_EFX_MAJOR_VERSION, ib, 1); + int major = ib.get(0); + ib.position(0).limit(1); + //ALC10.alcGetInteger(device, EFX10.ALC_EFX_MINOR_VERSION, ib); + alcGetInteger(AL.ALC_EFX_MINOR_VERSION, ib, 1); + int minor = ib.get(0); + logger.log(Level.INFO, "Audio effect extension version: {0}.{1}", new Object[]{major, minor}); + + //ALC10.alcGetInteger(device, EFX10.ALC_MAX_AUXILIARY_SENDS, ib); + alcGetInteger(AL.ALC_MAX_AUXILIARY_SENDS, ib, 1); + auxSends = ib.get(0); + logger.log(Level.INFO, "Audio max auxilary sends: {0}", auxSends); + + // create slot + ib.position(0).limit(1); + //EFX10.alGenAuxiliaryEffectSlots(ib); + alGenAuxiliaryEffectSlots(1, ib); + reverbFxSlot = ib.get(0); + + // create effect + ib.position(0).limit(1); + //EFX10.alGenEffects(ib); + alGenEffects(1, ib); + reverbFx = ib.get(0); + //EFX10.alEffecti(reverbFx, EFX10.AL_EFFECT_TYPE, EFX10.AL_EFFECT_REVERB); + alEffecti(reverbFx, AL.AL_EFFECT_TYPE, AL.AL_EFFECT_REVERB); + + // attach reverb effect to effect slot + //EFX10.alAuxiliaryEffectSloti(reverbFxSlot, EFX10.AL_EFFECTSLOT_EFFECT, reverbFx); + alAuxiliaryEffectSloti(reverbFxSlot, AL.AL_EFFECTSLOT_EFFECT, reverbFx); + } else { + logger.log(Level.WARNING, "OpenAL EFX not available! Audio effects won't work."); + } + } + + public void cleanupInThread() { + if (audioDisabled) { + //AL.destroy(); + alDestroy(); + checkError(true); + return; + } + + // stop any playing channels + for (int i = 0; i < chanSrcs.length; i++) { + if (chanSrcs[i] != null) { + clearChannel(i); + } + } + + // delete channel-based sources + ib.clear(); + ib.put(channels); + ib.flip(); + //alDeleteSources(ib); + alDeleteSources(channels.length, ib); + checkError(true); + + // delete audio buffers and filters + objManager.deleteAllObjects(this); + + if (supportEfx) { + ib.position(0).limit(1); + ib.put(0, reverbFx); + //EFX10.alDeleteEffects(ib); + alDeleteEffects(1, ib); + + // If this is not allocated, why is it deleted? + // Commented out to fix native crash in OpenAL. + ib.position(0).limit(1); + ib.put(0, reverbFxSlot); + //EFX10.alDeleteAuxiliaryEffectSlots(ib); + alDeleteAuxiliaryEffectSlots(1, ib); + } + + //AL.destroy(); + logger.log(Level.INFO, "Destroying OpenAL Soft Renderer"); + alDestroy(); + } + + public void cleanup() { + // kill audio thread + if (audioThread.isAlive()) { + audioThread.interrupt(); + } + } + + private void updateFilter(Filter f) { + int id = f.getId(); + if (id == -1) { + ib.position(0).limit(1); + //EFX10.alGenFilters(ib); + alGenFilters(1, ib); + id = ib.get(0); + f.setId(id); + + objManager.registerObject(f); + } + + if (f instanceof LowPassFilter) { + LowPassFilter lpf = (LowPassFilter) f; + //EFX10.alFilteri(id, EFX10.AL_FILTER_TYPE, EFX10.AL_FILTER_LOWPASS); + alFilteri(id, AL.AL_FILTER_TYPE, AL.AL_FILTER_LOWPASS); + //EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAIN, lpf.getVolume()); + alFilterf(id, AL.AL_LOWPASS_GAIN, lpf.getVolume()); + //EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAINHF, lpf.getHighFreqVolume()); + alFilterf(id, AL.AL_LOWPASS_GAINHF, lpf.getHighFreqVolume()); + } else { + throw new UnsupportedOperationException("Filter type unsupported: " + + f.getClass().getName()); + } + + f.clearUpdateNeeded(); + } + + public void updateSourceParam(AudioSource src, AudioParam param) { + checkDead(); + synchronized (threadLock) { + while (!threadLock.get()) { + try { + threadLock.wait(); + } catch (InterruptedException ex) { + } + } + if (audioDisabled) { + return; + } + + // There is a race condition in AudioSource that can + // cause this to be called for a node that has been + // detached from its channel. For example, setVolume() + // called from the render thread may see that that AudioSource + // still has a channel value but the audio thread may + // clear that channel before setVolume() gets to call + // updateSourceParam() (because the audio stopped playing + // on its own right as the volume was set). In this case, + // it should be safe to just ignore the update + if (src.getChannel() < 0) { + return; + } + + assert src.getChannel() >= 0; + + int id = channels[src.getChannel()]; + switch (param) { + case Position: + if (!src.isPositional()) { + return; + } + + Vector3f pos = src.getPosition(); + //alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z); + alSource3f(id, AL.AL_POSITION, pos.x, pos.y, pos.z); + checkError(true); + break; + case Velocity: + if (!src.isPositional()) { + return; + } + + Vector3f vel = src.getVelocity(); + //alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z); + alSource3f(id, AL.AL_VELOCITY, vel.x, vel.y, vel.z); + checkError(true); + break; + case MaxDistance: + if (!src.isPositional()) { + return; + } + + //alSourcef(id, AL_MAX_DISTANCE, src.getMaxDistance()); + alSourcef(id, AL.AL_MAX_DISTANCE, src.getMaxDistance()); + checkError(true); + break; + case RefDistance: + if (!src.isPositional()) { + return; + } + + //alSourcef(id, AL_REFERENCE_DISTANCE, src.getRefDistance()); + alSourcef(id, AL.AL_REFERENCE_DISTANCE, src.getRefDistance()); + checkError(true); + break; + case ReverbFilter: + if (!supportEfx || !src.isPositional() || !src.isReverbEnabled()) { + return; + } + + int filter = AL.AL_FILTER_NULL; + if (src.getReverbFilter() != null) { + Filter f = src.getReverbFilter(); + if (f.isUpdateNeeded()) { + updateFilter(f); + } + filter = f.getId(); + } + //AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter); + alSource3i(id, AL.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter); + break; + case ReverbEnabled: + if (!supportEfx || !src.isPositional()) { + return; + } + + if (src.isReverbEnabled()) { + updateSourceParam(src, AudioParam.ReverbFilter); + } else { + //AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, 0, 0, EFX10.AL_FILTER_NULL); + alSource3i(id, AL.AL_AUXILIARY_SEND_FILTER, 0, 0, AL.AL_FILTER_NULL); + } + break; + case IsPositional: + if (!src.isPositional()) { + // Play in headspace + //alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(id, AL.AL_SOURCE_RELATIVE, AL.AL_TRUE); + checkError(true); + //alSource3f(id, AL_POSITION, 0, 0, 0); + alSource3f(id, AL.AL_POSITION, 0, 0, 0); + checkError(true); + //alSource3f(id, AL_VELOCITY, 0, 0, 0); + alSource3f(id, AL.AL_VELOCITY, 0, 0, 0); + checkError(true); + + // Disable reverb + //AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, 0, 0, EFX10.AL_FILTER_NULL); + alSource3i(id, AL.AL_AUXILIARY_SEND_FILTER, 0, 0, AL.AL_FILTER_NULL); + } else { + //alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(id, AL.AL_SOURCE_RELATIVE, AL.AL_FALSE); + checkError(true); + updateSourceParam(src, AudioParam.Position); + updateSourceParam(src, AudioParam.Velocity); + updateSourceParam(src, AudioParam.MaxDistance); + updateSourceParam(src, AudioParam.RefDistance); + updateSourceParam(src, AudioParam.ReverbEnabled); + } + break; + case Direction: + if (!src.isDirectional()) { + return; + } + + Vector3f dir = src.getDirection(); + //alSource3f(id, AL_DIRECTION, dir.x, dir.y, dir.z); + alSource3f(id, AL.AL_DIRECTION, dir.x, dir.y, dir.z); + checkError(true); + break; + case InnerAngle: + if (!src.isDirectional()) { + return; + } + + //alSourcef(id, AL_CONE_INNER_ANGLE, src.getInnerAngle()); + alSourcef(id, AL.AL_CONE_INNER_ANGLE, src.getInnerAngle()); + checkError(true); + break; + case OuterAngle: + if (!src.isDirectional()) { + return; + } + + //alSourcef(id, AL_CONE_OUTER_ANGLE, src.getOuterAngle()); + alSourcef(id, AL.AL_CONE_OUTER_ANGLE, src.getOuterAngle()); + checkError(true); + break; + case IsDirectional: + if (src.isDirectional()) { + updateSourceParam(src, AudioParam.Direction); + updateSourceParam(src, AudioParam.InnerAngle); + updateSourceParam(src, AudioParam.OuterAngle); + //alSourcef(id, AL_CONE_OUTER_GAIN, 0); + alSourcef(id, AL.AL_CONE_OUTER_GAIN, 0); + checkError(true); + } else { + //alSourcef(id, AL_CONE_INNER_ANGLE, 360); + alSourcef(id, AL.AL_CONE_INNER_ANGLE, 360); + checkError(true); + //alSourcef(id, AL_CONE_OUTER_ANGLE, 360); + alSourcef(id, AL.AL_CONE_OUTER_ANGLE, 360); + checkError(true); + //alSourcef(id, AL_CONE_OUTER_GAIN, 1f); + alSourcef(id, AL.AL_CONE_OUTER_GAIN, 1f); + checkError(true); + } + break; + case DryFilter: + if (!supportEfx) { + return; + } + + if (src.getDryFilter() != null) { + Filter f = src.getDryFilter(); + if (f.isUpdateNeeded()) { + updateFilter(f); + + // NOTE: must re-attach filter for changes to apply. + //alSourcei(id, EFX10.AL_DIRECT_FILTER, f.getId()); + alSourcei(id, AL.AL_DIRECT_FILTER, f.getId()); + } + } else { + //alSourcei(id, EFX10.AL_DIRECT_FILTER, EFX10.AL_FILTER_NULL); + alSourcei(id, AL.AL_DIRECT_FILTER, AL.AL_FILTER_NULL); + } + break; + case Looping: + if (src.isLooping()) { + if (!(src.getAudioData() instanceof AudioStream)) { + //alSourcei(id, AL_LOOPING, AL_TRUE); + alSourcei(id, AL.AL_LOOPING, AL.AL_TRUE); + checkError(true); + } + } else { + //alSourcei(id, AL_LOOPING, AL_FALSE); + alSourcei(id, AL.AL_LOOPING, AL.AL_FALSE); + checkError(true); + } + break; + case Volume: + //alSourcef(id, AL_GAIN, src.getVolume()); + alSourcef(id, AL.AL_GAIN, src.getVolume()); + checkError(true); + break; + case Pitch: + //alSourcef(id, AL_PITCH, src.getPitch()); + alSourcef(id, AL.AL_PITCH, src.getPitch()); + checkError(true); + break; + } + } + } + + private void setSourceParams(int id, AudioSource src, boolean forceNonLoop) { + if (src.isPositional()) { + Vector3f pos = src.getPosition(); + Vector3f vel = src.getVelocity(); + //alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z); + alSource3f(id, AL.AL_POSITION, pos.x, pos.y, pos.z); + checkError(true); + //alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z); + alSource3f(id, AL.AL_VELOCITY, vel.x, vel.y, vel.z); + checkError(true); + //alSourcef(id, AL_MAX_DISTANCE, src.getMaxDistance()); + alSourcef(id, AL.AL_MAX_DISTANCE, src.getMaxDistance()); + checkError(true); + //alSourcef(id, AL_REFERENCE_DISTANCE, src.getRefDistance()); + alSourcef(id, AL.AL_REFERENCE_DISTANCE, src.getRefDistance()); + checkError(true); + //alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(id, AL.AL_SOURCE_RELATIVE, AL.AL_FALSE); + checkError(true); + + if (src.isReverbEnabled() && supportEfx) { + //int filter = EFX10.AL_FILTER_NULL; + int filter = AL.AL_FILTER_NULL; + if (src.getReverbFilter() != null) { + Filter f = src.getReverbFilter(); + if (f.isUpdateNeeded()) { + updateFilter(f); + } + filter = f.getId(); + } + //AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter); + alSource3i(id, AL.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter); + } + } else { + // play in headspace + //alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(id, AL.AL_SOURCE_RELATIVE, AL.AL_TRUE); + checkError(true); + //alSource3f(id, AL_POSITION, 0, 0, 0); + alSource3f(id, AL.AL_POSITION, 0, 0, 0); + checkError(true); + //alSource3f(id, AL_VELOCITY, 0, 0, 0); + alSource3f(id, AL.AL_VELOCITY, 0, 0, 0); + checkError(true); + } + + if (src.getDryFilter() != null && supportEfx) { + Filter f = src.getDryFilter(); + if (f.isUpdateNeeded()) { + updateFilter(f); + + // NOTE: must re-attach filter for changes to apply. + //alSourcei(id, EFX10.AL_DIRECT_FILTER, f.getId()); + alSourcei(id, AL.AL_DIRECT_FILTER, f.getId()); + } + } + + if (forceNonLoop) { + //alSourcei(id, AL_LOOPING, AL_FALSE); + alSourcei(id, AL.AL_LOOPING, AL.AL_FALSE); + checkError(true); + } else { + //alSourcei(id, AL_LOOPING, src.isLooping() ? AL_TRUE : AL_FALSE); + alSourcei(id, AL.AL_LOOPING, src.isLooping() ? AL.AL_TRUE : AL.AL_FALSE); + checkError(true); + } + //alSourcef(id, AL_GAIN, src.getVolume()); + alSourcef(id, AL.AL_GAIN, src.getVolume()); + checkError(true); + //alSourcef(id, AL_PITCH, src.getPitch()); + alSourcef(id, AL.AL_PITCH, src.getPitch()); + checkError(true); + //alSourcef(id, AL11.AL_SEC_OFFSET, src.getTimeOffset()); + alSourcef(id, AL.AL_SEC_OFFSET, src.getTimeOffset()); + checkError(true); + + if (src.isDirectional()) { + Vector3f dir = src.getDirection(); + //alSource3f(id, AL_DIRECTION, dir.x, dir.y, dir.z); + alSource3f(id, AL.AL_DIRECTION, dir.x, dir.y, dir.z); + checkError(true); + //alSourcef(id, AL_CONE_INNER_ANGLE, src.getInnerAngle()); + alSourcef(id, AL.AL_CONE_INNER_ANGLE, src.getInnerAngle()); + checkError(true); + //alSourcef(id, AL_CONE_OUTER_ANGLE, src.getOuterAngle()); + alSourcef(id, AL.AL_CONE_OUTER_ANGLE, src.getOuterAngle()); + checkError(true); + //alSourcef(id, AL_CONE_OUTER_GAIN, 0); + alSourcef(id, AL.AL_CONE_OUTER_GAIN, 0); + checkError(true); + } else { + //alSourcef(id, AL_CONE_INNER_ANGLE, 360); + alSourcef(id, AL.AL_CONE_INNER_ANGLE, 360); + checkError(true); + //alSourcef(id, AL_CONE_OUTER_ANGLE, 360); + alSourcef(id, AL.AL_CONE_OUTER_ANGLE, 360); + checkError(true); + //alSourcef(id, AL_CONE_OUTER_GAIN, 1f); + alSourcef(id, AL.AL_CONE_OUTER_GAIN, 1f); + checkError(true); + } + } + + public void updateListenerParam(Listener listener, ListenerParam param) { + checkDead(); + synchronized (threadLock) { + while (!threadLock.get()) { + try { + threadLock.wait(); + } catch (InterruptedException ex) { + } + } + if (audioDisabled) { + return; + } + + switch (param) { + case Position: + Vector3f pos = listener.getLocation(); + //alListener3f(AL_POSITION, pos.x, pos.y, pos.z); + alListener3f(AL.AL_POSITION, pos.x, pos.y, pos.z); + checkError(true); + break; + case Rotation: + Vector3f dir = listener.getDirection(); + Vector3f up = listener.getUp(); + fb.rewind(); + fb.put(dir.x).put(dir.y).put(dir.z); + fb.put(up.x).put(up.y).put(up.z); + fb.flip(); + //alListener(AL_ORIENTATION, fb); + alListener(AL.AL_ORIENTATION, fb); + checkError(true); + break; + case Velocity: + Vector3f vel = listener.getVelocity(); + //alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z); + alListener3f(AL.AL_VELOCITY, vel.x, vel.y, vel.z); + checkError(true); + break; + case Volume: + //alListenerf(AL_GAIN, listener.getVolume()); + alListenerf(AL.AL_GAIN, listener.getVolume()); + checkError(true); + break; + } + } + } + + private void setListenerParams(Listener listener) { + Vector3f pos = listener.getLocation(); + Vector3f vel = listener.getVelocity(); + Vector3f dir = listener.getDirection(); + Vector3f up = listener.getUp(); + + //alListener3f(AL_POSITION, pos.x, pos.y, pos.z); + alListener3f(AL.AL_POSITION, pos.x, pos.y, pos.z); + checkError(true); + //alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z); + alListener3f(AL.AL_VELOCITY, vel.x, vel.y, vel.z); + checkError(true); + fb.rewind(); + fb.put(dir.x).put(dir.y).put(dir.z); + fb.put(up.x).put(up.y).put(up.z); + fb.flip(); + //alListener(AL_ORIENTATION, fb); + alListener(AL.AL_ORIENTATION, fb); + checkError(true); + //alListenerf(AL_GAIN, listener.getVolume()); + alListenerf(AL.AL_GAIN, listener.getVolume()); + checkError(true); + } + + private int newChannel() { + if (freeChans.size() > 0) { + return freeChans.remove(0); + } else if (nextChan < channels.length) { + return nextChan++; + } else { + return -1; + } + } + + private void freeChannel(int index) { + if (index == nextChan - 1) { + nextChan--; + } else { + freeChans.add(index); + } + } + + public void setEnvironment(Environment env) { + checkDead(); + synchronized (threadLock) { + while (!threadLock.get()) { + try { + threadLock.wait(); + } catch (InterruptedException ex) { + } + } + if (audioDisabled || !supportEfx) { + return; + } + + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DENSITY, env.getDensity()); + alEffectf(reverbFx, AL.AL_REVERB_DENSITY, env.getDensity()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DIFFUSION, env.getDiffusion()); + alEffectf(reverbFx, AL.AL_REVERB_DIFFUSION, env.getDiffusion()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_GAIN, env.getGain()); + alEffectf(reverbFx, AL.AL_REVERB_GAIN, env.getGain()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_GAINHF, env.getGainHf()); + alEffectf(reverbFx, AL.AL_REVERB_GAINHF, env.getGainHf()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DECAY_TIME, env.getDecayTime()); + alEffectf(reverbFx, AL.AL_REVERB_DECAY_TIME, env.getDecayTime()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DECAY_HFRATIO, env.getDecayHFRatio()); + alEffectf(reverbFx, AL.AL_REVERB_DECAY_HFRATIO, env.getDecayHFRatio()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_REFLECTIONS_GAIN, env.getReflectGain()); + alEffectf(reverbFx, AL.AL_REVERB_REFLECTIONS_GAIN, env.getReflectGain()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_REFLECTIONS_DELAY, env.getReflectDelay()); + alEffectf(reverbFx, AL.AL_REVERB_REFLECTIONS_DELAY, env.getReflectDelay()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_LATE_REVERB_GAIN, env.getLateReverbGain()); + alEffectf(reverbFx, AL.AL_REVERB_LATE_REVERB_GAIN, env.getLateReverbGain()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_LATE_REVERB_DELAY, env.getLateReverbDelay()); + alEffectf(reverbFx, AL.AL_REVERB_LATE_REVERB_DELAY, env.getLateReverbDelay()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_AIR_ABSORPTION_GAINHF, env.getAirAbsorbGainHf()); + alEffectf(reverbFx, AL.AL_REVERB_AIR_ABSORPTION_GAINHF, env.getAirAbsorbGainHf()); + //EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_ROOM_ROLLOFF_FACTOR, env.getRoomRolloffFactor()); + alEffectf(reverbFx, AL.AL_REVERB_ROOM_ROLLOFF_FACTOR, env.getRoomRolloffFactor()); + + // attach effect to slot + //EFX10.alAuxiliaryEffectSloti(reverbFxSlot, EFX10.AL_EFFECTSLOT_EFFECT, reverbFx); + alAuxiliaryEffectSloti(reverbFxSlot, AL.AL_EFFECTSLOT_EFFECT, reverbFx); + } + } + + private boolean fillBuffer(AudioStream stream, int id) { + int size = 0; + int result; + + while (size < arrayBuf.length) { + result = stream.readSamples(arrayBuf, size, arrayBuf.length - size); + + if (result > 0) { + size += result; + } else { + break; + } + } + + if (size == 0) { + return false; + } + + nativeBuf.clear(); + nativeBuf.put(arrayBuf, 0, size); + nativeBuf.flip(); + + //alBufferData(id, convertFormat(stream), nativeBuf, stream.getSampleRate()); + alBufferData(id, convertFormat(stream), nativeBuf, size, stream.getSampleRate()); + checkError(true); + + return true; + } + + private boolean fillStreamingSource(int sourceId, AudioStream stream) { + if (!stream.isOpen()) { + return false; + } + + boolean active = true; + //int processed = alGetSourcei(sourceId, AL_BUFFERS_PROCESSED); + int processed = alGetSourcei(sourceId, AL.AL_BUFFERS_PROCESSED); + checkError(true); + + //while((processed--) != 0){ + if (processed > 0) { + int buffer; + + ib.position(0).limit(1); + //alSourceUnqueueBuffers(sourceId, ib); + alSourceUnqueueBuffers(sourceId, 1, ib); + checkError(true); + buffer = ib.get(0); + + active = fillBuffer(stream, buffer); + + ib.position(0).limit(1); + ib.put(0, buffer); + //alSourceQueueBuffers(sourceId, ib); + alSourceQueueBuffers(sourceId, 1, ib); + checkError(true); + } + + if (!active && stream.isOpen()) { + stream.close(); + } + + return active; + } + + private boolean attachStreamToSource(int sourceId, AudioStream stream) { + boolean active = true; + int activeBufferCount = 0; + for (int id : stream.getIds()) { + active = fillBuffer(stream, id); + ib.position(0).limit(1); + ib.put(id).flip(); + //alSourceQueueBuffers(sourceId, ib); + // OpenAL Soft does not like 0 size buffer data in alSourceQueueBuffers + // Produces error code 40964 (0xA004) = AL_INVALID_OPERATION and + // does not return (crashes) so that the error code can be checked. + // active is FALSE when the data size is 0 + if (active) { + alSourceQueueBuffers(sourceId, 1, ib); + checkError(true); + activeBufferCount++; + } + } + // adjust the steam id array if the audio data is smaller than STREAMING_BUFFER_COUNT + // this is to avoid an error with OpenAL Soft when alSourceUnenqueueBuffers + // is called with more buffers than were originally used with alSourceQueueBuffers + if (activeBufferCount < STREAMING_BUFFER_COUNT) { + int[] newIds = new int[activeBufferCount]; + for (int i=0; iAndroidAudioLoader will create an + * {@link AndroidAudioData} object with the specified asset key. + */ +public class AndroidAudioLoader implements AssetLoader { + + @Override + public Object load(AssetInfo assetInfo) throws IOException { + AndroidAudioData result = new AndroidAudioData(); + result.setAssetKey(assetInfo.getKey()); + return result; + } +} diff --git a/engine/src/ios/com/jme3/renderer/ios/IGLESShaderRenderer.java b/engine/src/ios/com/jme3/renderer/ios/IGLESShaderRenderer.java new file mode 100644 index 000000000..df5e3d0fb --- /dev/null +++ b/engine/src/ios/com/jme3/renderer/ios/IGLESShaderRenderer.java @@ -0,0 +1,2571 @@ +package com.jme3.renderer.ios; + +import com.jme3.light.LightList; +import com.jme3.material.RenderState; +import com.jme3.math.*; +import com.jme3.renderer.*; +import com.jme3.scene.Mesh; +import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.VertexBuffer.Format; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.VertexBuffer.Usage; +import com.jme3.shader.Attribute; +import com.jme3.shader.Shader; +import com.jme3.shader.Shader.ShaderSource; +import com.jme3.shader.Shader.ShaderType; +import com.jme3.shader.Uniform; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.FrameBuffer.RenderBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapAxis; +import com.jme3.util.BufferUtils; +import com.jme3.util.ListMap; +import com.jme3.util.NativeObjectManager; + +import java.nio.*; +import java.util.EnumSet; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import jme3tools.shader.ShaderDebug; + +/** + * The Renderer is responsible for taking rendering commands and + * executing them on the underlying video hardware. + * + * @author Kirill Vainer + */ +public class IGLESShaderRenderer implements Renderer { + + private static final Logger logger = Logger.getLogger(IGLESShaderRenderer.class.getName()); + private static final boolean VALIDATE_SHADER = false; + + private final NativeObjectManager objManager = new NativeObjectManager(); + private final EnumSet caps = EnumSet.noneOf(Caps.class); + private final Statistics statistics = new Statistics(); + private final StringBuilder stringBuf = new StringBuilder(250); + private final RenderContext context = new RenderContext(); + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); + + private final int maxFBOAttachs = 1; // Only 1 color attachment on ES + private final int maxMRTFBOAttachs = 1; // FIXME for now, not sure if > 1 is needed for ES + + private final int[] intBuf1 = new int[1]; + private final int[] intBuf16 = new int[16]; + + private int glslVer; + private int vertexTextureUnits; + private int fragTextureUnits; + private int vertexUniforms; + private int fragUniforms; + private int vertexAttribs; + private int maxRBSize; + private int maxTexSize; + private int maxCubeTexSize; + + private FrameBuffer lastFb = null; + private FrameBuffer mainFbOverride = null; + private boolean useVBO = true; + private boolean powerVr = false; + + private Shader boundShader; + + private int vpX, vpY, vpW, vpH; + private int clipX, clipY, clipW, clipH; + + public IGLESShaderRenderer() { + logger.log(Level.FINE, "IGLESShaderRenderer Constructor"); + } + + /** + * Get the capabilities of the renderer. + * @return The capabilities of the renderer. + */ + public EnumSet getCaps() { + logger.log(Level.FINE, "IGLESShaderRenderer getCaps"); + return caps; + } + + /** + * The statistics allow tracking of how data + * per frame, such as number of objects rendered, number of triangles, etc. + * These are updated when the Renderer's methods are used, make sure + * to call {@link Statistics#clearFrame() } at the appropriate time + * to get accurate info per frame. + */ + public Statistics getStatistics() { + logger.log(Level.FINE, "IGLESShaderRenderer getStatistics"); + return statistics; + } + + /** + * Invalidates the current rendering state. Should be called after + * the GL state was changed manually or through an external library. + */ + public void invalidateState() { + logger.log(Level.FINE, "IGLESShaderRenderer invalidateState"); + } + + /** + * Clears certain channels of the currently bound framebuffer. + * + * @param color True if to clear colors (RGBA) + * @param depth True if to clear depth/z + * @param stencil True if to clear stencil buffer (if available, otherwise + * ignored) + */ + public void clearBuffers(boolean color, boolean depth, boolean stencil) { + logger.log(Level.FINE, "IGLESShaderRenderer clearBuffers"); + int bits = 0; + if (color) { + bits = JmeIosGLES.GL_COLOR_BUFFER_BIT; + } + if (depth) { + bits |= JmeIosGLES.GL_DEPTH_BUFFER_BIT; + } + if (stencil) { + bits |= JmeIosGLES.GL_STENCIL_BUFFER_BIT; + } + if (bits != 0) { + JmeIosGLES.glClear(bits); + JmeIosGLES.checkGLError(); + } + } + + /** + * Sets the background (aka clear) color. + * + * @param color The background color to set + */ + public void setBackgroundColor(ColorRGBA color) { + logger.log(Level.FINE, "IGLESShaderRenderer setBackgroundColor"); + JmeIosGLES.glClearColor(color.r, color.g, color.b, color.a); + JmeIosGLES.checkGLError(); + } + + /** + * Applies the given {@link RenderState}, making the necessary + * GL calls so that the state is applied. + */ + public void applyRenderState(RenderState state) { + logger.log(Level.FINE, "IGLESShaderRenderer applyRenderState"); + /* + if (state.isWireframe() && !context.wireframe){ + GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_LINE); + context.wireframe = true; + }else if (!state.isWireframe() && context.wireframe){ + GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_FILL); + context.wireframe = false; + } + */ + if (state.isDepthTest() && !context.depthTestEnabled) { + JmeIosGLES.glEnable(JmeIosGLES.GL_DEPTH_TEST); + JmeIosGLES.glDepthFunc(convertTestFunction(context.depthFunc)); + JmeIosGLES.checkGLError(); + context.depthTestEnabled = true; + } else if (!state.isDepthTest() && context.depthTestEnabled) { + JmeIosGLES.glDisable(JmeIosGLES.GL_DEPTH_TEST); + JmeIosGLES.checkGLError(); + context.depthTestEnabled = false; + } + if (state.getDepthFunc() != context.depthFunc) { + JmeIosGLES.glDepthFunc(convertTestFunction(state.getDepthFunc())); + context.depthFunc = state.getDepthFunc(); + } + + if (state.isDepthWrite() && !context.depthWriteEnabled) { + JmeIosGLES.glDepthMask(true); + JmeIosGLES.checkGLError(); + context.depthWriteEnabled = true; + } else if (!state.isDepthWrite() && context.depthWriteEnabled) { + JmeIosGLES.glDepthMask(false); + JmeIosGLES.checkGLError(); + context.depthWriteEnabled = false; + } + if (state.isColorWrite() && !context.colorWriteEnabled) { + JmeIosGLES.glColorMask(true, true, true, true); + JmeIosGLES.checkGLError(); + context.colorWriteEnabled = true; + } else if (!state.isColorWrite() && context.colorWriteEnabled) { + JmeIosGLES.glColorMask(false, false, false, false); + JmeIosGLES.checkGLError(); + context.colorWriteEnabled = false; + } +// if (state.isPointSprite() && !context.pointSprite) { +//// GLES20.glEnable(GLES20.GL_POINT_SPRITE); +//// GLES20.glTexEnvi(GLES20.GL_POINT_SPRITE, GLES20.GL_COORD_REPLACE, GLES20.GL_TRUE); +//// GLES20.glEnable(GLES20.GL_VERTEX_PROGRAM_POINT_SIZE); +//// GLES20.glPointParameterf(GLES20.GL_POINT_SIZE_MIN, 1.0f); +// } else if (!state.isPointSprite() && context.pointSprite) { +//// GLES20.glDisable(GLES20.GL_POINT_SPRITE); +// } + + if (state.isPolyOffset()) { + if (!context.polyOffsetEnabled) { + JmeIosGLES.glEnable(JmeIosGLES.GL_POLYGON_OFFSET_FILL); + JmeIosGLES.glPolygonOffset(state.getPolyOffsetFactor(), + state.getPolyOffsetUnits()); + JmeIosGLES.checkGLError(); + + context.polyOffsetEnabled = true; + context.polyOffsetFactor = state.getPolyOffsetFactor(); + context.polyOffsetUnits = state.getPolyOffsetUnits(); + } else { + if (state.getPolyOffsetFactor() != context.polyOffsetFactor + || state.getPolyOffsetUnits() != context.polyOffsetUnits) { + JmeIosGLES.glPolygonOffset(state.getPolyOffsetFactor(), + state.getPolyOffsetUnits()); + JmeIosGLES.checkGLError(); + + context.polyOffsetFactor = state.getPolyOffsetFactor(); + context.polyOffsetUnits = state.getPolyOffsetUnits(); + } + } + } else { + if (context.polyOffsetEnabled) { + JmeIosGLES.glDisable(JmeIosGLES.GL_POLYGON_OFFSET_FILL); + JmeIosGLES.checkGLError(); + + context.polyOffsetEnabled = false; + context.polyOffsetFactor = 0; + context.polyOffsetUnits = 0; + } + } + if (state.getFaceCullMode() != context.cullMode) { + if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) { + JmeIosGLES.glDisable(JmeIosGLES.GL_CULL_FACE); + JmeIosGLES.checkGLError(); + } else { + JmeIosGLES.glEnable(JmeIosGLES.GL_CULL_FACE); + JmeIosGLES.checkGLError(); + } + + switch (state.getFaceCullMode()) { + case Off: + break; + case Back: + JmeIosGLES.glCullFace(JmeIosGLES.GL_BACK); + JmeIosGLES.checkGLError(); + break; + case Front: + JmeIosGLES.glCullFace(JmeIosGLES.GL_FRONT); + JmeIosGLES.checkGLError(); + break; + case FrontAndBack: + JmeIosGLES.glCullFace(JmeIosGLES.GL_FRONT_AND_BACK); + JmeIosGLES.checkGLError(); + break; + default: + throw new UnsupportedOperationException("Unrecognized face cull mode: " + + state.getFaceCullMode()); + } + + context.cullMode = state.getFaceCullMode(); + } + + if (state.getBlendMode() != context.blendMode) { + if (state.getBlendMode() == RenderState.BlendMode.Off) { + JmeIosGLES.glDisable(JmeIosGLES.GL_BLEND); + JmeIosGLES.checkGLError(); + } else { + JmeIosGLES.glEnable(JmeIosGLES.GL_BLEND); + switch (state.getBlendMode()) { + case Off: + break; + case Additive: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_ONE, JmeIosGLES.GL_ONE); + break; + case AlphaAdditive: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_SRC_ALPHA, JmeIosGLES.GL_ONE); + break; + case Color: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_ONE, JmeIosGLES.GL_ONE_MINUS_SRC_COLOR); + break; + case Alpha: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_SRC_ALPHA, JmeIosGLES.GL_ONE_MINUS_SRC_ALPHA); + break; + case PremultAlpha: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_ONE, JmeIosGLES.GL_ONE_MINUS_SRC_ALPHA); + break; + case Modulate: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_DST_COLOR, JmeIosGLES.GL_ZERO); + break; + case ModulateX2: + JmeIosGLES.glBlendFunc(JmeIosGLES.GL_DST_COLOR, JmeIosGLES.GL_SRC_COLOR); + break; + default: + throw new UnsupportedOperationException("Unrecognized blend mode: " + + state.getBlendMode()); + } + JmeIosGLES.checkGLError(); + } + context.blendMode = state.getBlendMode(); + } + } + + /** + * Set the range of the depth values for objects. All rendered + * objects will have their depth clamped to this range. + * + * @param start The range start + * @param end The range end + */ + public void setDepthRange(float start, float end) { + logger.log(Level.FINE, "IGLESShaderRenderer setDepthRange"); + JmeIosGLES.glDepthRangef(start, end); + JmeIosGLES.checkGLError(); + } + + /** + * Called when a new frame has been rendered. + */ + public void onFrame() { + logger.log(Level.FINE, "IGLESShaderRenderer onFrame"); + //JmeIosGLES.checkGLErrorForced(); + JmeIosGLES.checkGLError(); + + objManager.deleteUnused(this); + } + + /** + * Set the world matrix to use. Does nothing if the Renderer is + * shader based. + * + * @param worldMatrix World matrix to use. + */ + public void setWorldMatrix(Matrix4f worldMatrix) { + logger.log(Level.FINE, "IGLESShaderRenderer setWorldMatrix"); + } + + /** + * Sets the view and projection matrices to use. Does nothing if the Renderer + * is shader based. + * + * @param viewMatrix The view matrix to use. + * @param projMatrix The projection matrix to use. + */ + public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { + logger.log(Level.FINE, "IGLESShaderRenderer setViewProjectionMatrices"); + } + + /** + * Set the viewport location and resolution on the screen. + * + * @param x The x coordinate of the viewport + * @param y The y coordinate of the viewport + * @param width Width of the viewport + * @param height Height of the viewport + */ + public void setViewPort(int x, int y, int width, int height) { + logger.log(Level.FINE, "IGLESShaderRenderer setViewPort"); + if (x != vpX || vpY != y || vpW != width || vpH != height) { + JmeIosGLES.glViewport(x, y, width, height); + JmeIosGLES.checkGLError(); + + vpX = x; + vpY = y; + vpW = width; + vpH = height; + } + } + + /** + * Specifies a clipping rectangle. + * For all future rendering commands, no pixels will be allowed + * to be rendered outside of the clip rectangle. + * + * @param x The x coordinate of the clip rect + * @param y The y coordinate of the clip rect + * @param width Width of the clip rect + * @param height Height of the clip rect + */ + public void setClipRect(int x, int y, int width, int height) { + logger.log(Level.FINE, "IGLESShaderRenderer setClipRect"); + if (!context.clipRectEnabled) { + JmeIosGLES.glEnable(JmeIosGLES.GL_SCISSOR_TEST); + JmeIosGLES.checkGLError(); + context.clipRectEnabled = true; + } + if (clipX != x || clipY != y || clipW != width || clipH != height) { + JmeIosGLES.glScissor(x, y, width, height); + JmeIosGLES.checkGLError(); + clipX = x; + clipY = y; + clipW = width; + clipH = height; + } + } + + /** + * Clears the clipping rectangle set with + * {@link #setClipRect(int, int, int, int) }. + */ + public void clearClipRect() { + logger.log(Level.FINE, "IGLESShaderRenderer clearClipRect"); + if (context.clipRectEnabled) { + JmeIosGLES.glDisable(JmeIosGLES.GL_SCISSOR_TEST); + JmeIosGLES.checkGLError(); + context.clipRectEnabled = false; + + clipX = 0; + clipY = 0; + clipW = 0; + clipH = 0; + } + } + + /** + * Set lighting state. + * Does nothing if the renderer is shader based. + * The lights should be provided in world space. + * Specify null to disable lighting. + * + * @param lights The light list to set. + */ + public void setLighting(LightList lights) { + logger.log(Level.FINE, "IGLESShaderRenderer setLighting"); + } + + /** + * Sets the shader to use for rendering. + * If the shader has not been uploaded yet, it is compiled + * and linked. If it has been uploaded, then the + * uniform data is updated and the shader is set. + * + * @param shader The shader to use for rendering. + */ + public void setShader(Shader shader) { + logger.log(Level.FINE, "IGLESShaderRenderer setShader"); + if (shader == null) { + throw new IllegalArgumentException("Shader cannot be null"); + } else { + if (shader.isUpdateNeeded()) { + updateShaderData(shader); + } + + // NOTE: might want to check if any of the + // sources need an update? + + assert shader.getId() > 0; + + updateShaderUniforms(shader); + bindProgram(shader); + } + } + + /** + * Deletes a shader. This method also deletes + * the attached shader sources. + * + * @param shader Shader to delete. + */ + public void deleteShader(Shader shader) { + logger.log(Level.FINE, "IGLESShaderRenderer deleteShader"); + if (shader.getId() == -1) { + logger.warning("Shader is not uploaded to GPU, cannot delete."); + return; + } + + for (ShaderSource source : shader.getSources()) { + if (source.getId() != -1) { + JmeIosGLES.glDetachShader(shader.getId(), source.getId()); + JmeIosGLES.checkGLError(); + + deleteShaderSource(source); + } + } + + JmeIosGLES.glDeleteProgram(shader.getId()); + JmeIosGLES.checkGLError(); + + statistics.onDeleteShader(); + shader.resetObject(); + } + + /** + * Deletes the provided shader source. + * + * @param source The ShaderSource to delete. + */ + public void deleteShaderSource(ShaderSource source) { + logger.log(Level.FINE, "IGLESShaderRenderer deleteShaderSource"); + if (source.getId() < 0) { + logger.warning("Shader source is not uploaded to GPU, cannot delete."); + return; + } + + source.clearUpdateNeeded(); + + JmeIosGLES.glDeleteShader(source.getId()); + JmeIosGLES.checkGLError(); + + source.resetObject(); + } + + /** + * Copies contents from src to dst, scaling if necessary. + */ + public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { + logger.log(Level.FINE, "IGLESShaderRenderer copyFrameBuffer"); + copyFrameBuffer(src, dst, true); + } + + /** + * Copies contents from src to dst, scaling if necessary. + * set copyDepth to false to only copy the color buffers. + */ + public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { + logger.warning("IGLESShaderRenderer copyFrameBuffer with depth TODO"); + throw new RendererException("Copy framebuffer not implemented yet."); + } + + /** + * Sets the framebuffer that will be drawn to. + */ + public void setFrameBuffer(FrameBuffer fb) { + logger.log(Level.FINE, "IGLESShaderRenderer setFrameBuffer"); + if (fb == null && mainFbOverride != null) { + fb = mainFbOverride; + } + + if (lastFb == fb) { + if (fb == null || !fb.isUpdateNeeded()) { + return; + } + } + + // generate mipmaps for last FB if needed + if (lastFb != null) { + for (int i = 0; i < lastFb.getNumColorBuffers(); i++) { + RenderBuffer rb = lastFb.getColorBuffer(i); + Texture tex = rb.getTexture(); + if (tex != null + && tex.getMinFilter().usesMipMapLevels()) { + setTexture(0, rb.getTexture()); + +// int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace()); + int textureType = convertTextureType(tex.getType()); + JmeIosGLES.glGenerateMipmap(textureType); + JmeIosGLES.checkGLError(); + } + } + } + + if (fb == null) { + // unbind any fbos + if (context.boundFBO != 0) { + JmeIosGLES.glBindFramebuffer(JmeIosGLES.GL_FRAMEBUFFER, 0); + JmeIosGLES.checkGLError(); + + statistics.onFrameBufferUse(null, true); + + context.boundFBO = 0; + } + + /* + // select back buffer + if (context.boundDrawBuf != -1) { + glDrawBuffer(initialDrawBuf); + context.boundDrawBuf = -1; + } + if (context.boundReadBuf != -1) { + glReadBuffer(initialReadBuf); + context.boundReadBuf = -1; + } + */ + + lastFb = null; + } else { + if (fb.getNumColorBuffers() == 0 && fb.getDepthBuffer() == null) { + throw new IllegalArgumentException("The framebuffer: " + fb + + "\nDoesn't have any color/depth buffers"); + } + + if (fb.isUpdateNeeded()) { + updateFrameBuffer(fb); + } + + if (context.boundFBO != fb.getId()) { + JmeIosGLES.glBindFramebuffer(JmeIosGLES.GL_FRAMEBUFFER, fb.getId()); + JmeIosGLES.checkGLError(); + + statistics.onFrameBufferUse(fb, true); + + // update viewport to reflect framebuffer's resolution + setViewPort(0, 0, fb.getWidth(), fb.getHeight()); + + context.boundFBO = fb.getId(); + } else { + statistics.onFrameBufferUse(fb, false); + } + if (fb.getNumColorBuffers() == 0) { +// // make sure to select NONE as draw buf +// // no color buffer attached. select NONE + if (context.boundDrawBuf != -2) { +// glDrawBuffer(GL_NONE); + context.boundDrawBuf = -2; + } + if (context.boundReadBuf != -2) { +// glReadBuffer(GL_NONE); + context.boundReadBuf = -2; + } + } else { + if (fb.getNumColorBuffers() > maxFBOAttachs) { + throw new RendererException("Framebuffer has more color " + + "attachments than are supported" + + " by the video hardware!"); + } + if (fb.isMultiTarget()) { + if (fb.getNumColorBuffers() > maxMRTFBOAttachs) { + throw new RendererException("Framebuffer has more" + + " multi targets than are supported" + + " by the video hardware!"); + } + + if (context.boundDrawBuf != 100 + fb.getNumColorBuffers()) { + //intBuf16.clear(); + for (int i = 0; i < 16; i++) { + intBuf16[i] = i < fb.getNumColorBuffers() ? JmeIosGLES.GL_COLOR_ATTACHMENT0 + i : 0; + } + + //intBuf16.flip();// TODO: flip +// glDrawBuffers(intBuf16); + context.boundDrawBuf = 100 + fb.getNumColorBuffers(); + } + } else { + RenderBuffer rb = fb.getColorBuffer(fb.getTargetIndex()); + // select this draw buffer + if (context.boundDrawBuf != rb.getSlot()) { + JmeIosGLES.glActiveTexture(convertAttachmentSlot(rb.getSlot())); + JmeIosGLES.checkGLError(); + + context.boundDrawBuf = rb.getSlot(); + } + } + } + + assert fb.getId() >= 0; + assert context.boundFBO == fb.getId(); + + lastFb = fb; + + checkFrameBufferStatus(fb); + } + } + + /** + * Set the framebuffer that will be set instead of the main framebuffer + * when a call to setFrameBuffer(null) is made. + * + * @param fb + */ + public void setMainFrameBufferOverride(FrameBuffer fb) { + logger.log(Level.FINE, "IGLESShaderRenderer setMainFrameBufferOverride"); + mainFbOverride = fb; + } + + /** + * Reads the pixels currently stored in the specified framebuffer + * into the given ByteBuffer object. + * Only color pixels are transferred, the format is BGRA with 8 bits + * per component. The given byte buffer should have at least + * fb.getWidth() * fb.getHeight() * 4 bytes remaining. + * + * @param fb The framebuffer to read from + * @param byteBuf The bytebuffer to transfer color data to + */ + public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { + logger.log(Level.FINE, "IGLESShaderRenderer readFrameBuffer"); + if (fb != null) { + RenderBuffer rb = fb.getColorBuffer(); + if (rb == null) { + throw new IllegalArgumentException("Specified framebuffer" + + " does not have a colorbuffer"); + } + + setFrameBuffer(fb); + } else { + setFrameBuffer(null); + } + + //JmeIosGLES.glReadPixels2(vpX, vpY, vpW, vpH, JmeIosGLES.GL_RGBA, JmeIosGLES.GL_UNSIGNED_BYTE, byteBuf.array(), 0, vpW * vpH * 4); + JmeIosGLES.glReadPixels(vpX, vpY, vpW, vpH, JmeIosGLES.GL_RGBA, JmeIosGLES.GL_UNSIGNED_BYTE, byteBuf); + JmeIosGLES.checkGLError(); + } + + /** + * Deletes a framebuffer and all attached renderbuffers + */ + public void deleteFrameBuffer(FrameBuffer fb) { + logger.log(Level.FINE, "IGLESShaderRenderer deleteFrameBuffer"); + if (fb.getId() != -1) { + if (context.boundFBO == fb.getId()) { + JmeIosGLES.glBindFramebuffer(JmeIosGLES.GL_FRAMEBUFFER, 0); + JmeIosGLES.checkGLError(); + + context.boundFBO = 0; + } + + if (fb.getDepthBuffer() != null) { + deleteRenderBuffer(fb, fb.getDepthBuffer()); + } + if (fb.getColorBuffer() != null) { + deleteRenderBuffer(fb, fb.getColorBuffer()); + } + + intBuf1[0] = fb.getId(); + JmeIosGLES.glDeleteFramebuffers(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + fb.resetObject(); + + statistics.onDeleteFrameBuffer(); + } + } + + /** + * Sets the texture to use for the given texture unit. + */ + public void setTexture(int unit, Texture tex) { + logger.log(Level.FINE, "IGLESShaderRenderer setTexture"); + Image image = tex.getImage(); + if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated()) ) { + updateTexImageData(image, tex.getType()); + } + + int texId = image.getId(); + assert texId != -1; + + if (texId == -1) { + logger.warning("error: texture image has -1 id"); + } + + Image[] textures = context.boundTextures; + + int type = convertTextureType(tex.getType()); + if (!context.textureIndexList.moveToNew(unit)) { +// if (context.boundTextureUnit != unit){ +// glActiveTexture(GL_TEXTURE0 + unit); +// context.boundTextureUnit = unit; +// } +// glEnable(type); + } + + if (textures[unit] != image) { + if (context.boundTextureUnit != unit) { + JmeIosGLES.glActiveTexture(JmeIosGLES.GL_TEXTURE0 + unit); + context.boundTextureUnit = unit; + } + + JmeIosGLES.glBindTexture(type, texId); + JmeIosGLES.checkGLError(); + + textures[unit] = image; + + statistics.onTextureUse(tex.getImage(), true); + } else { + statistics.onTextureUse(tex.getImage(), false); + } + + setupTextureParams(tex); + } + + /** + * Modify the given Texture tex with the given Image. The image will be put at x and y into the texture. + * + * @param tex the Texture that will be modified + * @param pixels the source Image data to copy data from + * @param x the x position to put the image into the texture + * @param y the y position to put the image into the texture + */ + public void modifyTexture(Texture tex, Image pixels, int x, int y) { + logger.log(Level.FINE, "IGLESShaderRenderer modifyTexture"); + setTexture(0, tex); + TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y); + } + + /** + * Deletes a texture from the GPU. + */ + public void deleteImage(Image image) { + logger.log(Level.FINE, "IGLESShaderRenderer deleteImage"); + int texId = image.getId(); + if (texId != -1) { + intBuf1[0] = texId; + + JmeIosGLES.glDeleteTextures(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + image.resetObject(); + + statistics.onDeleteTexture(); + } + } + + /** + * Uploads a vertex buffer to the GPU. + * + * @param vb The vertex buffer to upload + */ + public void updateBufferData(VertexBuffer vb) { + logger.log(Level.FINE, "IGLESShaderRenderer updateBufferData"); + int bufId = vb.getId(); + boolean created = false; + if (bufId == -1) { + // create buffer + JmeIosGLES.glGenBuffers(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + bufId = intBuf1[0]; + vb.setId(bufId); + objManager.registerObject(vb); + + created = true; + } + + // bind buffer + int target; + if (vb.getBufferType() == VertexBuffer.Type.Index) { + target = JmeIosGLES.GL_ELEMENT_ARRAY_BUFFER; + if (context.boundElementArrayVBO != bufId) { + JmeIosGLES.glBindBuffer(target, bufId); + JmeIosGLES.checkGLError(); + + context.boundElementArrayVBO = bufId; + } + } else { + target = JmeIosGLES.GL_ARRAY_BUFFER; + if (context.boundArrayVBO != bufId) { + JmeIosGLES.glBindBuffer(target, bufId); + JmeIosGLES.checkGLError(); + + context.boundArrayVBO = bufId; + } + } + + int usage = convertUsage(vb.getUsage()); + vb.getData().rewind(); + + if (created || vb.hasDataSizeChanged()) { + // upload data based on format + int size = vb.getData().limit() * vb.getFormat().getComponentSize(); + + switch (vb.getFormat()) { + case Byte: + case UnsignedByte: + JmeIosGLES.glBufferData(target, size, (ByteBuffer) vb.getData(), usage); + JmeIosGLES.checkGLError(); + break; + case Short: + case UnsignedShort: + JmeIosGLES.glBufferData(target, size, (ShortBuffer) vb.getData(), usage); + JmeIosGLES.checkGLError(); + break; + case Int: + case UnsignedInt: + JmeIosGLES.glBufferData(target, size, (IntBuffer) vb.getData(), usage); + JmeIosGLES.checkGLError(); + break; + case Float: + JmeIosGLES.glBufferData(target, size, (FloatBuffer) vb.getData(), usage); + JmeIosGLES.checkGLError(); + break; + default: + throw new RuntimeException("Unknown buffer format."); + } + } else { + int size = vb.getData().limit() * vb.getFormat().getComponentSize(); + + switch (vb.getFormat()) { + case Byte: + case UnsignedByte: + JmeIosGLES.glBufferSubData(target, 0, size, (ByteBuffer) vb.getData()); + JmeIosGLES.checkGLError(); + break; + case Short: + case UnsignedShort: + JmeIosGLES.glBufferSubData(target, 0, size, (ShortBuffer) vb.getData()); + JmeIosGLES.checkGLError(); + break; + case Int: + case UnsignedInt: + JmeIosGLES.glBufferSubData(target, 0, size, (IntBuffer) vb.getData()); + JmeIosGLES.checkGLError(); + break; + case Float: + JmeIosGLES.glBufferSubData(target, 0, size, (FloatBuffer) vb.getData()); + JmeIosGLES.checkGLError(); + break; + default: + throw new RuntimeException("Unknown buffer format."); + } + } + vb.clearUpdateNeeded(); + } + + /** + * Deletes a vertex buffer from the GPU. + * @param vb The vertex buffer to delete + */ + public void deleteBuffer(VertexBuffer vb) { + logger.log(Level.FINE, "IGLESShaderRenderer deleteBuffer"); + int bufId = vb.getId(); + if (bufId != -1) { + // delete buffer + intBuf1[0] = bufId; + + JmeIosGLES.glDeleteBuffers(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + vb.resetObject(); + } + } + + /** + * Renders count meshes, with the geometry data supplied. + * The shader which is currently set with setShader is + * responsible for transforming the input verticies into clip space + * and shading it based on the given vertex attributes. + * The int variable gl_InstanceID can be used to access the current + * instance of the mesh being rendered inside the vertex shader. + * + * @param mesh The mesh to render + * @param lod The LOD level to use, see {@link Mesh#setLodLevels(com.jme3.scene.VertexBuffer[]) }. + * @param count Number of mesh instances to render + */ + public void renderMesh(Mesh mesh, int lod, int count) { + logger.log(Level.FINE, "IGLESShaderRenderer renderMesh"); + if (mesh.getVertexCount() == 0) { + return; + } + /* + * NOTE: not supported in OpenGL ES 2.0. + if (context.pointSize != mesh.getPointSize()) { + GLES10.glPointSize(mesh.getPointSize()); + context.pointSize = mesh.getPointSize(); + } + */ + if (context.lineWidth != mesh.getLineWidth()) { + JmeIosGLES.glLineWidth(mesh.getLineWidth()); + JmeIosGLES.checkGLError(); + context.lineWidth = mesh.getLineWidth(); + } + + statistics.onMeshDrawn(mesh, lod); +// if (GLContext.getCapabilities().GL_ARB_vertex_array_object){ +// renderMeshVertexArray(mesh, lod, count); +// }else{ + + if (useVBO) { + renderMeshDefault(mesh, lod, count); + } else { + renderMeshVertexArray(mesh, lod, count); + } + } + + /** + * Resets all previously used {@link NativeObject Native Objects} on this Renderer. + * The state of the native objects is reset in such way, that using + * them again will cause the renderer to reupload them. + * Call this method when you know the GL context is going to shutdown. + * + * @see NativeObject#resetObject() + */ + public void resetGLObjects() { + logger.log(Level.FINE, "IGLESShaderRenderer resetGLObjects"); + objManager.resetObjects(); + statistics.clearMemory(); + boundShader = null; + lastFb = null; + context.reset(); + } + + /** + * Deletes all previously used {@link NativeObject Native Objects} on this Renderer, and + * then resets the native objects. + * + * @see #resetGLObjects() + * @see NativeObject#deleteObject(java.lang.Object) + */ + public void cleanup() { + logger.log(Level.FINE, "IGLESShaderRenderer cleanup"); + objManager.deleteAllObjects(this); + statistics.clearMemory(); + } + + /** + * Sets the alpha to coverage state. + *

+ * When alpha coverage and multi-sampling is enabled, + * each pixel will contain alpha coverage in all + * of its subsamples, which is then combined when + * other future alpha-blended objects are rendered. + *

+ *

+ * Alpha-to-coverage is useful for rendering transparent objects + * without having to worry about sorting them. + *

+ */ + public void setAlphaToCoverage(boolean value) { + logger.log(Level.FINE, "IGLESShaderRenderer setAlphaToCoverage"); + if (value) { + JmeIosGLES.glEnable(JmeIosGLES.GL_SAMPLE_ALPHA_TO_COVERAGE); + JmeIosGLES.checkGLError(); + } else { + JmeIosGLES.glDisable(JmeIosGLES.GL_SAMPLE_ALPHA_TO_COVERAGE); + JmeIosGLES.checkGLError(); + } + } + + + /* ------------------------------------------------------------------------------ */ + + + public void initialize() { + Level store = logger.getLevel(); + logger.setLevel(Level.FINE); + + logger.log(Level.FINE, "Vendor: {0}", JmeIosGLES.glGetString(JmeIosGLES.GL_VENDOR)); + logger.log(Level.FINE, "Renderer: {0}", JmeIosGLES.glGetString(JmeIosGLES.GL_RENDERER)); + logger.log(Level.FINE, "Version: {0}", JmeIosGLES.glGetString(JmeIosGLES.GL_VERSION)); + logger.log(Level.FINE, "Shading Language Version: {0}", JmeIosGLES.glGetString(JmeIosGLES.GL_SHADING_LANGUAGE_VERSION)); + + /* + // Fix issue in TestRenderToMemory when GL_FRONT is the main + // buffer being used. + initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); + initialReadBuf = glGetInteger(GL_READ_BUFFER); + + // XXX: This has to be GL_BACK for canvas on Mac + // Since initialDrawBuf is GL_FRONT for pbuffer, gotta + // change this value later on ... +// initialDrawBuf = GL_BACK; +// initialReadBuf = GL_BACK; + */ + + // Check OpenGL version + int openGlVer = extractVersion("OpenGL ES ", JmeIosGLES.glGetString(JmeIosGLES.GL_VERSION)); + if (openGlVer == -1) { + glslVer = -1; + throw new UnsupportedOperationException("OpenGL ES 2.0+ is required for IGLESShaderRenderer!"); + } + + // Check shader language version + glslVer = extractVersion("OpenGL ES GLSL ES ", JmeIosGLES.glGetString(JmeIosGLES.GL_SHADING_LANGUAGE_VERSION)); + switch (glslVer) { + // TODO: When new versions of OpenGL ES shader language come out, + // update this. + default: + caps.add(Caps.GLSL100); + break; + } + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, intBuf16, 0); + vertexTextureUnits = intBuf16[0]; + logger.log(Level.FINE, "VTF Units: {0}", vertexTextureUnits); + if (vertexTextureUnits > 0) { + caps.add(Caps.VertexTextureFetch); + } + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_TEXTURE_IMAGE_UNITS, intBuf16, 0); + fragTextureUnits = intBuf16[0]; + logger.log(Level.FINE, "Texture Units: {0}", fragTextureUnits); + + // Multiply vector count by 4 to get float count. + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_VERTEX_UNIFORM_VECTORS, intBuf16, 0); + vertexUniforms = intBuf16[0] * 4; + logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_FRAGMENT_UNIFORM_VECTORS, intBuf16, 0); + fragUniforms = intBuf16[0] * 4; + logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_VARYING_VECTORS, intBuf16, 0); + int varyingFloats = intBuf16[0] * 4; + logger.log(Level.FINER, "Varying Floats: {0}", varyingFloats); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_VERTEX_ATTRIBS, intBuf16, 0); + vertexAttribs = intBuf16[0]; + logger.log(Level.FINE, "Vertex Attributes: {0}", vertexAttribs); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_SUBPIXEL_BITS, intBuf16, 0); + int subpixelBits = intBuf16[0]; + logger.log(Level.FINE, "Subpixel Bits: {0}", subpixelBits); + +// GLES10.glGetIntegerv(GLES10.GL_MAX_ELEMENTS_VERTICES, intBuf16); +// maxVertCount = intBuf16.get(0); +// logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); +// +// GLES10.glGetIntegerv(GLES10.GL_MAX_ELEMENTS_INDICES, intBuf16); +// maxTriCount = intBuf16.get(0); +// logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_TEXTURE_SIZE, intBuf16, 0); + maxTexSize = intBuf16[0]; + logger.log(Level.FINE, "Maximum Texture Resolution: {0}", maxTexSize); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_CUBE_MAP_TEXTURE_SIZE, intBuf16, 0); + maxCubeTexSize = intBuf16[0]; + logger.log(Level.FINE, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); + + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_MAX_RENDERBUFFER_SIZE, intBuf16, 0); + maxRBSize = intBuf16[0]; + logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); + + /* + if (ctxCaps.GL_ARB_color_buffer_float){ + // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. + if (ctxCaps.GL_ARB_half_float_pixel){ + caps.add(Caps.FloatColorBuffer); + } + } + + if (ctxCaps.GL_ARB_depth_buffer_float){ + caps.add(Caps.FloatDepthBuffer); + } + + if (ctxCaps.GL_ARB_draw_instanced) + caps.add(Caps.MeshInstancing); + + if (ctxCaps.GL_ARB_texture_buffer_object) + caps.add(Caps.TextureBuffer); + + if (ctxCaps.GL_ARB_texture_float){ + if (ctxCaps.GL_ARB_half_float_pixel){ + caps.add(Caps.FloatTexture); + } + } + + if (ctxCaps.GL_EXT_packed_float){ + caps.add(Caps.PackedFloatColorBuffer); + if (ctxCaps.GL_ARB_half_float_pixel){ + // because textures are usually uploaded as RGB16F + // need half-float pixel + caps.add(Caps.PackedFloatTexture); + } + } + + if (ctxCaps.GL_EXT_texture_array) + caps.add(Caps.TextureArray); + + if (ctxCaps.GL_EXT_texture_shared_exponent) + caps.add(Caps.SharedExponentTexture); + + if (ctxCaps.GL_EXT_framebuffer_object){ + caps.add(Caps.FrameBuffer); + + glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT, intBuf16); + maxRBSize = intBuf16.get(0); + logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); + + glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT, intBuf16); + maxFBOAttachs = intBuf16.get(0); + logger.log(Level.FINER, "FBO Max renderbuffers: {0}", maxFBOAttachs); + + if (ctxCaps.GL_EXT_framebuffer_multisample){ + caps.add(Caps.FrameBufferMultisample); + + glGetInteger(GL_MAX_SAMPLES_EXT, intBuf16); + maxFBOSamples = intBuf16.get(0); + logger.log(Level.FINER, "FBO Max Samples: {0}", maxFBOSamples); + } + + if (ctxCaps.GL_ARB_draw_buffers){ + caps.add(Caps.FrameBufferMRT); + glGetInteger(ARBDrawBuffers.GL_MAX_DRAW_BUFFERS_ARB, intBuf16); + maxMRTFBOAttachs = intBuf16.get(0); + logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); + } + } + + if (ctxCaps.GL_ARB_multisample){ + glGetInteger(ARBMultisample.GL_SAMPLE_BUFFERS_ARB, intBuf16); + boolean available = intBuf16.get(0) != 0; + glGetInteger(ARBMultisample.GL_SAMPLES_ARB, intBuf16); + int samples = intBuf16.get(0); + logger.log(Level.FINER, "Samples: {0}", samples); + boolean enabled = glIsEnabled(ARBMultisample.GL_MULTISAMPLE_ARB); + if (samples > 0 && available && !enabled){ + glEnable(ARBMultisample.GL_MULTISAMPLE_ARB); + } + } + */ + + String extensions = JmeIosGLES.glGetString(JmeIosGLES.GL_EXTENSIONS); + logger.log(Level.FINE, "GL_EXTENSIONS: {0}", extensions); + + // Get number of compressed formats available. + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_NUM_COMPRESSED_TEXTURE_FORMATS, intBuf16, 0); + int numCompressedFormats = intBuf16[0]; + + // Allocate buffer for compressed formats. + int[] compressedFormats = new int[numCompressedFormats]; + JmeIosGLES.glGetIntegerv(JmeIosGLES.GL_COMPRESSED_TEXTURE_FORMATS, compressedFormats, 0); + + // Check for errors after all glGet calls. + JmeIosGLES.checkGLError(); + + // Print compressed formats. + for (int i = 0; i < numCompressedFormats; i++) { + logger.log(Level.FINE, "Compressed Texture Formats: {0}", compressedFormats[i]); + } + + TextureUtil.loadTextureFeatures(extensions); + + applyRenderState(RenderState.DEFAULT); + JmeIosGLES.glDisable(JmeIosGLES.GL_DITHER); + JmeIosGLES.checkGLError(); + + logger.log(Level.FINE, "Caps: {0}", caps); + logger.setLevel(store); + } + + + /* ------------------------------------------------------------------------------ */ + + + private int extractVersion(String prefixStr, String versionStr) { + if (versionStr != null) { + int spaceIdx = versionStr.indexOf(" ", prefixStr.length()); + if (spaceIdx >= 1) { + versionStr = versionStr.substring(prefixStr.length(), spaceIdx).trim(); + } else { + versionStr = versionStr.substring(prefixStr.length()).trim(); + } + float version = Float.parseFloat(versionStr); + return (int) (version * 100); + } else { + return -1; + } + } + + private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { + intBuf1[0] = rb.getId(); + JmeIosGLES.glDeleteRenderbuffers(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + } + + private int convertUsage(Usage usage) { + switch (usage) { + case Static: + return JmeIosGLES.GL_STATIC_DRAW; + case Dynamic: + return JmeIosGLES.GL_DYNAMIC_DRAW; + case Stream: + return JmeIosGLES.GL_STREAM_DRAW; + default: + throw new RuntimeException("Unknown usage type."); + } + } + + + protected void bindProgram(Shader shader) { + int shaderId = shader.getId(); + if (context.boundShaderProgram != shaderId) { + JmeIosGLES.glUseProgram(shaderId); + JmeIosGLES.checkGLError(); + + statistics.onShaderUse(shader, true); + boundShader = shader; + context.boundShaderProgram = shaderId; + } else { + statistics.onShaderUse(shader, false); + } + } + + protected void updateShaderUniforms(Shader shader) { + ListMap uniforms = shader.getUniformMap(); + for (int i = 0; i < uniforms.size(); i++) { + Uniform uniform = uniforms.getValue(i); + if (uniform.isUpdateNeeded()) { + updateUniform(shader, uniform); + } + } + } + + + protected void updateUniform(Shader shader, Uniform uniform) { + logger.log(Level.FINE, "IGLESShaderRenderer private updateUniform: " + uniform.getVarType()); + int shaderId = shader.getId(); + + assert uniform.getName() != null; + assert shader.getId() > 0; + + if (context.boundShaderProgram != shaderId) { + JmeIosGLES.glUseProgram(shaderId); + JmeIosGLES.checkGLError(); + + statistics.onShaderUse(shader, true); + boundShader = shader; + context.boundShaderProgram = shaderId; + } else { + statistics.onShaderUse(shader, false); + } + + int loc = uniform.getLocation(); + if (loc == -1) { + return; + } + + if (loc == -2) { + // get uniform location + updateUniformLocation(shader, uniform); + if (uniform.getLocation() == -1) { + // not declared, ignore + uniform.clearUpdateNeeded(); + return; + } + loc = uniform.getLocation(); + } + + if (uniform.getVarType() == null) { + // removed logging the warning to avoid flooding the log + // (LWJGL also doesn't post a warning) + //logger.log(Level.FINEST, "Uniform value is not set yet. Shader: {0}, Uniform: {1}", + // new Object[]{shader.toString(), uniform.toString()}); + return; // value not set yet.. + } + + statistics.onUniformSet(); + + uniform.clearUpdateNeeded(); + ByteBuffer bb;//GetPrimitiveArrayCritical + FloatBuffer fb; + IntBuffer ib; + switch (uniform.getVarType()) { + case Float: + Float f = (Float) uniform.getValue(); + JmeIosGLES.glUniform1f(loc, f.floatValue()); + break; + case Vector2: + Vector2f v2 = (Vector2f) uniform.getValue(); + JmeIosGLES.glUniform2f(loc, v2.getX(), v2.getY()); + break; + case Vector3: + Vector3f v3 = (Vector3f) uniform.getValue(); + JmeIosGLES.glUniform3f(loc, v3.getX(), v3.getY(), v3.getZ()); + break; + case Vector4: + Object val = uniform.getValue(); + if (val instanceof ColorRGBA) { + ColorRGBA c = (ColorRGBA) val; + JmeIosGLES.glUniform4f(loc, c.r, c.g, c.b, c.a); + } else if (val instanceof Vector4f) { + Vector4f c = (Vector4f) val; + JmeIosGLES.glUniform4f(loc, c.x, c.y, c.z, c.w); + } else { + Quaternion c = (Quaternion) uniform.getValue(); + JmeIosGLES.glUniform4f(loc, c.getX(), c.getY(), c.getZ(), c.getW()); + } + break; + case Boolean: + Boolean b = (Boolean) uniform.getValue(); + JmeIosGLES.glUniform1i(loc, b.booleanValue() ? JmeIosGLES.GL_TRUE : JmeIosGLES.GL_FALSE); + break; + case Matrix3: + fb = (FloatBuffer) uniform.getValue(); + assert fb.remaining() == 9; + JmeIosGLES.glUniformMatrix3fv(loc, 1, false, fb); + break; + case Matrix4: + fb = (FloatBuffer) uniform.getValue(); + assert fb.remaining() == 16; + JmeIosGLES.glUniformMatrix4fv(loc, 1, false, fb); + break; + case IntArray: + ib = (IntBuffer) uniform.getValue(); + JmeIosGLES.glUniform1iv(loc, ib.limit(), ib); + break; + case FloatArray: + fb = (FloatBuffer) uniform.getValue(); + JmeIosGLES.glUniform1fv(loc, fb.limit(), fb); + break; + case Vector2Array: + fb = (FloatBuffer) uniform.getValue(); + JmeIosGLES.glUniform2fv(loc, fb.limit() / 2, fb); + break; + case Vector3Array: + fb = (FloatBuffer) uniform.getValue(); + JmeIosGLES.glUniform3fv(loc, fb.limit() / 3, fb); + break; + case Vector4Array: + fb = (FloatBuffer) uniform.getValue(); + JmeIosGLES.glUniform4fv(loc, fb.limit() / 4, fb); + break; + case Matrix4Array: + fb = (FloatBuffer) uniform.getValue(); + JmeIosGLES.glUniformMatrix4fv(loc, fb.limit() / 16, false, fb); + break; + case Int: + Integer i = (Integer) uniform.getValue(); + JmeIosGLES.glUniform1i(loc, i.intValue()); + break; + default: + throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType()); + } + JmeIosGLES.checkGLError(); + } + + protected void updateUniformLocation(Shader shader, Uniform uniform) { + stringBuf.setLength(0); + stringBuf.append(uniform.getName()).append('\0'); + updateNameBuffer(); + int loc = JmeIosGLES.glGetUniformLocation(shader.getId(), uniform.getName()); + JmeIosGLES.checkGLError(); + + if (loc < 0) { + uniform.setLocation(-1); + // uniform is not declared in shader + } else { + uniform.setLocation(loc); + } + } + + protected void updateNameBuffer() { + int len = stringBuf.length(); + + nameBuf.position(0); + nameBuf.limit(len); + for (int i = 0; i < len; i++) { + nameBuf.put((byte) stringBuf.charAt(i)); + } + + nameBuf.rewind(); + } + + + public void updateShaderData(Shader shader) { + int id = shader.getId(); + boolean needRegister = false; + if (id == -1) { + // create program + id = JmeIosGLES.glCreateProgram(); + JmeIosGLES.checkGLError(); + + if (id <= 0) { + throw new RendererException("Invalid ID received when trying to create shader program."); + } + + shader.setId(id); + needRegister = true; + } + + for (ShaderSource source : shader.getSources()) { + if (source.isUpdateNeeded()) { + updateShaderSourceData(source); + } + + JmeIosGLES.glAttachShader(id, source.getId()); + JmeIosGLES.checkGLError(); + } + + // link shaders to program + JmeIosGLES.glLinkProgram(id); + JmeIosGLES.checkGLError(); + + JmeIosGLES.glGetProgramiv(id, JmeIosGLES.GL_LINK_STATUS, intBuf1, 0); + JmeIosGLES.checkGLError(); + + boolean linkOK = intBuf1[0] == JmeIosGLES.GL_TRUE; + String infoLog = null; + + if (VALIDATE_SHADER || !linkOK) { + JmeIosGLES.glGetProgramiv(id, JmeIosGLES.GL_INFO_LOG_LENGTH, intBuf1, 0); + JmeIosGLES.checkGLError(); + + int length = intBuf1[0]; + if (length > 3) { + // get infos + infoLog = JmeIosGLES.glGetProgramInfoLog(id); + JmeIosGLES.checkGLError(); + } + } + + if (linkOK) { + if (infoLog != null) { + logger.log(Level.FINE, "shader link success. \n{0}", infoLog); + } else { + logger.fine("shader link success"); + } + shader.clearUpdateNeeded(); + if (needRegister) { + // Register shader for clean up if it was created in this method. + objManager.registerObject(shader); + statistics.onNewShader(); + } else { + // OpenGL spec: uniform locations may change after re-link + resetUniformLocations(shader); + } + } else { + if (infoLog != null) { + throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog); + } else { + throw new RendererException("Shader link failure, shader:" + shader + " info: "); + } + } + } + + protected void resetUniformLocations(Shader shader) { + ListMap uniforms = shader.getUniformMap(); + for (int i = 0; i < uniforms.size(); i++) { + Uniform uniform = uniforms.getValue(i); + uniform.reset(); // e.g check location again + } + } + + public void updateTexImageData(Image img, Texture.Type type) { + int texId = img.getId(); + if (texId == -1) { + // create texture + JmeIosGLES.glGenTextures(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + texId = intBuf1[0]; + img.setId(texId); + objManager.registerObject(img); + + statistics.onNewTexture(); + } + + // bind texture + int target = convertTextureType(type); + if (context.boundTextures[0] != img) { + if (context.boundTextureUnit != 0) { + JmeIosGLES.glActiveTexture(JmeIosGLES.GL_TEXTURE0); + JmeIosGLES.checkGLError(); + + context.boundTextureUnit = 0; + } + + JmeIosGLES.glBindTexture(target, texId); + JmeIosGLES.checkGLError(); + + context.boundTextures[0] = img; + } + + boolean needMips = false; + if (img.isGeneratedMipmapsRequired()) { + needMips = true; + img.setMipmapsGenerated(true); + } + + if (target == JmeIosGLES.GL_TEXTURE_CUBE_MAP) { + // Check max texture size before upload + if (img.getWidth() > maxCubeTexSize || img.getHeight() > maxCubeTexSize) { + throw new RendererException("Cannot upload cubemap " + img + ". The maximum supported cubemap resolution is " + maxCubeTexSize); + } + } else { + if (img.getWidth() > maxTexSize || img.getHeight() > maxTexSize) { + throw new RendererException("Cannot upload texture " + img + ". The maximum supported texture resolution is " + maxTexSize); + } + } + + if (target == JmeIosGLES.GL_TEXTURE_CUBE_MAP) { + // Upload a cube map / sky box + /* + @SuppressWarnings("unchecked") + List bmps = (List) img.getEfficentData(); + if (bmps != null) { + // Native android bitmap + if (bmps.size() != 6) { + throw new UnsupportedOperationException("Invalid texture: " + img + + "Cubemap textures must contain 6 data units."); + } + for (int i = 0; i < 6; i++) { + TextureUtil.uploadTextureBitmap(JmeIosGLES.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i).getBitmap(), needMips); + bmps.get(i).notifyBitmapUploaded(); + } + } else { + */ + // Standard jme3 image data + List data = img.getData(); + if (data.size() != 6) { + throw new UnsupportedOperationException("Invalid texture: " + img + + "Cubemap textures must contain 6 data units."); + } + for (int i = 0; i < 6; i++) { + TextureUtil.uploadTextureAny(img, JmeIosGLES.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, needMips); + } + //} + } else { + TextureUtil.uploadTextureAny(img, target, 0, needMips); + /* + if (img.getEfficentData() instanceof AndroidImageInfo) { + AndroidImageInfo info = (AndroidImageInfo) img.getEfficentData(); + info.notifyBitmapUploaded(); + } + */ + } + + img.clearUpdateNeeded(); + } + + private void setupTextureParams(Texture tex) { + int target = convertTextureType(tex.getType()); + + // filter things + int minFilter = convertMinFilter(tex.getMinFilter()); + int magFilter = convertMagFilter(tex.getMagFilter()); + + JmeIosGLES.glTexParameteri(target, JmeIosGLES.GL_TEXTURE_MIN_FILTER, minFilter); + JmeIosGLES.checkGLError(); + JmeIosGLES.glTexParameteri(target, JmeIosGLES.GL_TEXTURE_MAG_FILTER, magFilter); + JmeIosGLES.checkGLError(); + + /* + if (tex.getAnisotropicFilter() > 1){ + + if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){ + glTexParameterf(target, + EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, + tex.getAnisotropicFilter()); + } + + } + */ + // repeat modes + + switch (tex.getType()) { + case ThreeDimensional: + case CubeMap: // cubemaps use 3D coords + // GL_TEXTURE_WRAP_R is not available in api 8 + //GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); + case TwoDimensional: + case TwoDimensionalArray: + JmeIosGLES.glTexParameteri(target, JmeIosGLES.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); + + // fall down here is intentional.. +// case OneDimensional: + JmeIosGLES.glTexParameteri(target, JmeIosGLES.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); + + JmeIosGLES.checkGLError(); + break; + default: + throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); + } + + // R to Texture compare mode +/* + if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off){ + GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_MODE, GLES20.GL_COMPARE_R_TO_TEXTURE); + GLES20.glTexParameteri(target, GLES20.GL_DEPTH_TEXTURE_MODE, GLES20.GL_INTENSITY); + if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual){ + GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_GEQUAL); + }else{ + GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_LEQUAL); + } + } + */ + } + + private int convertTextureType(Texture.Type type) { + switch (type) { + case TwoDimensional: + return JmeIosGLES.GL_TEXTURE_2D; + // case TwoDimensionalArray: + // return EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT; +// case ThreeDimensional: + // return GLES20.GL_TEXTURE_3D; + case CubeMap: + return JmeIosGLES.GL_TEXTURE_CUBE_MAP; + default: + throw new UnsupportedOperationException("Unknown texture type: " + type); + } + } + + private int convertMagFilter(Texture.MagFilter filter) { + switch (filter) { + case Bilinear: + return JmeIosGLES.GL_LINEAR; + case Nearest: + return JmeIosGLES.GL_NEAREST; + default: + throw new UnsupportedOperationException("Unknown mag filter: " + filter); + } + } + + private int convertMinFilter(Texture.MinFilter filter) { + switch (filter) { + case Trilinear: + return JmeIosGLES.GL_LINEAR_MIPMAP_LINEAR; + case BilinearNearestMipMap: + return JmeIosGLES.GL_LINEAR_MIPMAP_NEAREST; + case NearestLinearMipMap: + return JmeIosGLES.GL_NEAREST_MIPMAP_LINEAR; + case NearestNearestMipMap: + return JmeIosGLES.GL_NEAREST_MIPMAP_NEAREST; + case BilinearNoMipMaps: + return JmeIosGLES.GL_LINEAR; + case NearestNoMipMaps: + return JmeIosGLES.GL_NEAREST; + default: + throw new UnsupportedOperationException("Unknown min filter: " + filter); + } + } + + private int convertWrapMode(Texture.WrapMode mode) { + switch (mode) { + case BorderClamp: + case Clamp: + case EdgeClamp: + return JmeIosGLES.GL_CLAMP_TO_EDGE; + case Repeat: + return JmeIosGLES.GL_REPEAT; + case MirroredRepeat: + return JmeIosGLES.GL_MIRRORED_REPEAT; + default: + throw new UnsupportedOperationException("Unknown wrap mode: " + mode); + } + } + + private void renderMeshVertexArray(Mesh mesh, int lod, int count) { + for (VertexBuffer vb : mesh.getBufferList().getArray()) { + if (vb.getBufferType() == Type.InterleavedData + || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers + || vb.getBufferType() == Type.Index) { + continue; + } + + if (vb.getStride() == 0) { + // not interleaved + setVertexAttrib_Array(vb); + } else { + // interleaved + VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); + setVertexAttrib_Array(vb, interleavedData); + } + } + + VertexBuffer indices = null; + if (mesh.getNumLodLevels() > 0) { + indices = mesh.getLodLevel(lod); + } else { + indices = mesh.getBuffer(Type.Index);//buffers.get(Type.Index.ordinal()); + } + if (indices != null) { + drawTriangleList_Array(indices, mesh, count); + } else { + JmeIosGLES.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); + JmeIosGLES.checkGLError(); + } + clearVertexAttribs(); + clearTextureUnits(); + } + + private void renderMeshDefault(Mesh mesh, int lod, int count) { + VertexBuffer indices = null; + VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); + if (interleavedData != null && interleavedData.isUpdateNeeded()) { + updateBufferData(interleavedData); + } + + //IntMap buffers = mesh.getBuffers(); ; + if (mesh.getNumLodLevels() > 0) { + indices = mesh.getLodLevel(lod); + } else { + indices = mesh.getBuffer(Type.Index);// buffers.get(Type.Index.ordinal()); + } + for (VertexBuffer vb : mesh.getBufferList().getArray()){ + if (vb.getBufferType() == Type.InterleavedData + || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers + || vb.getBufferType() == Type.Index) { + continue; + } + + if (vb.getStride() == 0) { + // not interleaved + setVertexAttrib(vb); + } else { + // interleaved + setVertexAttrib(vb, interleavedData); + } + } + if (indices != null) { + drawTriangleList(indices, mesh, count); + } else { +// throw new UnsupportedOperationException("Cannot render without index buffer"); + JmeIosGLES.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); + JmeIosGLES.checkGLError(); + } + clearVertexAttribs(); + clearTextureUnits(); + } + + + public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) { + if (vb.getBufferType() == VertexBuffer.Type.Index) { + throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); + } + + if (vb.isUpdateNeeded() && idb == null) { + updateBufferData(vb); + } + + int programId = context.boundShaderProgram; + if (programId > 0) { + Attribute attrib = boundShader.getAttribute(vb.getBufferType()); + int loc = attrib.getLocation(); + if (loc == -1) { + return; // not defined + } + + if (loc == -2) { +// stringBuf.setLength(0); +// stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); +// updateNameBuffer(); + + String attributeName = "in" + vb.getBufferType().name(); + loc = JmeIosGLES.glGetAttribLocation(programId, attributeName); + JmeIosGLES.checkGLError(); + + // not really the name of it in the shader (inPosition\0) but + // the internal name of the enum (Position). + if (loc < 0) { + attrib.setLocation(-1); + return; // not available in shader. + } else { + attrib.setLocation(loc); + } + } + + VertexBuffer[] attribs = context.boundAttribs; + if (!context.attribIndexList.moveToNew(loc)) { + JmeIosGLES.glEnableVertexAttribArray(loc); + JmeIosGLES.checkGLError(); + //System.out.println("Enabled ATTRIB IDX: "+loc); + } + if (attribs[loc] != vb) { + // NOTE: Use id from interleaved buffer if specified + int bufId = idb != null ? idb.getId() : vb.getId(); + assert bufId != -1; + + if (bufId == -1) { + logger.warning("invalid buffer id"); + } + + if (context.boundArrayVBO != bufId) { + JmeIosGLES.glBindBuffer(JmeIosGLES.GL_ARRAY_BUFFER, bufId); + JmeIosGLES.checkGLError(); + + context.boundArrayVBO = bufId; + } + + vb.getData().rewind(); + /* + Android22Workaround.glVertexAttribPointer(loc, + vb.getNumComponents(), + convertVertexBufferFormat(vb.getFormat()), + vb.isNormalized(), + vb.getStride(), + 0); + */ + logger.warning("iTODO Android22Workaround"); + + JmeIosGLES.glVertexAttribPointer(loc, + vb.getNumComponents(), + convertVertexBufferFormat(vb.getFormat()), + vb.isNormalized(), + vb.getStride(), + null); + + JmeIosGLES.checkGLError(); + + attribs[loc] = vb; + } + } else { + throw new IllegalStateException("Cannot render mesh without shader bound"); + } + } + + public void setVertexAttrib(VertexBuffer vb) { + setVertexAttrib(vb, null); + } + + public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) { + /* if (count > 1){ + ARBDrawInstanced.glDrawArraysInstancedARB(convertElementMode(mode), 0, + vertCount, count); + }else{*/ + JmeIosGLES.glDrawArrays(convertElementMode(mode), 0, vertCount); + JmeIosGLES.checkGLError(); + /* + }*/ + } + + public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { + if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { + throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); + } + + if (indexBuf.isUpdateNeeded()) { + updateBufferData(indexBuf); + } + + int bufId = indexBuf.getId(); + assert bufId != -1; + + if (bufId == -1) { + throw new RendererException("Invalid buffer ID"); + } + + if (context.boundElementArrayVBO != bufId) { + JmeIosGLES.glBindBuffer(JmeIosGLES.GL_ELEMENT_ARRAY_BUFFER, bufId); + JmeIosGLES.checkGLError(); + + context.boundElementArrayVBO = bufId; + } + + int vertCount = mesh.getVertexCount(); + boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); + + Buffer indexData = indexBuf.getData(); + + if (indexBuf.getFormat() == Format.UnsignedInt) { + throw new RendererException("OpenGL ES does not support 32-bit index buffers." + + "Split your models to avoid going over 65536 vertices."); + } + + if (mesh.getMode() == Mode.Hybrid) { + int[] modeStart = mesh.getModeStart(); + int[] elementLengths = mesh.getElementLengths(); + + int elMode = convertElementMode(Mode.Triangles); + int fmt = convertVertexBufferFormat(indexBuf.getFormat()); + int elSize = indexBuf.getFormat().getComponentSize(); + int listStart = modeStart[0]; + int stripStart = modeStart[1]; + int fanStart = modeStart[2]; + int curOffset = 0; + for (int i = 0; i < elementLengths.length; i++) { + if (i == stripStart) { + elMode = convertElementMode(Mode.TriangleStrip); + } else if (i == fanStart) { + elMode = convertElementMode(Mode.TriangleStrip); + } + int elementLength = elementLengths[i]; + + if (useInstancing) { + //ARBDrawInstanced. + throw new IllegalArgumentException("instancing is not supported."); + /* + GLES20.glDrawElementsInstancedARB(elMode, + elementLength, + fmt, + curOffset, + count); + */ + } else { + indexBuf.getData().position(curOffset); + JmeIosGLES.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); + JmeIosGLES.checkGLError(); + /* + glDrawRangeElements(elMode, + 0, + vertCount, + elementLength, + fmt, + curOffset); + */ + } + + curOffset += elementLength * elSize; + } + } else { + if (useInstancing) { + throw new IllegalArgumentException("instancing is not supported."); + //ARBDrawInstanced. +/* + GLES20.glDrawElementsInstancedARB(convertElementMode(mesh.getMode()), + indexBuf.getData().limit(), + convertVertexBufferFormat(indexBuf.getFormat()), + 0, + count); + */ + } else { + logger.log(Level.FINE, "IGLESShaderRenderer drawTriangleList TODO check"); + indexData.rewind(); + JmeIosGLES.glDrawElementsIndex( + convertElementMode(mesh.getMode()), + indexBuf.getData().limit(), + convertVertexBufferFormat(indexBuf.getFormat()), + 0); + /*TODO: + indexData.rewind(); + JmeIosGLES.glDrawElements( + convertElementMode(mesh.getMode()), + indexBuf.getData().limit(), + convertVertexBufferFormat(indexBuf.getFormat()), + 0); + */ + JmeIosGLES.checkGLError(); + } + } + } + + public int convertElementMode(Mesh.Mode mode) { + switch (mode) { + case Points: + return JmeIosGLES.GL_POINTS; + case Lines: + return JmeIosGLES.GL_LINES; + case LineLoop: + return JmeIosGLES.GL_LINE_LOOP; + case LineStrip: + return JmeIosGLES.GL_LINE_STRIP; + case Triangles: + return JmeIosGLES.GL_TRIANGLES; + case TriangleFan: + return JmeIosGLES.GL_TRIANGLE_FAN; + case TriangleStrip: + return JmeIosGLES.GL_TRIANGLE_STRIP; + default: + throw new UnsupportedOperationException("Unrecognized mesh mode: " + mode); + } + } + + + private int convertVertexBufferFormat(Format format) { + switch (format) { + case Byte: + return JmeIosGLES.GL_BYTE; + case UnsignedByte: + return JmeIosGLES.GL_UNSIGNED_BYTE; + case Short: + return JmeIosGLES.GL_SHORT; + case UnsignedShort: + return JmeIosGLES.GL_UNSIGNED_SHORT; + case Int: + return JmeIosGLES.GL_INT; + case UnsignedInt: + return JmeIosGLES.GL_UNSIGNED_INT; + /* + case Half: + return NVHalfFloat.GL_HALF_FLOAT_NV; + // return ARBHalfFloatVertex.GL_HALF_FLOAT; + */ + case Float: + return JmeIosGLES.GL_FLOAT; +// case Double: +// return JmeIosGLES.GL_DOUBLE; + default: + throw new RuntimeException("Unknown buffer format."); + + } + } + + public void clearVertexAttribs() { + IDList attribList = context.attribIndexList; + for (int i = 0; i < attribList.oldLen; i++) { + int idx = attribList.oldList[i]; + + JmeIosGLES.glDisableVertexAttribArray(idx); + JmeIosGLES.checkGLError(); + + context.boundAttribs[idx] = null; + } + context.attribIndexList.copyNewToOld(); + } + + + public void clearTextureUnits() { + IDList textureList = context.textureIndexList; + Image[] textures = context.boundTextures; + for (int i = 0; i < textureList.oldLen; i++) { + int idx = textureList.oldList[i]; +// if (context.boundTextureUnit != idx){ +// glActiveTexture(GL_TEXTURE0 + idx); +// context.boundTextureUnit = idx; +// } +// glDisable(convertTextureType(textures[idx].getType())); + textures[idx] = null; + } + context.textureIndexList.copyNewToOld(); + } + + + public void updateFrameBuffer(FrameBuffer fb) { + int id = fb.getId(); + if (id == -1) { + // create FBO + JmeIosGLES.glGenFramebuffers(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + id = intBuf1[0]; + fb.setId(id); + objManager.registerObject(fb); + + statistics.onNewFrameBuffer(); + } + + if (context.boundFBO != id) { + JmeIosGLES.glBindFramebuffer(JmeIosGLES.GL_FRAMEBUFFER, id); + JmeIosGLES.checkGLError(); + + // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 + context.boundDrawBuf = 0; + context.boundFBO = id; + } + + FrameBuffer.RenderBuffer depthBuf = fb.getDepthBuffer(); + if (depthBuf != null) { + updateFrameBufferAttachment(fb, depthBuf); + } + + for (int i = 0; i < fb.getNumColorBuffers(); i++) { + FrameBuffer.RenderBuffer colorBuf = fb.getColorBuffer(i); + updateFrameBufferAttachment(fb, colorBuf); + } + + fb.clearUpdateNeeded(); + } + + + public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { + boolean needAttach; + if (rb.getTexture() == null) { + // if it hasn't been created yet, then attach is required. + needAttach = rb.getId() == -1; + updateRenderBuffer(fb, rb); + } else { + needAttach = false; + updateRenderTexture(fb, rb); + } + if (needAttach) { + JmeIosGLES.glFramebufferRenderbuffer(JmeIosGLES.GL_FRAMEBUFFER, + convertAttachmentSlot(rb.getSlot()), + JmeIosGLES.GL_RENDERBUFFER, + rb.getId()); + + JmeIosGLES.checkGLError(); + } + } + + + public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { + Texture tex = rb.getTexture(); + Image image = tex.getImage(); + if (image.isUpdateNeeded()) { + updateTexImageData(image, tex.getType()); + + // NOTE: For depth textures, sets nearest/no-mips mode + // Required to fix "framebuffer unsupported" + // for old NVIDIA drivers! + setupTextureParams(tex); + } + + JmeIosGLES.glFramebufferTexture2D(JmeIosGLES.GL_FRAMEBUFFER, + convertAttachmentSlot(rb.getSlot()), + convertTextureType(tex.getType()), + image.getId(), + 0); + + JmeIosGLES.checkGLError(); + } + + + private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { + int id = rb.getId(); + if (id == -1) { + JmeIosGLES.glGenRenderbuffers(1, intBuf1, 0); + JmeIosGLES.checkGLError(); + + id = intBuf1[0]; + rb.setId(id); + } + + if (context.boundRB != id) { + JmeIosGLES.glBindRenderbuffer(JmeIosGLES.GL_RENDERBUFFER, id); + JmeIosGLES.checkGLError(); + + context.boundRB = id; + } + + if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) { + throw new RendererException("Resolution " + fb.getWidth() + + ":" + fb.getHeight() + " is not supported."); + } + + TextureUtil.IosGLImageFormat imageFormat = TextureUtil.getImageFormat(rb.getFormat()); + if (imageFormat.renderBufferStorageFormat == 0) { + throw new RendererException("The format '" + rb.getFormat() + "' cannot be used for renderbuffers."); + } + +// if (fb.getSamples() > 1 && GLContext.getCapabilities().GL_EXT_framebuffer_multisample) { + if (fb.getSamples() > 1) { +// // FIXME + throw new RendererException("Multisample FrameBuffer is not supported yet."); +// int samples = fb.getSamples(); +// if (maxFBOSamples < samples) { +// samples = maxFBOSamples; +// } +// glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, +// samples, +// glFmt.internalFormat, +// fb.getWidth(), +// fb.getHeight()); + } else { + JmeIosGLES.glRenderbufferStorage(JmeIosGLES.GL_RENDERBUFFER, + imageFormat.renderBufferStorageFormat, + fb.getWidth(), + fb.getHeight()); + + JmeIosGLES.checkGLError(); + } + } + + + private int convertAttachmentSlot(int attachmentSlot) { + // can also add support for stencil here + if (attachmentSlot == -100) { + return JmeIosGLES.GL_DEPTH_ATTACHMENT; + } else if (attachmentSlot == 0) { + return JmeIosGLES.GL_COLOR_ATTACHMENT0; + } else { + throw new UnsupportedOperationException("Android does not support multiple color attachments to an FBO"); + } + } + + + private void checkFrameBufferStatus(FrameBuffer fb) { + try { + checkFrameBufferError(); + } catch (IllegalStateException ex) { + logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb); + printRealFrameBufferInfo(fb); + throw ex; + } + } + + private void checkFrameBufferError() { + int status = JmeIosGLES.glCheckFramebufferStatus(JmeIosGLES.GL_FRAMEBUFFER); + switch (status) { + case JmeIosGLES.GL_FRAMEBUFFER_COMPLETE: + break; + case JmeIosGLES.GL_FRAMEBUFFER_UNSUPPORTED: + //Choose different formats + throw new IllegalStateException("Framebuffer object format is " + + "unsupported by the video hardware."); + case JmeIosGLES.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + throw new IllegalStateException("Framebuffer has erronous attachment."); + case JmeIosGLES.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + throw new IllegalStateException("Framebuffer doesn't have any renderbuffers attached."); + case JmeIosGLES.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + throw new IllegalStateException("Framebuffer attachments must have same dimensions."); +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: +// throw new IllegalStateException("Framebuffer attachments must have same formats."); +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: +// throw new IllegalStateException("Incomplete draw buffer."); +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: +// throw new IllegalStateException("Incomplete read buffer."); +// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: +// throw new IllegalStateException("Incomplete multisample buffer."); + default: + //Programming error; will fail on all hardware + throw new IllegalStateException("Some video driver error " + + "or programming error occured. " + + "Framebuffer object status is invalid: " + status); + } + } + + private void printRealRenderBufferInfo(FrameBuffer fb, RenderBuffer rb, String name) { + System.out.println("== Renderbuffer " + name + " =="); + System.out.println("RB ID: " + rb.getId()); + System.out.println("Is proper? " + JmeIosGLES.glIsRenderbuffer(rb.getId())); + + int attachment = convertAttachmentSlot(rb.getSlot()); + + //intBuf16.clear(); + JmeIosGLES.glGetFramebufferAttachmentParameteriv(JmeIosGLES.GL_FRAMEBUFFER, + attachment, JmeIosGLES.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, intBuf16, 0); + int type = intBuf16[0]; + + //intBuf16.clear(); + JmeIosGLES.glGetFramebufferAttachmentParameteriv(JmeIosGLES.GL_FRAMEBUFFER, + attachment, JmeIosGLES.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, intBuf16, 0); + int rbName = intBuf16[0]; + + switch (type) { + case JmeIosGLES.GL_NONE: + System.out.println("Type: None"); + break; + case JmeIosGLES.GL_TEXTURE: + System.out.println("Type: Texture"); + break; + case JmeIosGLES.GL_RENDERBUFFER: + System.out.println("Type: Buffer"); + System.out.println("RB ID: " + rbName); + break; + } + } + + private void printRealFrameBufferInfo(FrameBuffer fb) { +// boolean doubleBuffer = GLES20.glGetBooleanv(GLES20.GL_DOUBLEBUFFER); + boolean doubleBuffer = false; // FIXME +// String drawBuf = getTargetBufferName(glGetInteger(GL_DRAW_BUFFER)); +// String readBuf = getTargetBufferName(glGetInteger(GL_READ_BUFFER)); + + int fbId = fb.getId(); + //intBuf16.clear(); +// int curDrawBinding = GLES20.glGetIntegerv(GLES20.GL_DRAW_FRAMEBUFFER_BINDING); +// int curReadBinding = glGetInteger(ARBFramebufferObject.GL_READ_FRAMEBUFFER_BINDING); + + System.out.println("=== OpenGL FBO State ==="); + System.out.println("Context doublebuffered? " + doubleBuffer); + System.out.println("FBO ID: " + fbId); + System.out.println("Is proper? " + JmeIosGLES.glIsFramebuffer(fbId)); +// System.out.println("Is bound to draw? " + (fbId == curDrawBinding)); +// System.out.println("Is bound to read? " + (fbId == curReadBinding)); +// System.out.println("Draw buffer: " + drawBuf); +// System.out.println("Read buffer: " + readBuf); + + if (context.boundFBO != fbId) { + JmeIosGLES.glBindFramebuffer(JmeIosGLES.GL_FRAMEBUFFER, fbId); + context.boundFBO = fbId; + } + + if (fb.getDepthBuffer() != null) { + printRealRenderBufferInfo(fb, fb.getDepthBuffer(), "Depth"); + } + for (int i = 0; i < fb.getNumColorBuffers(); i++) { + printRealRenderBufferInfo(fb, fb.getColorBuffer(i), "Color" + i); + } + + + } + + public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count) { + if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { + throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); + } + + boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); + if (useInstancing) { + throw new IllegalArgumentException("Caps.MeshInstancing is not supported."); + } + + int vertCount = mesh.getVertexCount(); + Buffer indexData = indexBuf.getData(); + indexData.rewind(); + + if (mesh.getMode() == Mode.Hybrid) { + int[] modeStart = mesh.getModeStart(); + int[] elementLengths = mesh.getElementLengths(); + + int elMode = convertElementMode(Mode.Triangles); + int fmt = convertVertexBufferFormat(indexBuf.getFormat()); + int elSize = indexBuf.getFormat().getComponentSize(); + int listStart = modeStart[0]; + int stripStart = modeStart[1]; + int fanStart = modeStart[2]; + int curOffset = 0; + for (int i = 0; i < elementLengths.length; i++) { + if (i == stripStart) { + elMode = convertElementMode(Mode.TriangleStrip); + } else if (i == fanStart) { + elMode = convertElementMode(Mode.TriangleFan); + } + int elementLength = elementLengths[i]; + + indexBuf.getData().position(curOffset); + JmeIosGLES.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); + JmeIosGLES.checkGLError(); + + curOffset += elementLength * elSize; + } + } else { + JmeIosGLES.glDrawElements( + convertElementMode(mesh.getMode()), + indexBuf.getData().limit(), + convertVertexBufferFormat(indexBuf.getFormat()), + indexBuf.getData()); + JmeIosGLES.checkGLError(); + } + } + + public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb) { + if (vb.getBufferType() == VertexBuffer.Type.Index) { + throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); + } + + // Get shader + int programId = context.boundShaderProgram; + if (programId > 0) { + VertexBuffer[] attribs = context.boundAttribs; + + Attribute attrib = boundShader.getAttribute(vb.getBufferType()); + int loc = attrib.getLocation(); + if (loc == -1) { + //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]"); + return; + } else if (loc == -2) { + String attributeName = "in" + vb.getBufferType().name(); + + loc = JmeIosGLES.glGetAttribLocation(programId, attributeName); + JmeIosGLES.checkGLError(); + + if (loc < 0) { + attrib.setLocation(-1); + return; // not available in shader. + } else { + attrib.setLocation(loc); + } + + } // if (loc == -2) + + if ((attribs[loc] != vb) || vb.isUpdateNeeded()) { + // NOTE: Use data from interleaved buffer if specified + VertexBuffer avb = idb != null ? idb : vb; + avb.getData().rewind(); + avb.getData().position(vb.getOffset()); + + // Upload attribute data + JmeIosGLES.glVertexAttribPointer(loc, + vb.getNumComponents(), + convertVertexBufferFormat(vb.getFormat()), + vb.isNormalized(), + vb.getStride(), + avb.getData()); + + JmeIosGLES.checkGLError(); + + JmeIosGLES.glEnableVertexAttribArray(loc); + JmeIosGLES.checkGLError(); + + attribs[loc] = vb; + } // if (attribs[loc] != vb) + } else { + throw new IllegalStateException("Cannot render mesh without shader bound"); + } + } + + public void setVertexAttrib_Array(VertexBuffer vb) { + setVertexAttrib_Array(vb, null); + } + + + public void updateShaderSourceData(ShaderSource source) { + int id = source.getId(); + if (id == -1) { + // Create id + id = JmeIosGLES.glCreateShader(convertShaderType(source.getType())); + JmeIosGLES.checkGLError(); + + if (id <= 0) { + throw new RendererException("Invalid ID received when trying to create shader."); + } + source.setId(id); + } + + if (!source.getLanguage().equals("GLSL100")) { + throw new RendererException("This shader cannot run in OpenGL ES. " + + "Only GLSL 1.0 shaders are supported."); + } + + // upload shader source + // merge the defines and source code + byte[] definesCodeData = source.getDefines().getBytes(); + byte[] sourceCodeData = source.getSource().getBytes(); + ByteBuffer codeBuf = BufferUtils.createByteBuffer(definesCodeData.length + + sourceCodeData.length); + codeBuf.put(definesCodeData); + codeBuf.put(sourceCodeData); + codeBuf.flip(); + + if (powerVr && source.getType() == ShaderType.Vertex) { + // XXX: This is to fix a bug in old PowerVR, remove + // when no longer applicable. + JmeIosGLES.glShaderSource( + id, source.getDefines() + + source.getSource()); + } else { + String precision =""; + if (source.getType() == ShaderType.Fragment) { + precision = "precision mediump float;\n"; + } + JmeIosGLES.glShaderSource( + id, + precision + +source.getDefines() + + source.getSource()); + } +// int range[] = new int[2]; +// int precision[] = new int[1]; +// GLES20.glGetShaderPrecisionFormat(GLES20.GL_VERTEX_SHADER, GLES20.GL_HIGH_FLOAT, range, 0, precision, 0); +// System.out.println("PRECISION HIGH FLOAT VERTEX"); +// System.out.println("range "+range[0]+"," +range[1]); +// System.out.println("precision "+precision[0]); + + JmeIosGLES.glCompileShader(id); + JmeIosGLES.checkGLError(); + + JmeIosGLES.glGetShaderiv(id, JmeIosGLES.GL_COMPILE_STATUS, intBuf1, 0); + JmeIosGLES.checkGLError(); + + boolean compiledOK = intBuf1[0] == JmeIosGLES.GL_TRUE; + String infoLog = null; + + if (VALIDATE_SHADER || !compiledOK) { + // even if compile succeeded, check + // log for warnings + JmeIosGLES.glGetShaderiv(id, JmeIosGLES.GL_INFO_LOG_LENGTH, intBuf1, 0); + JmeIosGLES.checkGLError(); + infoLog = JmeIosGLES.glGetShaderInfoLog(id); + } + + if (compiledOK) { + if (infoLog != null) { + logger.log(Level.FINE, "compile success: {0}, {1}", new Object[]{source.getName(), infoLog}); + } else { + logger.log(Level.FINE, "compile success: {0}", source.getName()); + } + source.clearUpdateNeeded(); + } else { + logger.log(Level.WARNING, "Bad compile of:\n{0}", + new Object[]{ShaderDebug.formatShaderSource(source.getDefines(), source.getSource(),stringBuf.toString())}); + if (infoLog != null) { + throw new RendererException("compile error in:" + source + " error:" + infoLog); + } else { + throw new RendererException("compile error in:" + source + " error: "); + } + } + } + + + public int convertShaderType(ShaderType type) { + switch (type) { + case Fragment: + return JmeIosGLES.GL_FRAGMENT_SHADER; + case Vertex: + return JmeIosGLES.GL_VERTEX_SHADER; +// case Geometry: +// return ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB; + default: + throw new RuntimeException("Unrecognized shader type."); + } + } + + private int convertTestFunction(RenderState.TestFunction testFunc) { + switch (testFunc) { + case Never: + return JmeIosGLES.GL_NEVER; + case Less: + return JmeIosGLES.GL_LESS; + case LessOrEqual: + return JmeIosGLES.GL_LEQUAL; + case Greater: + return JmeIosGLES.GL_GREATER; + case GreaterOrEqual: + return JmeIosGLES.GL_GEQUAL; + case Equal: + return JmeIosGLES.GL_EQUAL; + case NotEqual: + return JmeIosGLES.GL_NOTEQUAL; + case Always: + return JmeIosGLES.GL_ALWAYS; + default: + throw new UnsupportedOperationException("Unrecognized test function: " + testFunc); + } + } +} \ No newline at end of file diff --git a/engine/src/ios/com/jme3/renderer/ios/JmeIosGLES.java b/engine/src/ios/com/jme3/renderer/ios/JmeIosGLES.java new file mode 100644 index 000000000..0811dc422 --- /dev/null +++ b/engine/src/ios/com/jme3/renderer/ios/JmeIosGLES.java @@ -0,0 +1,273 @@ +package com.jme3.renderer.ios; + +import com.jme3.renderer.RendererException; + +import java.nio.Buffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The iOS GLES interface iOS alternative to Android's GLES20 class + * + * @author Kostyantyn Hushchyn + */ +public class JmeIosGLES { + private static final Logger logger = Logger.getLogger(JmeIosGLES.class.getName()); + + private static boolean ENABLE_ERROR_CHECKING = true; + + public static final int GL_ALPHA = 0x00001906; + public static final int GL_ALWAYS = 0x00000207; + public static final int GL_ARRAY_BUFFER = 0x00008892; + public static final int GL_BACK = 0x00000405; + public static final int GL_BLEND = 0x00000be2; + public static final int GL_BYTE = 0x00001400; + public static final int GL_CLAMP_TO_EDGE = 0x0000812f; + public static final int GL_COLOR_ATTACHMENT0 = 0x00008ce0; + public static final int GL_COLOR_BUFFER_BIT = 0x00004000; + public static final int GL_COMPILE_STATUS = 0x00008b81; + public static final int GL_COMPRESSED_TEXTURE_FORMATS = 0x000086a3; + public static final int GL_CULL_FACE = 0x00000b44; + public static final int GL_DEPTH_ATTACHMENT = 0x00008d00; + public static final int GL_DEPTH_BUFFER_BIT = 0x00000100; + public static final int GL_DEPTH_COMPONENT = 0x00001902; + public static final int GL_DEPTH_COMPONENT16 = 0x000081a5; + public static final int GL_DEPTH_TEST = 0x00000b71; + public static final int GL_DITHER = 0x00000bd0; + public static final int GL_DST_COLOR = 0x00000306; + public static final int GL_DYNAMIC_DRAW = 0x000088e8; + public static final int GL_EQUAL = 0x00000202; + public static final int GL_ELEMENT_ARRAY_BUFFER = 0x00008893; + public static final int GL_EXTENSIONS = 0x00001f03; + public static final int GL_FALSE = 0x00000000; + public static final int GL_FLOAT = 0x00001406; + public static final int GL_FRAGMENT_SHADER = 0x00008b30; + public static final int GL_FRAMEBUFFER = 0x00008d40; + public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x00008cd1; + public static final int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x00008cd0; + public static final int GL_FRAMEBUFFER_COMPLETE = 0x00008cd5; + public static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x00008cd6; + public static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x00008cd9; + public static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x00008cd7; + public static final int GL_FRAMEBUFFER_UNSUPPORTED = 0x00008cdd; + public static final int GL_FRONT = 0x00000404; + public static final int GL_FRONT_AND_BACK = 0x00000408; + public static final int GL_GEQUAL = 0x00000206; + public static final int GL_GREATER = 0x00000204; + public static final int GL_HIGH_FLOAT = 0x00008df2; + public static final int GL_INFO_LOG_LENGTH = 0x00008b84; + public static final int GL_INT = 0x00001404; + public static final int GL_LEQUAL = 0x00000203; + public static final int GL_LESS = 0x00000201; + public static final int GL_LINEAR = 0x00002601; + public static final int GL_LINEAR_MIPMAP_LINEAR = 0x00002703; + public static final int GL_LINEAR_MIPMAP_NEAREST = 0x00002701; + public static final int GL_LINES = 0x00000001; + public static final int GL_LINE_LOOP = 0x00000002; + public static final int GL_LINE_STRIP = 0x00000003; + public static final int GL_LINK_STATUS = 0x00008b82; + public static final int GL_LUMINANCE = 0x00001909; + public static final int GL_LUMINANCE_ALPHA = 0x0000190a; + public static final int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x0000851c; + public static final int GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x00008dfd; + public static final int GL_MAX_RENDERBUFFER_SIZE = 0x000084e8; + public static final int GL_MAX_TEXTURE_IMAGE_UNITS = 0x00008872; + public static final int GL_MAX_TEXTURE_SIZE = 0x00000d33; + public static final int GL_MAX_VARYING_VECTORS = 0x00008dfc; + public static final int GL_MAX_VERTEX_ATTRIBS = 0x00008869; + public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x00008b4c; + public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x00008dfb; + public static final int GL_MIRRORED_REPEAT = 0x00008370; + public static final int GL_NEAREST = 0x00002600; + public static final int GL_NEAREST_MIPMAP_LINEAR = 0x00002702; + public static final int GL_NEAREST_MIPMAP_NEAREST = 0x00002700; + public static final int GL_NEVER = 0x00000200; + public static final int GL_NONE = 0x00000000; + public static final int GL_NOTEQUAL = 0x00000205; + public static final int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x000086a2; + public static final int GL_ONE = 0x00000001; + public static final int GL_ONE_MINUS_SRC_ALPHA = 0x00000303; + public static final int GL_ONE_MINUS_SRC_COLOR = 0x00000301; + public static final int GL_POINTS = 0x00000000; + public static final int GL_POLYGON_OFFSET_FILL = 0x00008037; + public static final int GL_RENDERBUFFER = 0x00008d41; + public static final int GL_RENDERER = 0x00001f01; + public static final int GL_REPEAT = 0x00002901; + public static final int GL_RGB = 0x00001907; + public static final int GL_RGB565 = 0x00008d62; + public static final int GL_RGB5_A1 = 0x00008057; + public static final int GL_RGBA = 0x00001908; + public static final int GL_RGBA4 = 0x00008056; + public static final int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x0000809e; + public static final int GL_SCISSOR_TEST = 0x00000c11; + public static final int GL_SHADING_LANGUAGE_VERSION = 0x00008b8c; + public static final int GL_SHORT = 0x00001402; + public static final int GL_SRC_COLOR = 0x00000300; + public static final int GL_SRC_ALPHA = 0x00000302; + public static final int GL_STATIC_DRAW = 0x000088e4; + public static final int GL_STENCIL_BUFFER_BIT = 0x00000400; + public static final int GL_STREAM_DRAW = 0x000088e0; + public static final int GL_SUBPIXEL_BITS = 0x00000d50; + public static final int GL_TEXTURE = 0x00001702; + public static final int GL_TEXTURE0 = 0x000084c0; + public static final int GL_TEXTURE_2D = 0x00000de1; + public static final int GL_TEXTURE_CUBE_MAP = 0x00008513; + public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x00008515; + public static final int GL_TEXTURE_MAG_FILTER = 0x00002800; + public static final int GL_TEXTURE_MIN_FILTER = 0x00002801; + public static final int GL_TEXTURE_WRAP_S = 0x00002802; + public static final int GL_TEXTURE_WRAP_T = 0x00002803; + public static final int GL_TRIANGLES = 0x00000004; + public static final int GL_TRIANGLE_FAN = 0x00000006; + public static final int GL_TRIANGLE_STRIP = 0x00000005; + public static final int GL_TRUE = 0x00000001; + public static final int GL_UNPACK_ALIGNMENT = 0x00000cf5; + public static final int GL_UNSIGNED_BYTE = 0x00001401; + public static final int GL_UNSIGNED_INT = 0x00001405; + public static final int GL_UNSIGNED_SHORT = 0x00001403; + public static final int GL_UNSIGNED_SHORT_4_4_4_4 = 0x00008033; + public static final int GL_UNSIGNED_SHORT_5_5_5_1 = 0x00008034; + public static final int GL_UNSIGNED_SHORT_5_6_5 = 0x00008363; + public static final int GL_VENDOR = 0x00001f00; + public static final int GL_VERSION = 0x00001f02; + public static final int GL_VERTEX_SHADER = 0x00008b31; + public static final int GL_ZERO = 0x00000000; + + public static native void glActiveTexture(int texture); + public static native void glAttachShader(int program, int shader); + public static native void glBindBuffer(int target, int buffer); + public static native void glBindFramebuffer(int target, int framebuffer); + public static native void glBindRenderbuffer(int target, int renderbuffer); + public static native void glBindTexture(int target, int texture); +// public static native void glBindVertexArray // TODO: Investigate this + public static native void glBlendFunc(int sfactor, int dfactor); + public static native void glBufferData(int target, int size, Buffer data, int usage); + public static native void glBufferData2(int target, int size, byte[] data, int offset, int usage); + public static native void glBufferSubData(int target, int offset, int size, Buffer data); + public static native void glBufferSubData2(int target, int offset, int size, byte[] data, int dataoffset); + public static native int glCheckFramebufferStatus(int target); + public static native void glClear(int mask); + public static native void glClearColor(float red, float green, float blue, float alpha); + public static native void glColorMask(boolean red, boolean green, boolean blue, boolean alpha); + public static native void glCompileShader(int shader); + public static native void glCompressedTexImage2D(int target, int level, int internalformat, int width, int height, int border, int imageSize, Buffer pixels); + public static native void glCompressedTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int imageSize, Buffer pixels); + public static native int glCreateProgram(); + public static native int glCreateShader(int type); + public static native void glCullFace(int mode); + public static native void glDeleteBuffers(int n, int[] buffers, int offset); + public static native void glDeleteFramebuffers(int n, int[] framebuffers, int offset); + public static native void glDeleteProgram(int program); + public static native void glDeleteRenderbuffers(int n, int[] renderbuffers, int offset); + public static native void glDeleteShader(int shader); + public static native void glDeleteTextures(int n, int[] textures, int offset); + public static native void glDepthFunc(int func); + public static native void glDepthMask(boolean flag); + public static native void glDepthRangef(float zNear, float zFar); + public static native void glDetachShader(int program, int shader); + public static native void glDisableVertexAttribArray(int index); + public static native void glDisable(int cap); + public static native void glDrawArrays(int mode, int first, int count); + public static native void glDrawElements(int mode, int count, int type, Buffer indices); + public static native void glDrawElements2(int mode, int count, int type, byte[] indices, int offset); + public static native void glDrawElementsIndex(int mode, int count, int type, int offset); + public static native void glEnable(int cap); + public static native void glEnableVertexAttribArray(int index); + public static native void glFramebufferRenderbuffer(int target, int attachment, int renderbuffertarget, int renderbuffer); + public static native void glFramebufferTexture2D(int target, int attachment, int textarget, int texture, int level); + public static native void glGenBuffers(int n, int[] buffers, int offset); + public static native void glGenFramebuffers(int n, int[] framebuffers, int offset); + public static native void glGenRenderbuffers(int n, int[] renderbuffers, int offset); + public static native void glGenTextures(int n, int[] textures, int offset); + public static native void glGenerateMipmap(int target); + public static native int glGetAttribLocation(int program, String name); + public static native int glGetError(); + public static native void glGetFramebufferAttachmentParameteriv(int target, int attachment, int pname, int[] params, int offset); + public static native void glGetIntegerv (int pname, int[] params, int offset); + public static native String glGetProgramInfoLog(int program); + public static native void glGetProgramiv(int program, int pname, int[] params, int offset); + public static native String glGetShaderInfoLog(int shader); + public static native void glGetShaderiv(int shader, int pname, int[] params, int offset); + public static native String glGetString(int name); + public static native int glGetUniformLocation(int program, String name); + public static native boolean glIsFramebuffer(int framebuffer); + public static native boolean glIsRenderbuffer(int renderbuffer); + public static native void glLineWidth(float width); + public static native void glLinkProgram(int program); + public static native void glPixelStorei(int pname, int param); + public static native void glPolygonOffset(float factor, float units); + public static native void glReadPixels(int vpX, int vpY, int vpW, int vpH, int format, int type, Buffer pixels); + public static native void glReadPixels2(int vpX, int vpY, int vpW, int vpH, int format, int type, byte[] pixels, int offset, int size); + public static native void glRenderbufferStorage(int target, int internalformat, int width, int height); + public static native void glScissor(int x, int y, int width, int height); + public static native void glShaderSource(int shader, String string); + public static native void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, Buffer pixels); + public static native void glTexParameteri(int target, int pname, int param); + public static native void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, Buffer pixels); + public static native void glUniform1f(int location, float x); + public static native void glUniform1fv(int location, int count, FloatBuffer v); + public static native void glUniform1fv2(int location, int count, float[] v, int offset); + public static native void glUniform1i(int location, int x); + public static native void glUniform1iv(int location, int count, IntBuffer v); + public static native void glUniform1iv2(int location, int count, int[] v, int offset); + public static native void glUniform2f(int location, float x, float y); + public static native void glUniform2fv(int location, int count, FloatBuffer v); + public static native void glUniform2fv2(int location, int count, float[] v, int offset); + public static native void glUniform3f(int location, float x, float y, float z); + public static native void glUniform3fv(int location, int count, FloatBuffer v); + public static native void glUniform3fv2(int location, int count, float[] v, int offset); + public static native void glUniform4f(int location, float x, float y, float z, float w); + public static native void glUniform4fv(int location, int count, FloatBuffer v); + public static native void glUniform4fv2(int location, int count, float[] v, int offset); + public static native void glUniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer value); + public static native void glUniformMatrix3fv2(int location, int count, boolean transpose, float[] value, int offset); + public static native void glUniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer value); + public static native void glUniformMatrix4fv2(int location, int count, boolean transpose, float[] value, int offset); + public static native void glUseProgram(int program); + //public static native void glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, byte[] ptr, int offset); + public static native void glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, Buffer ptr); + public static native void glVertexAttribPointer2(int indx, int size, int type, boolean normalized, int stride, int offset); + public static native void glViewport(int x, int y, int width, int height); + + + public static void checkGLError() { + if (!ENABLE_ERROR_CHECKING) { + return; + } + int error = glGetError(); + if (error != 0) { + String message = null;//GLU.gluErrorString(error); + if (message == null) { + throw new RendererException("An unknown [" + error + "] OpenGL error has occurred."); + } else { + throw new RendererException("An OpenGL error has occurred: " + message); + } + } + } + + /* + public static String gluErrorString(int error) { + switch (error) { + case GL10.GL_NO_ERROR: + return "no error"; + case GL10.GL_INVALID_ENUM: + return "invalid enum"; + case GL10.GL_INVALID_VALUE: + return "invalid value"; + case GL10.GL_INVALID_OPERATION: + return "invalid operation"; + case GL10.GL_STACK_OVERFLOW: + return "stack overflow"; + case GL10.GL_STACK_UNDERFLOW: + return "stack underflow"; + case GL10.GL_OUT_OF_MEMORY: + return "out of memory"; + default: + return null; + } + } + */ + +} \ No newline at end of file diff --git a/engine/src/ios/com/jme3/renderer/ios/TextureUtil.java b/engine/src/ios/com/jme3/renderer/ios/TextureUtil.java new file mode 100644 index 000000000..596df0ce4 --- /dev/null +++ b/engine/src/ios/com/jme3/renderer/ios/TextureUtil.java @@ -0,0 +1,591 @@ +package com.jme3.renderer.ios; + +//import android.graphics.Bitmap; +//import android.opengl.ETC1; +//import android.opengl.ETC1Util.ETC1Texture; +//import android.opengl.JmeIosGLES; +//import android.opengl.GLUtils; +//import com.jme3.asset.AndroidImageInfo; +import com.jme3.renderer.ios.JmeIosGLES; +import com.jme3.math.FastMath; +import com.jme3.renderer.RendererException; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TextureUtil { + + private static final Logger logger = Logger.getLogger(TextureUtil.class.getName()); + //TODO Make this configurable through appSettings + public static boolean ENABLE_COMPRESSION = true; + private static boolean NPOT = false; + private static boolean ETC1support = false; + private static boolean DXT1 = false; + private static boolean PVRTC = false; + private static boolean DEPTH24_STENCIL8 = false; + private static boolean DEPTH_TEXTURE = false; + private static boolean RGBA8 = false; + + // Same constant used by both GL_ARM_rgba8 and GL_OES_rgb8_rgba8. + private static final int GL_RGBA8 = 0x8058; + + private static final int GL_DXT1 = 0x83F0; + private static final int GL_DXT1A = 0x83F1; + + private static final int GL_DEPTH_STENCIL_OES = 0x84F9; + private static final int GL_UNSIGNED_INT_24_8_OES = 0x84FA; + private static final int GL_DEPTH24_STENCIL8_OES = 0x88F0; + + public static void loadTextureFeatures(String extensionString) { + ETC1support = extensionString.contains("GL_OES_compressed_ETC1_RGB8_texture"); + DEPTH24_STENCIL8 = extensionString.contains("GL_OES_packed_depth_stencil"); + NPOT = extensionString.contains("GL_IMG_texture_npot") + || extensionString.contains("GL_OES_texture_npot") + || extensionString.contains("GL_NV_texture_npot_2D_mipmap"); + + PVRTC = extensionString.contains("GL_IMG_texture_compression_pvrtc"); + + DXT1 = extensionString.contains("GL_EXT_texture_compression_dxt1"); + DEPTH_TEXTURE = extensionString.contains("GL_OES_depth_texture"); + + RGBA8 = extensionString.contains("GL_ARM_rgba8") || + extensionString.contains("GL_OES_rgb8_rgba8"); + + logger.log(Level.FINE, "Supports ETC1? {0}", ETC1support); + logger.log(Level.FINE, "Supports DEPTH24_STENCIL8? {0}", DEPTH24_STENCIL8); + logger.log(Level.FINE, "Supports NPOT? {0}", NPOT); + logger.log(Level.FINE, "Supports PVRTC? {0}", PVRTC); + logger.log(Level.FINE, "Supports DXT1? {0}", DXT1); + logger.log(Level.FINE, "Supports DEPTH_TEXTURE? {0}", DEPTH_TEXTURE); + logger.log(Level.FINE, "Supports RGBA8? {0}", RGBA8); + } + + /* + private static void buildMipmap(Bitmap bitmap, boolean compress) { + int level = 0; + int height = bitmap.getHeight(); + int width = bitmap.getWidth(); + + logger.log(Level.FINEST, " - Generating mipmaps for bitmap using SOFTWARE"); + + JmeIosGLES.glPixelStorei(JmeIosGLES.GL_UNPACK_ALIGNMENT, 1); + + while (height >= 1 || width >= 1) { + //First of all, generate the texture from our bitmap and set it to the according level + if (compress) { + logger.log(Level.FINEST, " - Uploading LOD level {0} ({1}x{2}) with compression.", new Object[]{level, width, height}); + uploadBitmapAsCompressed(JmeIosGLES.GL_TEXTURE_2D, level, bitmap, false, 0, 0); + } else { + logger.log(Level.FINEST, " - Uploading LOD level {0} ({1}x{2}) directly.", new Object[]{level, width, height}); + GLUtils.texImage2D(JmeIosGLES.GL_TEXTURE_2D, level, bitmap, 0); + } + + if (height == 1 || width == 1) { + break; + } + + //Increase the mipmap level + height /= 2; + width /= 2; + Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); + + // Recycle any bitmaps created as a result of scaling the bitmap. + // Do not recycle the original image (mipmap level 0) + if (level != 0) { + bitmap.recycle(); + } + + bitmap = bitmap2; + + level++; + } + } + + private static void uploadBitmapAsCompressed(int target, int level, Bitmap bitmap, boolean subTexture, int x, int y) { + if (bitmap.hasAlpha()) { + logger.log(Level.FINEST, " - Uploading bitmap directly. Cannot compress as alpha present."); + if (subTexture) { + GLUtils.texSubImage2D(target, level, x, y, bitmap); + JmeIosGLES.checkGLError(); + } else { + GLUtils.texImage2D(target, level, bitmap, 0); + JmeIosGLES.checkGLError(); + } + } else { + // Convert to RGB565 + int bytesPerPixel = 2; + Bitmap rgb565 = bitmap.copy(Bitmap.Config.RGB_565, true); + + // Put texture data into ByteBuffer + ByteBuffer inputImage = BufferUtils.createByteBuffer(bitmap.getRowBytes() * bitmap.getHeight()); + rgb565.copyPixelsToBuffer(inputImage); + inputImage.position(0); + + // Delete the copied RGB565 image + rgb565.recycle(); + + // Encode the image into the output bytebuffer + int encodedImageSize = ETC1.getEncodedDataSize(bitmap.getWidth(), bitmap.getHeight()); + ByteBuffer compressedImage = BufferUtils.createByteBuffer(encodedImageSize); + ETC1.encodeImage(inputImage, bitmap.getWidth(), + bitmap.getHeight(), + bytesPerPixel, + bytesPerPixel * bitmap.getWidth(), + compressedImage); + + // Delete the input image buffer + BufferUtils.destroyDirectBuffer(inputImage); + + // Create an ETC1Texture from the compressed image data + ETC1Texture etc1tex = new ETC1Texture(bitmap.getWidth(), bitmap.getHeight(), compressedImage); + + // Upload the ETC1Texture + if (bytesPerPixel == 2) { + int oldSize = (bitmap.getRowBytes() * bitmap.getHeight()); + int newSize = compressedImage.capacity(); + logger.log(Level.FINEST, " - Uploading compressed image to GL, oldSize = {0}, newSize = {1}, ratio = {2}", new Object[]{oldSize, newSize, (float) oldSize / newSize}); + if (subTexture) { + JmeIosGLES.glCompressedTexSubImage2D(target, + level, + x, y, + bitmap.getWidth(), + bitmap.getHeight(), + ETC1.ETC1_RGB8_OES, + etc1tex.getData().capacity(), + etc1tex.getData()); + + JmeIosGLES.checkGLError(); + } else { + JmeIosGLES.glCompressedTexImage2D(target, + level, + ETC1.ETC1_RGB8_OES, + bitmap.getWidth(), + bitmap.getHeight(), + 0, + etc1tex.getData().capacity(), + etc1tex.getData()); + + JmeIosGLES.checkGLError(); + } + +// ETC1Util.loadTexture(target, level, 0, JmeIosGLES.GL_RGB, +// JmeIosGLES.GL_UNSIGNED_SHORT_5_6_5, etc1Texture); +// } else if (bytesPerPixel == 3) { +// ETC1Util.loadTexture(target, level, 0, JmeIosGLES.GL_RGB, +// JmeIosGLES.GL_UNSIGNED_BYTE, etc1Texture); + } + + BufferUtils.destroyDirectBuffer(compressedImage); + } + } + + /** + * uploadTextureBitmap uploads a native android bitmap + */ + /* + public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean needMips) { + uploadTextureBitmap(target, bitmap, needMips, false, 0, 0); + } + + /** + * uploadTextureBitmap uploads a native android bitmap + */ + /* + public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean needMips, boolean subTexture, int x, int y) { + boolean recycleBitmap = false; + //TODO, maybe this should raise an exception when NPOT is not supported + + boolean willCompress = ENABLE_COMPRESSION && ETC1support && !bitmap.hasAlpha(); + if (needMips && willCompress) { + // Image is compressed and mipmaps are desired, generate them + // using software. + buildMipmap(bitmap, willCompress); + } else { + if (willCompress) { + // Image is compressed but mipmaps are not desired, upload directly. + logger.log(Level.FINEST, " - Uploading compressed bitmap. Mipmaps are not generated."); + uploadBitmapAsCompressed(target, 0, bitmap, subTexture, x, y); + + } else { + // Image is not compressed, mipmaps may or may not be desired. + logger.log(Level.FINEST, " - Uploading bitmap directly.{0}", + (needMips + ? " Mipmaps will be generated in HARDWARE" + : " Mipmaps are not generated.")); + if (subTexture) { + System.err.println("x : " + x + " y :" + y + " , " + bitmap.getWidth() + "/" + bitmap.getHeight()); + GLUtils.texSubImage2D(target, 0, x, y, bitmap); + JmeIosGLES.checkGLError(); + } else { + GLUtils.texImage2D(target, 0, bitmap, 0); + JmeIosGLES.checkGLError(); + } + + if (needMips) { + // No pregenerated mips available, + // generate from base level if required + JmeIosGLES.glGenerateMipmap(target); + JmeIosGLES.checkGLError(); + } + } + } + + if (recycleBitmap) { + bitmap.recycle(); + } + } + */ + + public static void uploadTextureAny(Image img, int target, int index, boolean needMips) { + /* + if (img.getEfficentData() instanceof AndroidImageInfo) { + logger.log(Level.FINEST, " === Uploading image {0}. Using BITMAP PATH === ", img); + // If image was loaded from asset manager, use fast path + AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData(); + uploadTextureBitmap(target, imageInfo.getBitmap(), needMips); + } else { + */ + logger.log(Level.FINEST, " === Uploading image {0}. Using BUFFER PATH === ", img); + boolean wantGeneratedMips = needMips && !img.hasMipmaps(); + if (wantGeneratedMips && img.getFormat().isCompressed()) { + logger.log(Level.WARNING, "Generating mipmaps is only" + + " supported for Bitmap based or non-compressed images!"); + } + + // Upload using slower path + logger.log(Level.FINEST, " - Uploading bitmap directly.{0}", + (wantGeneratedMips + ? " Mipmaps will be generated in HARDWARE" + : " Mipmaps are not generated.")); + + uploadTexture(img, target, index); + + // Image was uploaded using slower path, since it is not compressed, + // then compress it + if (wantGeneratedMips) { + // No pregenerated mips available, + // generate from base level if required + JmeIosGLES.glGenerateMipmap(target); + JmeIosGLES.checkGLError(); + } + //} + } + + private static void unsupportedFormat(Format fmt) { + throw new UnsupportedOperationException("The image format '" + fmt + "' is unsupported by the video hardware."); + } + + public static IosGLImageFormat getImageFormat(Format fmt) throws UnsupportedOperationException { + IosGLImageFormat imageFormat = new IosGLImageFormat(); + switch (fmt) { + case RGBA16: + case RGB16: + case RGB10: + case Luminance16: + case Luminance16Alpha16: + case Alpha16: + case Depth32: + case Depth32F: + throw new UnsupportedOperationException("The image format '" + + fmt + "' is not supported by OpenGL ES 2.0 specification."); + case Alpha8: + imageFormat.format = JmeIosGLES.GL_ALPHA; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + if (RGBA8) { + imageFormat.renderBufferStorageFormat = GL_RGBA8; + } else { + // Highest precision alpha supported by vanilla OGLES2 + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGBA4; + } + break; + case Luminance8: + imageFormat.format = JmeIosGLES.GL_LUMINANCE; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + if (RGBA8) { + imageFormat.renderBufferStorageFormat = GL_RGBA8; + } else { + // Highest precision luminance supported by vanilla OGLES2 + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGB565; + } + break; + case Luminance8Alpha8: + imageFormat.format = JmeIosGLES.GL_LUMINANCE_ALPHA; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + if (RGBA8) { + imageFormat.renderBufferStorageFormat = GL_RGBA8; + } else { + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGBA4; + } + break; + case RGB565: + imageFormat.format = JmeIosGLES.GL_RGB; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_SHORT_5_6_5; + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGB565; + break; + case ARGB4444: + imageFormat.format = JmeIosGLES.GL_RGBA4; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_SHORT_4_4_4_4; + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGBA4; + break; + case RGB5A1: + imageFormat.format = JmeIosGLES.GL_RGBA; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_SHORT_5_5_5_1; + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGB5_A1; + break; + case RGB8: + imageFormat.format = JmeIosGLES.GL_RGB; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + if (RGBA8) { + imageFormat.renderBufferStorageFormat = GL_RGBA8; + } else { + // Fallback: Use RGB565 if RGBA8 is not available. + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGB565; + } + break; + case BGR8: + imageFormat.format = JmeIosGLES.GL_RGB; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + if (RGBA8) { + imageFormat.renderBufferStorageFormat = GL_RGBA8; + } else { + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGB565; + } + break; + case RGBA8: + imageFormat.format = JmeIosGLES.GL_RGBA; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + if (RGBA8) { + imageFormat.renderBufferStorageFormat = GL_RGBA8; + } else { + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_RGBA4; + } + break; + case Depth: + case Depth16: + if (!DEPTH_TEXTURE) { + unsupportedFormat(fmt); + } + imageFormat.format = JmeIosGLES.GL_DEPTH_COMPONENT; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_SHORT; + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_DEPTH_COMPONENT16; + break; + case Depth24: + case Depth24Stencil8: + if (!DEPTH_TEXTURE) { + unsupportedFormat(fmt); + } + if (DEPTH24_STENCIL8) { + // NEW: True Depth24 + Stencil8 format. + imageFormat.format = GL_DEPTH_STENCIL_OES; + imageFormat.dataType = GL_UNSIGNED_INT_24_8_OES; + imageFormat.renderBufferStorageFormat = GL_DEPTH24_STENCIL8_OES; + } else { + // Vanilla OGLES2, only Depth16 available. + imageFormat.format = JmeIosGLES.GL_DEPTH_COMPONENT; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_SHORT; + imageFormat.renderBufferStorageFormat = JmeIosGLES.GL_DEPTH_COMPONENT16; + } + break; + case DXT1: + if (!DXT1) { + unsupportedFormat(fmt); + } + imageFormat.format = GL_DXT1; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + imageFormat.compress = true; + break; + case DXT1A: + if (!DXT1) { + unsupportedFormat(fmt); + } + imageFormat.format = GL_DXT1A; + imageFormat.dataType = JmeIosGLES.GL_UNSIGNED_BYTE; + imageFormat.compress = true; + break; + default: + throw new UnsupportedOperationException("Unrecognized format: " + fmt); + } + return imageFormat; + } + + public static class IosGLImageFormat { + + boolean compress = false; + int format = -1; + int renderBufferStorageFormat = -1; + int dataType = -1; + } + + private static void uploadTexture(Image img, + int target, + int index) { + + /* + if (img.getEfficentData() instanceof AndroidImageInfo) { + throw new RendererException("This image uses efficient data. " + + "Use uploadTextureBitmap instead."); + } + */ + + // Otherwise upload image directly. + // Prefer to only use power of 2 textures here to avoid errors. + Image.Format fmt = img.getFormat(); + ByteBuffer data; + if (index >= 0 || img.getData() != null && img.getData().size() > 0) { + data = img.getData(index); + } else { + data = null; + } + + int width = img.getWidth(); + int height = img.getHeight(); + + if (!NPOT) { + // Check if texture is POT + if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)) { + throw new RendererException("Non-power-of-2 textures " + + "are not supported by the video hardware " + + "and no scaling path available for image: " + img); + } + } + IosGLImageFormat imageFormat = getImageFormat(fmt); + + if (data != null) { + JmeIosGLES.glPixelStorei(JmeIosGLES.GL_UNPACK_ALIGNMENT, 1); + JmeIosGLES.checkGLError(); + } + + int[] mipSizes = img.getMipMapSizes(); + int pos = 0; + if (mipSizes == null) { + if (data != null) { + mipSizes = new int[]{data.capacity()}; + } else { + mipSizes = new int[]{width * height * fmt.getBitsPerPixel() / 8}; + } + } + + for (int i = 0; i < mipSizes.length; i++) { + int mipWidth = Math.max(1, width >> i); + int mipHeight = Math.max(1, height >> i); + + if (data != null) { + data.position(pos); + data.limit(pos + mipSizes[i]); + } + + if (imageFormat.compress && data != null) { + JmeIosGLES.glCompressedTexImage2D(target, + i, + imageFormat.format, + mipWidth, + mipHeight, + 0, + data.remaining(), + data); + } else { + JmeIosGLES.glTexImage2D(target, + i, + imageFormat.format, + mipWidth, + mipHeight, + 0, + imageFormat.format, + imageFormat.dataType, + data); + } + JmeIosGLES.checkGLError(); + + pos += mipSizes[i]; + } + } + + /** + * Update the texture currently bound to target at with data from the given + * Image at position x and y. The parameter index is used as the zoffset in + * case a 3d texture or texture 2d array is being updated. + * + * @param image Image with the source data (this data will be put into the + * texture) + * @param target the target texture + * @param index the mipmap level to update + * @param x the x position where to put the image in the texture + * @param y the y position where to put the image in the texture + */ + public static void uploadSubTexture( + Image img, + int target, + int index, + int x, + int y) { + //TODO: + /* + if (img.getEfficentData() instanceof AndroidImageInfo) { + AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData(); + uploadTextureBitmap(target, imageInfo.getBitmap(), true, true, x, y); + return; + } + */ + + // Otherwise upload image directly. + // Prefer to only use power of 2 textures here to avoid errors. + Image.Format fmt = img.getFormat(); + ByteBuffer data; + if (index >= 0 || img.getData() != null && img.getData().size() > 0) { + data = img.getData(index); + } else { + data = null; + } + + int width = img.getWidth(); + int height = img.getHeight(); + + if (!NPOT) { + // Check if texture is POT + if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)) { + throw new RendererException("Non-power-of-2 textures " + + "are not supported by the video hardware " + + "and no scaling path available for image: " + img); + } + } + IosGLImageFormat imageFormat = getImageFormat(fmt); + + if (data != null) { + JmeIosGLES.glPixelStorei(JmeIosGLES.GL_UNPACK_ALIGNMENT, 1); + JmeIosGLES.checkGLError(); + } + + int[] mipSizes = img.getMipMapSizes(); + int pos = 0; + if (mipSizes == null) { + if (data != null) { + mipSizes = new int[]{data.capacity()}; + } else { + mipSizes = new int[]{width * height * fmt.getBitsPerPixel() / 8}; + } + } + + for (int i = 0; i < mipSizes.length; i++) { + int mipWidth = Math.max(1, width >> i); + int mipHeight = Math.max(1, height >> i); + + if (data != null) { + data.position(pos); + data.limit(pos + mipSizes[i]); + } + + if (imageFormat.compress && data != null) { + JmeIosGLES.glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, imageFormat.format, data.remaining(), data); + JmeIosGLES.checkGLError(); + } else { + JmeIosGLES.glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, imageFormat.format, imageFormat.dataType, data); + JmeIosGLES.checkGLError(); + } + + pos += mipSizes[i]; + } + } +} diff --git a/engine/src/ios/com/jme3/system/ios/IGLESContext.java b/engine/src/ios/com/jme3/system/ios/IGLESContext.java new file mode 100644 index 000000000..d96962244 --- /dev/null +++ b/engine/src/ios/com/jme3/system/ios/IGLESContext.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system.ios; + +import com.jme3.input.*; +import com.jme3.input.controls.SoftTextDialogInputListener; +import com.jme3.input.dummy.DummyKeyInput; +import com.jme3.input.dummy.DummyMouseInput; +import com.jme3.renderer.ios.IGLESShaderRenderer; +import com.jme3.system.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class IGLESContext implements JmeContext { + + private static final Logger logger = Logger.getLogger(IGLESContext.class.getName()); + protected final AtomicBoolean created = new AtomicBoolean(false); + protected final AtomicBoolean renderable = new AtomicBoolean(false); + protected final AtomicBoolean needClose = new AtomicBoolean(false); + protected AppSettings settings = new AppSettings(true); + protected boolean autoFlush = true; + + /* + * >= OpenGL ES 2.0 (iOS) + */ + protected IGLESShaderRenderer renderer; + protected Timer timer; + protected SystemListener listener; + protected int minFrameDuration = 0; // No FPS cap + + public IGLESContext() { + logger.log(Level.FINE, "IGLESContext constructor"); + } + + @Override + public Type getType() { + return Type.Display; + } + + @Override + public void setSettings(AppSettings settings) { + logger.log(Level.FINE, "IGLESContext setSettings"); + this.settings.copyFrom(settings); + /* + if (androidInput != null) { + androidInput.loadSettings(settings); + } + */ + + } + + @Override + public void setSystemListener(SystemListener listener) { + logger.log(Level.FINE, "IGLESContext setSystemListener"); + this.listener = listener; + } + + @Override + public AppSettings getSettings() { + return settings; + } + + @Override + public com.jme3.renderer.Renderer getRenderer() { + logger.log(Level.FINE, "IGLESContext getRenderer"); + return renderer; + } + + @Override + public MouseInput getMouseInput() { + return new DummyMouseInput(); + } + + @Override + public KeyInput getKeyInput() { + return new DummyKeyInput(); + } + + @Override + public JoyInput getJoyInput() { + /* + if (androidSensorJoyInput == null) { + androidSensorJoyInput = new AndroidSensorJoyInput(); + } + return androidSensorJoyInput; + */ + return null;// new DummySensorJoyInput(); + } + + @Override + public TouchInput getTouchInput() { + //return androidInput; + return null;// new DummyTouchInput(); + } + + @Override + public Timer getTimer() { + return timer; + } + + @Override + public void setTitle(String title) { + } + + @Override + public boolean isCreated() { + logger.log(Level.FINE, "IGLESContext isCreated"); + return created.get(); + } + + @Override + public void setAutoFlushFrames(boolean enabled) { + this.autoFlush = enabled; + } + + @Override + public boolean isRenderable() { + logger.log(Level.FINE, "IGLESContext isRenderable"); + return true;// renderable.get(); + } + + @Override + public void create(boolean waitFor) { + logger.log(Level.FINE, "IGLESContext create"); + renderer = new IGLESShaderRenderer(); + timer = new NanoTimer(); + +//synchronized (createdLock){ + created.set(true); + //createdLock.notifyAll(); + //} + + listener.initialize(); + + if (waitFor) { + //waitFor(true); + } + logger.log(Level.FINE, "IGLESContext created"); + } + + public void create() { + create(false); + } + + @Override + public void restart() { + } + + @Override + public void destroy(boolean waitFor) { + logger.log(Level.FINE, "IGLESContext destroy"); + listener.destroy(); + needClose.set(true); + if (waitFor) { + //waitFor(false); + } + } + + public void destroy() { + destroy(true); + } + + protected void waitFor(boolean createdVal) { + while (renderable.get() != createdVal) { + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + } + } + } +} \ No newline at end of file diff --git a/engine/src/ios/com/jme3/system/ios/IosAssetManager.java b/engine/src/ios/com/jme3/system/ios/IosAssetManager.java index 42f1736d6..edddf4f57 100644 --- a/engine/src/ios/com/jme3/system/ios/IosAssetManager.java +++ b/engine/src/ios/com/jme3/system/ios/IosAssetManager.java @@ -35,6 +35,7 @@ import com.jme3.asset.AssetLoader; import com.jme3.asset.DesktopAssetManager; import com.jme3.asset.TextureKey; import com.jme3.asset.plugins.ClasspathLocator; +import com.jme3.audio.plugins.WAVLoader; import com.jme3.texture.Texture; import java.io.InputStream; import java.net.URL; @@ -87,8 +88,10 @@ public class IosAssetManager extends DesktopAssetManager { registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib"); registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o"); registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt"); + registerLoader(WAVLoader.class, "wav"); - // Less common loaders (especially on Android) + // Less common loaders (especially on iOS) + registerLoaderSafe("com.jme3.audio.plugins.OGGLoader", "ogg"); registerLoaderSafe("com.jme3.texture.plugins.DDSLoader", "dds"); registerLoaderSafe("com.jme3.texture.plugins.PFMLoader", "pfm"); registerLoaderSafe("com.jme3.texture.plugins.HDRLoader", "hdr"); diff --git a/engine/src/ios/com/jme3/system/ios/IosHarness.java b/engine/src/ios/com/jme3/system/ios/IosHarness.java index 5c111c585..f3b10196e 100644 --- a/engine/src/ios/com/jme3/system/ios/IosHarness.java +++ b/engine/src/ios/com/jme3/system/ios/IosHarness.java @@ -51,4 +51,11 @@ public abstract class IosHarness extends ObjcNativeObject { public abstract void appReactivated(); public abstract void appClosed(); + + public abstract void appUpdate(); + + public abstract void appDraw(); + + public abstract void appReshape(int width, int height); + } \ No newline at end of file diff --git a/engine/src/ios/com/jme3/system/ios/JmeIosSystem.java b/engine/src/ios/com/jme3/system/ios/JmeIosSystem.java index 935dc8e77..12c1b6595 100644 --- a/engine/src/ios/com/jme3/system/ios/JmeIosSystem.java +++ b/engine/src/ios/com/jme3/system/ios/JmeIosSystem.java @@ -33,6 +33,7 @@ package com.jme3.system.ios; import com.jme3.asset.AssetManager; import com.jme3.audio.AudioRenderer; +import com.jme3.audio.android.AndroidOpenALSoftAudioRenderer; import com.jme3.system.AppSettings; import com.jme3.system.JmeContext; import com.jme3.system.JmeSystemDelegate; @@ -89,7 +90,7 @@ public class JmeIosSystem extends JmeSystemDelegate { ctx = new NullContext(); ctx.setSettings(settings); } else { - ctx = new NullContext(); + ctx = new IGLESContext(); ctx.setSettings(settings); } return ctx; @@ -97,7 +98,7 @@ public class JmeIosSystem extends JmeSystemDelegate { @Override public AudioRenderer newAudioRenderer(AppSettings settings) { - throw new UnsupportedOperationException("Not supported yet."); + return new AndroidOpenALSoftAudioRenderer(); } @Override diff --git a/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java b/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java index 7ee6edcf4..0d479ebc1 100644 --- a/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java +++ b/sdk/jme3-blender/src/com/jme3/gde/blender/BlenderTool.java @@ -250,7 +250,10 @@ public class BlenderTool { } private static File getBlenderSettingsFolder() { - File blender = InstalledFileLocator.getDefault().locate(getBlenderOsPath() + "/2.67", null, false); + File blender = InstalledFileLocator.getDefault().locate(getBlenderOsPath() + "/2.69", null, false); + if (blender == null) { + blender = InstalledFileLocator.getDefault().locate(getBlenderOsPath() + "/2.67", null, false); + } if (blender == null) { DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Error finding Blender settings")); logger.log(Level.SEVERE, "Error finding Blender settings"); diff --git a/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/Blender3dsDataObject.java b/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/Blender3dsDataObject.java index e6e623b98..8623d7ee0 100644 --- a/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/Blender3dsDataObject.java +++ b/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/Blender3dsDataObject.java @@ -4,7 +4,6 @@ */ package com.jme3.gde.blender.filetypes; -import com.jme3.gde.core.assets.SpatialAssetDataObject; import java.io.IOException; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; @@ -20,65 +19,65 @@ import org.openide.util.NbBundle.Messages; "LBL_Blender3ds_LOADER=3DS Files (via Blender)" }) @MIMEResolver.ExtensionRegistration( - displayName = "#LBL_Blender3ds_LOADER", -mimeType = "application/x-3ds", -extension = {"3ds", "3DS"}) + displayName = "#LBL_Blender3ds_LOADER", + mimeType = "application/x-3ds", + extension = {"3ds", "3DS"}) @DataObject.Registration( - mimeType = "application/x-3ds", -iconBase = "com/jme3/gde/blender/blender.png", -displayName = "#LBL_Blender3ds_LOADER", -position = 300) + mimeType = "application/x-3ds", + iconBase = "com/jme3/gde/blender/blender.png", + displayName = "#LBL_Blender3ds_LOADER", + position = 300) @ActionReferences({ @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "System", id = "org.openide.actions.OpenAction"), - position = 100, - separatorAfter = 200), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.OpenAction"), + position = 100, + separatorAfter = 200), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "Edit", id = "org.openide.actions.CutAction"), - position = 300), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "Edit", id = "org.openide.actions.CutAction"), + position = 300), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), - position = 400, - separatorAfter = 500), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), + position = 400, + separatorAfter = 500), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), - position = 600), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), + position = 600), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "System", id = "org.openide.actions.RenameAction"), - position = 700, - separatorAfter = 800), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.RenameAction"), + position = 700, + separatorAfter = 800), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), - position = 900, - separatorAfter = 1000), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), + position = 900, + separatorAfter = 1000), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), - position = 1100, - separatorAfter = 1200), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), + position = 1100, + separatorAfter = 1200), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "System", id = "org.openide.actions.ToolsAction"), - position = 1300), + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.ToolsAction"), + position = 1300), @ActionReference( - path = "Loaders/application/x-3ds/Actions", - id = - @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), - position = 1400) + path = "Loaders/application/x-3ds/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), + position = 1400) }) public class Blender3dsDataObject extends AbstractBlenderImportDataObject { diff --git a/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/BlenderFbxDataObject.java b/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/BlenderFbxDataObject.java new file mode 100644 index 000000000..31d29ea22 --- /dev/null +++ b/sdk/jme3-blender/src/com/jme3/gde/blender/filetypes/BlenderFbxDataObject.java @@ -0,0 +1,93 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.blender.filetypes; + +import java.io.IOException; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.MIMEResolver; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectExistsException; +import org.openide.loaders.MultiFileLoader; +import org.openide.util.NbBundle.Messages; + +@Messages({ + "LBL_BlenderFbx_LOADER=Files of BlenderFbx" +}) +@MIMEResolver.ExtensionRegistration( + displayName = "#LBL_BlenderFbx_LOADER", + mimeType = "application/fbx", + extension = {"fbx"}) +@DataObject.Registration( + mimeType = "application/fbx", + iconBase = "com/jme3/gde/blender/blender.png", + displayName = "#LBL_BlenderFbx_LOADER", + position = 300) +@ActionReferences({ + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.OpenAction"), + position = 100, + separatorAfter = 200), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "Edit", id = "org.openide.actions.CutAction"), + position = 300), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), + position = 400, + separatorAfter = 500), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), + position = 600), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.RenameAction"), + position = 700, + separatorAfter = 800), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), + position = 900, + separatorAfter = 1000), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), + position = 1100, + separatorAfter = 1200), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.ToolsAction"), + position = 1300), + @ActionReference( + path = "Loaders/application/fbx/Actions", + id = + @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), + position = 1400) +}) +public class BlenderFbxDataObject extends AbstractBlenderImportDataObject { + + public BlenderFbxDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { + super(pf, loader); + SUFFIX = "3ds"; +// registerEditor("application/fbx", false); + } +// @Override +// protected int associateLookup() { +// return 1; +// } +} diff --git a/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java b/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java index 116d424b5..3bd7e356f 100644 --- a/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java +++ b/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/Scripts.java @@ -30,6 +30,7 @@ public class Scripts { } checkScript(folder, "import_3ds.py"); checkScript(folder, "import_dae.py"); + checkScript(folder, "import_fbx.py"); } private static void checkScript(FileObject folder, String name) { diff --git a/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py b/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py new file mode 100644 index 000000000..296932d5f --- /dev/null +++ b/sdk/jme3-blender/src/com/jme3/gde/blender/scripts/import_fbx.py @@ -0,0 +1,83 @@ +# This script invokes blender to import and save external model formats as +# .blend files to be processed further. +# +# Example usage for this importer: +# blender --background --factory-startup --python $HOME/import_3ds.py -- \ +# --i="/tmp/hello.3ds" \ +# --o="/tmp/hello.blend" \ +# +# See blender --help for details. + +import bpy + +# Imports a file using importer +def import_file(file_path): + # Import the model + bpy.ops.import_scene.fbx(filepath = file_path) + +# Clear existing objects. +def clear_scene(): + scene = bpy.context.scene + scene.camera = None + for obj in scene.objects: + scene.objects.unlink(obj) + +# Save current scene as .blend file +def save_file(save_path): + # Check if output file exists already + try: + f = open(save_path, 'w') + f.close() + ok = True + except: + print("Cannot save to path %r" % save_path) + + import traceback + traceback.print_exc() + + # Save .blend file + if ok: + bpy.ops.wm.save_as_mainfile(filepath=save_path) + +def main(): + import sys # to get command line args + import argparse # to parse options for us and print a nice help message + + # get the args passed to blender after "--", all of which are ignored by + # blender so scripts may receive their own arguments + argv = sys.argv + + if "--" not in argv: + argv = [] # as if no args are passed + else: + argv = argv[argv.index("--") + 1:] # get all args after "--" + + # When --help or no args are given, print this help + usage_text = \ + "Run blender in background mode with this script:" + " blender --background --factory-startup --python " + __file__ + " -- [options]" + + parser = argparse.ArgumentParser(description=usage_text) + + # Possible types are: string, int, long, choice, float and complex. + parser.add_argument("-i", "--input", dest="file_path", metavar='FILE', + help="Import the specified file") + parser.add_argument("-o", "--output", dest="save_path", metavar='FILE', + help="Save the generated file to the specified path") + + args = parser.parse_args(argv) # In this example we wont use the args + + if not argv: + parser.print_help() + return + + # Run the conversion + clear_scene() + import_file(args.file_path) + save_file(args.save_path) + + print("batch job finished, exiting") + + +if __name__ == "__main__": + main() diff --git a/sdk/jme3-core/src/com/jme3/gde/core/filters/AbstractFilterNode.java b/sdk/jme3-core/src/com/jme3/gde/core/filters/AbstractFilterNode.java index 35400bb61..1413099b0 100644 --- a/sdk/jme3-core/src/com/jme3/gde/core/filters/AbstractFilterNode.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/filters/AbstractFilterNode.java @@ -35,6 +35,7 @@ import com.jme3.gde.core.filters.actions.EnableFiterAction; import com.jme3.gde.core.icons.IconList; import com.jme3.gde.core.properties.SceneExplorerProperty; import com.jme3.gde.core.properties.ScenePropertyChangeListener; +import com.jme3.gde.core.scene.SceneSyncListener; import com.jme3.gde.core.util.PropertyUtils; import com.jme3.post.Filter; import java.awt.Image; @@ -59,7 +60,7 @@ import org.openide.util.actions.SystemAction; * @author normenhansen */ @SuppressWarnings("unchecked") -public abstract class AbstractFilterNode extends AbstractNode implements FilterNode, ScenePropertyChangeListener { +public abstract class AbstractFilterNode extends AbstractNode implements FilterNode, ScenePropertyChangeListener, SceneSyncListener { protected boolean readOnly = false; protected DataObject dataObject; @@ -112,6 +113,18 @@ public abstract class AbstractFilterNode extends AbstractNode implements FilterN }; } + public void syncSceneData(float tpf) { + //TODO: precache structure to avoid locks? Do it backwards, sending the actual bean value? + for (PropertySet propertySet : getPropertySets()) { + for (Property property : propertySet.getProperties()) { + if(property instanceof SceneExplorerProperty){ + SceneExplorerProperty prop = (SceneExplorerProperty)property; + prop.syncValue(); + } + } + } + } + @Override public Action getPreferredAction() { return Actions.alwaysEnabled(new EnableFiterAction(this), "Toggle enabled", "", false); @@ -222,8 +235,10 @@ public abstract class AbstractFilterNode extends AbstractNode implements FilterN if (name.equals("Name")) { setName((String)after); } - fireSave(true); firePropertyChange(name, before, after); + if (!SceneExplorerProperty.PROP_INIT_CHANGE.equals(type)) { + fireSave(true); + } } public Filter getFilter() { diff --git a/sdk/nbi/stub/ext/infra/build/products/blender-linux-x64/build.properties b/sdk/nbi/stub/ext/infra/build/products/blender-linux-x64/build.properties index d42a77753..80025b8d2 100644 --- a/sdk/nbi/stub/ext/infra/build/products/blender-linux-x64/build.properties +++ b/sdk/nbi/stub/ext/infra/build/products/blender-linux-x64/build.properties @@ -103,9 +103,9 @@ product.logic.1.path=${nbproject.dist.dir}/${nbproject.dist.file.name} # * indices should start with 1 product.data.length=1 product.data.1.zip=false -product.data.1.uri=http://download.blender.org/release/Blender2.67/blender-2.67b-linux-glibc211-x86_64.tar.bz2 -product.data.tar=blender-2.67b-linux-glibc211-x86_64.tar.bz2 -product.data.sub.dir=blender-2.67b-linux-glibc211-x86_64 +product.data.1.uri=http://download.blender.org/release/Blender2.69/blender-2.69-linux-glibc211-x86_64.tar.bz2 +product.data.tar=blender-2.69-linux-glibc211-x86_64.tar.bz2 +product.data.sub.dir=blender-2.69-linux-glibc211-x86_64 # modificator for the required disk space parameter; the core value will be the # sum of unzipped unstallation data files diff --git a/sdk/nbi/stub/ext/infra/build/products/blender-linux-x86/build.properties b/sdk/nbi/stub/ext/infra/build/products/blender-linux-x86/build.properties index 65f48bb69..001bf2a09 100644 --- a/sdk/nbi/stub/ext/infra/build/products/blender-linux-x86/build.properties +++ b/sdk/nbi/stub/ext/infra/build/products/blender-linux-x86/build.properties @@ -103,9 +103,9 @@ product.logic.1.path=${nbproject.dist.dir}/${nbproject.dist.file.name} # * indices should start with 1 product.data.length=1 product.data.1.zip=false -product.data.1.uri=http://download.blender.org/release/Blender2.67/blender-2.67b-linux-glibc211-i686.tar.bz2 -product.data.tar=blender-2.67b-linux-glibc211-i686.tar.bz2 -product.data.sub.dir=blender-2.67b-linux-glibc211-i686 +product.data.1.uri=http://download.blender.org/release/Blender2.69/blender-2.69-linux-glibc211-i686.tar.bz2 +product.data.tar=blender-2.69-linux-glibc211-i686.tar.bz2 +product.data.sub.dir=blender-2.69-linux-glibc211-i686 # modificator for the required disk space parameter; the core value will be the # sum of unzipped unstallation data files diff --git a/sdk/nbi/stub/ext/infra/build/products/blender-macosx/build.properties b/sdk/nbi/stub/ext/infra/build/products/blender-macosx/build.properties index e5eaa6708..b009bc2ec 100644 --- a/sdk/nbi/stub/ext/infra/build/products/blender-macosx/build.properties +++ b/sdk/nbi/stub/ext/infra/build/products/blender-macosx/build.properties @@ -104,7 +104,7 @@ product.logic.1.path=${nbproject.dist.dir}/${nbproject.dist.file.name} product.data.length=1 product.data.1.zip=true #normen -product.data.1.uri=http://download.blender.org/release/Blender2.67/blender-2.67b-OSX_10.6-x86_64.zip +product.data.1.uri=http://download.blender.org/release/Blender2.69/blender-2.69-OSX_10.6-x86_64.zip product.data.root=Blender product.data.sub.dir=Blender diff --git a/sdk/nbi/stub/ext/infra/build/products/blender-windows-x64/build.properties b/sdk/nbi/stub/ext/infra/build/products/blender-windows-x64/build.properties index 42d534239..a9a684573 100644 --- a/sdk/nbi/stub/ext/infra/build/products/blender-windows-x64/build.properties +++ b/sdk/nbi/stub/ext/infra/build/products/blender-windows-x64/build.properties @@ -103,8 +103,8 @@ product.logic.1.path=${nbproject.dist.dir}/${nbproject.dist.file.name} # * indices should start with 1 product.data.length=1 product.data.1.zip=true -product.data.1.uri=http://download.blender.org/release/Blender2.67/blender-2.67b-windows64.zip -product.data.sub.dir=blender-2.67b-windows64 +product.data.1.uri=http://download.blender.org/release/Blender2.69/blender-2.69-windows64.zip +product.data.sub.dir=blender-2.69-windows64 # modificator for the required disk space parameter; the core value will be the # sum of unzipped unstallation data files diff --git a/sdk/nbi/stub/ext/infra/build/products/blender-windows-x86/build.properties b/sdk/nbi/stub/ext/infra/build/products/blender-windows-x86/build.properties index d654ddfb7..31e72a069 100644 --- a/sdk/nbi/stub/ext/infra/build/products/blender-windows-x86/build.properties +++ b/sdk/nbi/stub/ext/infra/build/products/blender-windows-x86/build.properties @@ -104,8 +104,8 @@ product.logic.1.path=${nbproject.dist.dir}/${nbproject.dist.file.name} product.data.length=1 product.data.1.zip=true #normenhttp://ftp.nluug.nl/pub/graphics/blender/release//Blender2.65/blender-2.65a-windows32.zip -product.data.1.uri=http://download.blender.org/release/Blender2.67/blender-2.67b-windows32.zip -product.data.sub.dir=blender-2.67b-windows32 +product.data.1.uri=http://download.blender.org/release/Blender2.69/blender-2.69-windows32.zip +product.data.sub.dir=blender-2.69-windows32 # modificator for the required disk space parameter; the core value will be the # sum of unzipped unstallation data files diff --git a/sdk/nbproject/project.properties b/sdk/nbproject/project.properties index c2ae1c392..55e93e79a 100644 --- a/sdk/nbproject/project.properties +++ b/sdk/nbproject/project.properties @@ -6,7 +6,7 @@ app.icon.icns=jmonkeyplatform.icns #version name used for application and settings folder, no spaces! app.version=3.0 #version number used for plugins, only 3 numbers (e.g. 3.1.3) -plugins.version=3.0.4 +plugins.version=3.0.5 #used netbeans platform netbeans.platform.url=http://download.netbeans.org/netbeans/7.3.1/final/zip/netbeans-7.3.1-201306052037-javase.zip #command line args