diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3482499..a533813 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:label="@string/app_name" android:theme="@style/AppTheme" > @@ -27,9 +27,9 @@ + android:exported="true"> diff --git a/app/src/main/assets/shaders/blend_fragment.glsl b/app/src/main/assets/shaders/blend_fragment.glsl index 60ae3db..55cfa25 100644 --- a/app/src/main/assets/shaders/blend_fragment.glsl +++ b/app/src/main/assets/shaders/blend_fragment.glsl @@ -26,18 +26,23 @@ void main() { vec4 blendColor = u_color; vec4 finalColor; + // Calculate luminance to detect dark areas (for black background transparency) + float luminance = dot(texColor.rgb, vec3(0.299, 0.587, 0.114)); + // Apply different blend modes if (u_blendMode == BLEND_ADD) { - // Additive blending: add colors together - finalColor = clamp(texColor + blendColor, 0.0, 1.0); + // Additive blending: multiply texture with color first, then add in framebuffer + finalColor.rgb = texColor.rgb * blendColor.rgb; + finalColor.a = texColor.a * blendColor.a; } else if (u_blendMode == BLEND_MULTIPLY) { // Multiplicative blending: multiply colors finalColor = texColor * blendColor; } else if (u_blendMode == BLEND_ALPHA) { - // Alpha blending: interpolate based on alpha - finalColor = mix(texColor, blendColor, blendColor.a); + // Alpha blending: preserve texture transparency + finalColor.rgb = texColor.rgb * blendColor.rgb; + finalColor.a = texColor.a * blendColor.a; } else if (u_blendMode == BLEND_XOR) { // XOR-like blending: absolute difference @@ -52,7 +57,17 @@ void main() { finalColor = texColor * blendColor; } - // Ensure alpha is reasonable + // Discard dark pixels (black background) to create transparency + if (luminance < 0.1) { + discard; + } + + // Discard completely transparent pixels from texture alpha + if (texColor.a < 0.01) { + discard; + } + + // Also discard if final alpha is too low if (finalColor.a < 0.01) { discard; } diff --git a/app/src/main/assets/shaders/color_fragment.glsl b/app/src/main/assets/shaders/color_fragment.glsl new file mode 100644 index 0000000..d9bb388 --- /dev/null +++ b/app/src/main/assets/shaders/color_fragment.glsl @@ -0,0 +1,37 @@ +#version 320 es + +precision mediump float; + +// Input from vertex shader +in vec2 v_texCoord; + +// Uniforms +uniform vec4 u_color; +uniform int u_blendMode; + +// Output color +out vec4 fragColor; + +// Blend mode constants +const int BLEND_ADD = 0; +const int BLEND_MULTIPLY = 1; +const int BLEND_ALPHA = 2; +const int BLEND_XOR = 3; + +void main() { + // Use solid color (no texture) + vec4 finalColor = u_color; + + // For XOR mode, apply some color manipulation + if (u_blendMode == BLEND_XOR) { + // Enhance color for invert effect + finalColor.rgb = 1.0 - finalColor.rgb; + } + + // Discard completely transparent pixels + if (finalColor.a < 0.01) { + discard; + } + + fragColor = finalColor; +} \ No newline at end of file diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/opengl/shaders/ShaderLoader.java b/app/src/main/java/net/t106/sinkerglwallpaper/opengl/shaders/ShaderLoader.java index c405581..dcbb035 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/opengl/shaders/ShaderLoader.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/opengl/shaders/ShaderLoader.java @@ -73,5 +73,9 @@ public static int createBasicProgram(Context context) { public static int createBlendProgram(Context context) { return createProgramFromAssets(context, "basic_vertex.glsl", "blend_fragment.glsl"); } + + public static int createColorProgram(Context context) { + return createProgramFromAssets(context, "basic_vertex.glsl", "color_fragment.glsl"); + } } } \ No newline at end of file diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/LeftFilter.java b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/LeftFilter.java index 64874bc..5a63bcb 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/LeftFilter.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/LeftFilter.java @@ -29,64 +29,27 @@ public LeftFilter() @Override protected void createShaderProgram() { - // Use blend shader program for customizable blending - shaderProgram = ShaderLoader.Programs.createBlendProgram(SinkerService.getContext()); + // Use color shader program for color-only rendering + shaderProgram = ShaderLoader.Programs.createColorProgram(SinkerService.getContext()); } @Override public void Draw(float[] viewMatrix, float[] projectionMatrix) { + // Update MVP matrix (no rotation, just basic transformation) updateMVP(viewMatrix, projectionMatrix); - + // Bind shader and set uniforms bindShader(); - - // No texture binding needed for color-only rendering - ShaderUtils.setUniform1i(textureLocation, 0); - - // Set blend mode from user settings - ShaderUtils.setUniform1i(blendModeLocation, SinkerService.blend_type); - - // Set color from user settings (convert from 0-100 range to 0.0-1.0) - int[] col = SinkerService.col; - float red = col[0] / 100.0f; - float green = col[1] / 100.0f; - float blue = col[2] / 100.0f; - float alpha = col[3] / 100.0f; - ShaderUtils.setUniform4f(colorLocation, red, green, blue, alpha); - - // Enable blending with mode based on user settings + GLES32.glEnable(GLES32.GL_BLEND); - - switch(SinkerService.blend_type) - { - // Additive - case 0: - GLES32.glBlendFunc(GLES32.GL_ONE, GLES32.GL_ONE); - break; - // Multiplicative - case 1: - GLES32.glBlendFunc(GLES32.GL_ZERO, GLES32.GL_SRC_COLOR); - break; - // Alpha - case 2: - GLES32.glBlendFunc(GLES32.GL_SRC_ALPHA, GLES32.GL_ONE); - break; - // XOR (Exclusive OR) - case 3: - GLES32.glBlendFunc(GLES32.GL_ONE_MINUS_DST_COLOR, GLES32.GL_ONE_MINUS_SRC_COLOR); - break; - default: - GLES32.glBlendFunc(GLES32.GL_SRC_ALPHA, GLES32.GL_ONE_MINUS_SRC_ALPHA); - break; - } - - // Bind VAO and draw + + ShaderUtils.setUniform4f(colorLocation, 0.2f, 0.4f, 0.60f, 0.4f); + GLES32.glBlendFunc(GLES32.GL_ONE, GLES32.GL_ONE); BufferUtils.bindVAO(vao); BufferUtils.drawQuad(); BufferUtils.unbindVAO(); - - // Disable blending + GLES32.glDisable(GLES32.GL_BLEND); } @@ -102,7 +65,7 @@ public void sizechange(boolean smollflg) // Update vertex data based on size if(smollflg) { - apex = new float[] { -0.5f, -1.5f, 0.5f, -1.5f, -0.5f, 1.5f, 0.5f, 1.5f, }; + apex = new float[] { -0.5f, -1.5f, 0.0f, -1.5f, -0.5f, 1.5f, 0.0f, 1.5f, }; } else { apex = new float[] { -0.7f, -1.5f, 0.7f, -1.5f, -0.7f, 1.5f, 0.7f, 1.5f, }; } diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/RightFilter.java b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/RightFilter.java index c3fab38..4d81c27 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/RightFilter.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/filters/RightFilter.java @@ -35,8 +35,8 @@ public RightFilter() @Override protected void createShaderProgram() { - // Use basic shader program without texture - shaderProgram = ShaderLoader.Programs.createBasicProgram(SinkerService.getContext()); + // Use color shader program for color-only rendering + shaderProgram = ShaderLoader.Programs.createColorProgram(SinkerService.getContext()); } @Override @@ -46,21 +46,17 @@ public void Draw(float[] viewMatrix, float[] projectionMatrix) { // Bind shader and set uniforms bindShader(); - - // No texture binding needed for color-only rendering - ShaderUtils.setUniform1i(textureLocation, 0); - - // Set blend mode to custom invert effect (can be simulated with XOR mode) - ShaderUtils.setUniform1i(blendModeLocation, 3); // XOR mode - - // Set filter color (pinkish) - ShaderUtils.setUniform4f(colorLocation, RED, GREEN, BLUE, ALPHA); - - // Enable special blending for invert effect + GLES32.glEnable(GLES32.GL_BLEND); + + ShaderUtils.setUniform4f(colorLocation, 0.2f, 0.4f, 0.60f, 0.4f); + GLES32.glBlendFunc(GLES32.GL_ZERO, GLES32.GL_SRC_COLOR); + BufferUtils.bindVAO(vao); + BufferUtils.drawQuad(); + BufferUtils.unbindVAO(); + + ShaderUtils.setUniform4f(colorLocation, 0.85f, 0.85f, 0.85f, 1.00f); GLES32.glBlendFunc(GLES32.GL_ONE_MINUS_DST_COLOR, GLES32.GL_ZERO); - - // Bind VAO and draw BufferUtils.bindVAO(vao); BufferUtils.drawQuad(); BufferUtils.unbindVAO(); diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/BackgroundGraveyard.java b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/BackgroundGraveyard.java index 90d7497..f9f63a8 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/BackgroundGraveyard.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/BackgroundGraveyard.java @@ -18,12 +18,6 @@ public class BackgroundGraveyard extends Graveyard { private static final float ROTATION_SPEED = 0.125f; // Positive rotation (opposite to center) private static final int MAX_COUNT = 2880; - // Color tint for background - private static final float RED = 0.375f; - private static final float GREEN = 0.04f; - private static final float BLUE = 0.09f; - private static final float ALPHA = 0.5f; - public BackgroundGraveyard() { super(); @@ -57,7 +51,7 @@ public void Draw(float[] viewMatrix, float[] projectionMatrix) { ShaderUtils.setUniform1i(blendModeLocation, 0); // Set color tint (reddish-brown tint) - ShaderUtils.setUniform4f(colorLocation, RED, GREEN, BLUE, ALPHA); + ShaderUtils.setUniform4f(colorLocation, 0.375f, 0.04f, 0.09f, 1.0f); // Enable blending for additive effect GLES32.glEnable(GLES32.GL_BLEND); diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/CenterGraveyard.java b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/CenterGraveyard.java index 593c45d..b7d0a50 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/CenterGraveyard.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/CenterGraveyard.java @@ -38,6 +38,22 @@ protected void createShaderProgram() { @Override public void Draw(float[] viewMatrix, float[] projectionMatrix) { + // android.util.Log.d("CenterGraveyard", "Draw() called"); + + // Debug: Check if shader and texture are valid + if (shaderProgram == 0) { + android.util.Log.e("CenterGraveyard", "Shader program is 0!"); + return; + } + if (SinkerService.textures[0] == 0) { + android.util.Log.e("CenterGraveyard", "Texture is 0!"); + return; + } + if (vao == 0) { + android.util.Log.e("CenterGraveyard", "VAO is 0!"); + return; + } + // Update MVP matrix with current rotation updateMVP(viewMatrix, projectionMatrix); @@ -47,16 +63,17 @@ public void Draw(float[] viewMatrix, float[] projectionMatrix) { // Set texture TextureUtils.bindTexture(0, SinkerService.textures[0]); - // Set blend mode to additive (0) + // Set blend mode to additive (0) for beautiful color effects ShaderUtils.setUniform1i(blendModeLocation, 0); // Set color (white for no tinting) - ShaderUtils.setUniform4f(colorLocation, 1.0f, 1.0f, 1.0f, 1.0f); + ShaderUtils.setUniform4f(colorLocation, 0.37f, 1.0f, 1.0f, 1.0f); - // Enable blending for additive effect + // Use additive blending for glowing effects GLES32.glEnable(GLES32.GL_BLEND); GLES32.glBlendFunc(GLES32.GL_ONE, GLES32.GL_ONE); - +// GLES32.glBlendFunc(GLES32.GL_SRC_ALPHA, GLES32.GL_ONE_MINUS_SRC_ALPHA); + // Bind VAO and draw BufferUtils.bindVAO(vao); BufferUtils.drawQuad(); diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/Graveyard.java b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/Graveyard.java index b6b407b..e1b0036 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/Graveyard.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/objects/Graveyard.java @@ -43,8 +43,16 @@ public Graveyard() { * Must be called after OpenGL context is created */ public void initGL() { + android.util.Log.d("Graveyard", getClass().getSimpleName() + " initGL() started"); + // Create shader program createShaderProgram(); + android.util.Log.d("Graveyard", getClass().getSimpleName() + " shader program: " + shaderProgram); + + if (shaderProgram == 0) { + android.util.Log.e("Graveyard", getClass().getSimpleName() + " failed to create shader program!"); + return; + } // Get uniform locations mvpMatrixLocation = ShaderUtils.getUniformLocation(shaderProgram, "u_mvpMatrix"); @@ -52,8 +60,14 @@ public void initGL() { colorLocation = ShaderUtils.getUniformLocation(shaderProgram, "u_color"); blendModeLocation = ShaderUtils.getUniformLocation(shaderProgram, "u_blendMode"); + android.util.Log.d("Graveyard", getClass().getSimpleName() + " uniform locations: mvp=" + mvpMatrixLocation + + ", texture=" + textureLocation + ", color=" + colorLocation + ", blend=" + blendModeLocation); + // Create VAO and VBOs createBuffers(); + android.util.Log.d("Graveyard", getClass().getSimpleName() + " VAO: " + vao); + + android.util.Log.d("Graveyard", getClass().getSimpleName() + " initGL() completed"); } /** diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/services/SinkerService.java b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/services/SinkerService.java index a72301d..7b9af82 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/rendering/services/SinkerService.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/rendering/services/SinkerService.java @@ -69,6 +69,9 @@ public MyRenderer() @Override public void onDrawFrame(javax.microedition.khronos.opengles.GL10 gl) { + // Reset OpenGL state to known values + resetOpenGLState(); + // Clear screen GLES32.glClear(GLES32.GL_COLOR_BUFFER_BIT); @@ -83,12 +86,52 @@ public void onDrawFrame(javax.microedition.khronos.opengles.GL10 gl) { lf.Update(deltaTime); rf.Update(deltaTime); - // Draw objects + // Draw objects - filters first, then graveyards bgy.Draw(viewMatrix, projectionMatrix); cgy.Draw(viewMatrix, projectionMatrix); lf.Draw(viewMatrix, projectionMatrix); rf.Draw(viewMatrix, projectionMatrix); } + + private void resetOpenGLState() { + // Reset only binding states, not capabilities that objects need to control + GLES32.glUseProgram(0); + GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, 0); + GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, 0); + GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, 0); + + // Don't reset blend, depth test, or cull face as objects may need them + // Reset vertex attribute arrays + for (int i = 0; i < 8; i++) { + GLES32.glDisableVertexAttribArray(i); + } + } + + private void drawWithStateIsolation(Runnable drawCommand) { + // Save current OpenGL binding state (not capabilities) + int[] currentProgram = new int[1]; + int[] currentTexture = new int[1]; + int[] currentArrayBuffer = new int[1]; + + GLES32.glGetIntegerv(GLES32.GL_CURRENT_PROGRAM, currentProgram, 0); + GLES32.glGetIntegerv(GLES32.GL_TEXTURE_BINDING_2D, currentTexture, 0); + GLES32.glGetIntegerv(GLES32.GL_ARRAY_BUFFER_BINDING, currentArrayBuffer, 0); + + try { + // Execute draw command + drawCommand.run(); + } finally { + // Restore only binding states, let objects control their own capabilities + GLES32.glUseProgram(currentProgram[0]); + GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, currentTexture[0]); + GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, currentArrayBuffer[0]); + + // Reset vertex attribute arrays + for (int i = 0; i < 8; i++) { + GLES32.glDisableVertexAttribArray(i); + } + } + } @Override public void onSurfaceChanged(javax.microedition.khronos.opengles.GL10 gl, int wid, int hei) { GLES32.glViewport(0, 0, wid, hei); @@ -139,6 +182,9 @@ public void onSurfaceCreated(javax.microedition.khronos.opengles.GL10 gl, javax. if (newTextures != null) { textures[0] = newTextures[0]; // Original texture textures[1] = newTextures[1]; // Flipped texture + android.util.Log.d("SinkerService", "Textures loaded: " + textures[0] + ", " + textures[1]); + } else { + android.util.Log.e("SinkerService", "Failed to load textures!"); } // Set background color diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/ui/activities/SettingsActivity.java b/app/src/main/java/net/t106/sinkerglwallpaper/ui/activities/SettingsActivity.java index e918588..c54e4b4 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/ui/activities/SettingsActivity.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/ui/activities/SettingsActivity.java @@ -13,11 +13,17 @@ public class SettingsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle(R.string.title_activity_settings); if (savedInstanceState == null) { getSupportFragmentManager() .beginTransaction() - .replace(android.R.id.content, new SettingsFragment()) + .replace(R.id.settings_container, new SettingsFragment()) .commit(); } } diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SeekBarPreference.java b/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SeekBarPreference.java index c814a23..fa1ecf0 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SeekBarPreference.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SeekBarPreference.java @@ -25,6 +25,15 @@ public class SeekBarPreference extends DialogPreference{ public SeekBarPreference(Context context, AttributeSet attrs) { super(context, attrs); + init(context); + } + + public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { cxt = context; SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(cxt); col[0] = sp.getInt("col_R", 50); diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SizeChangePreference.java b/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SizeChangePreference.java index 24dd0bc..77f44dc 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SizeChangePreference.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/SizeChangePreference.java @@ -23,6 +23,15 @@ public class SizeChangePreference extends DialogPreference { public SizeChangePreference(Context context, AttributeSet attrs) { super(context, attrs); + init(context); + } + + public SizeChangePreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { cxt = context; SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(cxt); tmp_prog = sp.getInt("size", 200); diff --git a/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/TextBoxPreference.java b/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/TextBoxPreference.java index e5050bd..916b1b9 100644 --- a/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/TextBoxPreference.java +++ b/app/src/main/java/net/t106/sinkerglwallpaper/ui/preferences/TextBoxPreference.java @@ -12,6 +12,11 @@ public TextBoxPreference(Context context, AttributeSet attrs) { setDialogLayoutResource(R.layout.textboxpref); } + public TextBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setDialogLayoutResource(R.layout.textboxpref); + } + public void onBindDialogView(android.view.View view) { } diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 0000000..14a7eb9 --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml index 6def607..e4c5eb7 100644 --- a/app/src/main/res/values-v11/styles.xml +++ b/app/src/main/res/values-v11/styles.xml @@ -4,7 +4,7 @@ Base application theme for API 11+. This theme completely replaces AppBaseTheme from res/values/styles.xml on API 11+ devices. --> - diff --git a/app/src/main/res/values-v14/styles.xml b/app/src/main/res/values-v14/styles.xml index 0a3271b..da940f2 100644 --- a/app/src/main/res/values-v14/styles.xml +++ b/app/src/main/res/values-v14/styles.xml @@ -5,7 +5,7 @@ AppBaseTheme from BOTH res/values/styles.xml and res/values-v11/styles.xml on API 14+ devices. --> - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 830ea6b..b777016 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -4,7 +4,7 @@ Base application theme, dependent on API level. This theme is replaced by AppBaseTheme from res/values-vXX/styles.xml on newer devices. --> -