Skip to content

Commit

Permalink
Merge branch 'main' into fix/sphere-not-facing-user
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienBousquieEPFL committed Dec 19, 2024
2 parents d470a46 + a47bc44 commit e7f729d
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
package com.github.lookupgroup27.lookup.model.map.renderables
package com.github.lookupgroup27.lookup.util.opengl

import android.graphics.Bitmap
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.lookupgroup27.lookup.model.map.renderables.label.Label
import com.github.lookupgroup27.lookup.model.map.renderables.label.LabelUtils
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith

/** Instrumented tests for LabelUtils and the Label class. */
@RunWith(AndroidJUnit4::class)
class LabelTest {

/** Tests that a Label object can be created successfully. */
@Test
fun testLabelCreation() {
val text = "Star A"
val position = floatArrayOf(1.0f, 2.0f, 3.0f)
val label = Label(text, position)

assertEquals("Label text should be 'Star A'", "Star A", label.text)
assertArrayEquals(
"Label position should match", floatArrayOf(1.0f, 2.0f, 3.0f), label.position, 0.0f)
assertNull("Label textureId should be null by default", label.textureId)
}
class LabelUtilsTest {

/** Tests that the bitmap is created successfully. */
@Test
Expand All @@ -33,7 +18,7 @@ class LabelTest {

assertNotNull("Bitmap should not be null", bitmap)
assertEquals("Bitmap width should be 256", 256, bitmap.width)
assertEquals("Bitmap height should be 128", 128, bitmap.height)
assertEquals("Bitmap height should be 256", 256, bitmap.height)
}

/** Tests that the bitmap contains non-transparent pixels. */
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/assets/shaders/label_fragment_shader.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
precision mediump float;

uniform sampler2D uTexture;
varying vec2 vTexCoordinate;

void main() {
gl_FragColor = texture2D(uTexture, vTexCoordinate);
}
13 changes: 13 additions & 0 deletions app/src/main/assets/shaders/label_vertex_shader.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;

attribute vec4 aPosition;
attribute vec2 aTexCoordinate;

varying vec2 vTexCoordinate;

void main() {
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * aPosition;
vTexCoordinate = aTexCoordinate;
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class MapRenderer(
// Bind the texture and render the SkyBox
GLES20.glDepthMask(false)
textureManager.bindTexture(skyBoxTextureHandle)
// skyBox.draw(camera) commented out until the texture is changed to see stars
skyBox.draw(camera)
GLES20.glDepthMask(true)

val deltaTime = computeDeltaTime()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import com.github.lookupgroup27.lookup.model.map.renderables.utils.GeometryUtils
import com.github.lookupgroup27.lookup.model.map.skybox.buffers.ColorBuffer
import com.github.lookupgroup27.lookup.model.map.skybox.buffers.IndexBuffer
import com.github.lookupgroup27.lookup.model.map.skybox.buffers.VertexBuffer
import com.github.lookupgroup27.lookup.util.ShaderUtils.readShader
import com.github.lookupgroup27.lookup.util.opengl.ShaderProgram
import com.github.lookupgroup27.lookup.util.opengl.ShaderUtils.readShader

/**
* Renderer for creating circular 2D objects in an OpenGL environment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.content.Context
import android.opengl.GLES20
import android.opengl.Matrix
import com.github.lookupgroup27.lookup.model.map.Camera
import com.github.lookupgroup27.lookup.ui.map.renderables.Label
import com.github.lookupgroup27.lookup.util.opengl.Position
import com.github.lookupgroup27.lookup.util.opengl.TextureManager

/**
Expand All @@ -28,7 +30,7 @@ import com.github.lookupgroup27.lookup.util.opengl.TextureManager
*/
open class Planet(
private val context: Context,
val name: String? = "Planet",
val name: String = "Planet",
val position: FloatArray = floatArrayOf(0.0f, 0.0f, -2.0f),
var textureId: Int,
numBands: Int = SphereRenderer.DEFAULT_NUM_BANDS,
Expand All @@ -43,6 +45,8 @@ open class Planet(
protected var textureHandle: Int = 0

private var textureManager: TextureManager
private val label =
Label(context, name, Position(position[0], position[1], position[2]), 0.1f, scale)

// New properties for rotation
private var rotationAngle: Float = 0f // Current rotation angle in degrees
Expand Down Expand Up @@ -85,6 +89,7 @@ open class Planet(
* @param camera The camera used for rendering the scene.
*/
fun draw(camera: Camera, transformMatrix: FloatArray? = null) {
label.draw(camera)
val modelMatrix = FloatArray(16)
val billboardMatrix = FloatArray(16)
val mvpMatrix = FloatArray(16)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import com.github.lookupgroup27.lookup.model.map.skybox.buffers.ColorBuffer
import com.github.lookupgroup27.lookup.model.map.skybox.buffers.IndexBuffer
import com.github.lookupgroup27.lookup.model.map.skybox.buffers.TextureBuffer
import com.github.lookupgroup27.lookup.model.map.skybox.buffers.VertexBuffer
import com.github.lookupgroup27.lookup.util.ShaderUtils.readShader
import com.github.lookupgroup27.lookup.util.opengl.ShaderProgram
import com.github.lookupgroup27.lookup.util.opengl.ShaderUtils.readShader

/**
* Base class for rendering spherical 3D objects in an OpenGL environment.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package com.github.lookupgroup27.lookup.ui.map.renderables

import android.content.Context
import android.opengl.GLES20
import android.opengl.GLUtils
import android.opengl.Matrix
import com.github.lookupgroup27.lookup.model.map.Camera
import com.github.lookupgroup27.lookup.util.opengl.BufferUtils.toBuffer
import com.github.lookupgroup27.lookup.util.opengl.LabelUtils
import com.github.lookupgroup27.lookup.util.opengl.Position
import com.github.lookupgroup27.lookup.util.opengl.ShaderProgram
import com.github.lookupgroup27.lookup.util.opengl.ShaderUtils.readShader
import java.nio.FloatBuffer

/**
* A label that displays text in the 3D world.
*
* @param context The application context
* @param text The text to display on the label
* @param pos The position of the label TODO Implement this in others OpenGL classes
* @param size The size of the label
* @param objectSize The size of the object to label
*/
class Label(context: Context, text: String, var pos: Position, size: Float, objectSize: Float) {
private val shaderProgram: ShaderProgram
private val textureId: Int
private val vertexBuffer: FloatBuffer
private val texCoordBuffer: FloatBuffer

companion object {
private const val PADDING = 0.025f
}

init {
// Initialize shader program
val vertexShaderCode = readShader(context, "label_vertex_shader.glsl")
val fragmentShaderCode = readShader(context, "label_fragment_shader.glsl")

shaderProgram = ShaderProgram(vertexShaderCode, fragmentShaderCode)

// Define vertices for a quad that will display the label
// These coordinates represent a quad that fills the screen
val vertices =
floatArrayOf(
-size,
-size - objectSize - PADDING,
0f, // Bottom left
size,
-size - objectSize - PADDING,
0f, // Bottom right
-size,
size - objectSize - PADDING,
0f, // Top left
size,
size - objectSize - PADDING,
0f // Top right
)
vertexBuffer = vertices.toBuffer()

// Define texture coordinates
val texCoords =
floatArrayOf(
0f,
1f, // Bottom left
1f,
1f, // Bottom right
0f,
0f, // Top left
1f,
0f // Top right
)
texCoordBuffer = texCoords.toBuffer()

// Initialize Label texture
val textureHandles = IntArray(1)
GLES20.glGenTextures(1, textureHandles, 0)
textureId = textureHandles[0]

// Bind texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)

// Set texture parameters
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR)

// Load bitmap to OpenGL
val bitmap = LabelUtils.createLabelBitmap(text)
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0)
}

/**
* Draws the label in the 3D world.
*
* @param camera The camera used to render the label
*/
fun draw(camera: Camera) {
GLES20.glEnable(GLES20.GL_BLEND)
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)
shaderProgram.use()

// Get attribute and uniform locations
val modelMatrixHandle = GLES20.glGetUniformLocation(shaderProgram.programId, "uModelMatrix")
val viewMatrixHandle = GLES20.glGetUniformLocation(shaderProgram.programId, "uViewMatrix")
val projMatrixHandle = GLES20.glGetUniformLocation(shaderProgram.programId, "uProjMatrix")
val positionHandle = GLES20.glGetAttribLocation(shaderProgram.programId, "aPosition")
val texCoordHandle = GLES20.glGetAttribLocation(shaderProgram.programId, "aTexCoordinate")
val textureHandle = GLES20.glGetUniformLocation(shaderProgram.programId, "uTexture")

// Bind texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glUniform1i(textureHandle, 0)

// Set up vertex and texture coordinate buffers
vertexBuffer.position(0)
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer)
GLES20.glEnableVertexAttribArray(positionHandle)

texCoordBuffer.position(0)
GLES20.glVertexAttribPointer(texCoordHandle, 2, GLES20.GL_FLOAT, false, 0, texCoordBuffer)
GLES20.glEnableVertexAttribArray(texCoordHandle)

val billboardMatrix = FloatArray(16)
val modelMatrix = camera.modelMatrix.clone()

// Extract camera look direction from view matrix
val lookX = -camera.viewMatrix[2]
val lookY = -camera.viewMatrix[6]
val lookZ = -camera.viewMatrix[10]

// Create billboard rotation (this is the vector compared to the object that points up for the
// text
// Example we take a text Hello, we have:
// ↑ Hello
val upX = camera.viewMatrix[1]
val upY = camera.viewMatrix[5]
val upZ = camera.viewMatrix[9]

// Calculate right vector (cross product)
val rightX = upY * lookZ - upZ * lookY
val rightY = upZ * lookX - upX * lookZ
val rightZ = upX * lookY - upY * lookX

// Set billboard matrix
billboardMatrix[0] = -rightX
billboardMatrix[1] = -rightY
billboardMatrix[2] = -rightZ
billboardMatrix[3] = 0f

billboardMatrix[4] = upX
billboardMatrix[5] = upY
billboardMatrix[6] = upZ
billboardMatrix[7] = 0f

billboardMatrix[8] = lookX
billboardMatrix[9] = lookY
billboardMatrix[10] = lookZ
billboardMatrix[11] = 0f

billboardMatrix[12] = 0f
billboardMatrix[13] = 0f
billboardMatrix[14] = 0f
billboardMatrix[15] = 1f

// First translate to position
Matrix.translateM(modelMatrix, 0, pos.x, pos.y, pos.z)

// Then apply billboard rotation
val rotatedMatrix = FloatArray(16)
Matrix.multiplyMM(rotatedMatrix, 0, modelMatrix, 0, billboardMatrix, 0)

// Set the MVP matrix
GLES20.glUniformMatrix4fv(modelMatrixHandle, 1, false, rotatedMatrix, 0)
GLES20.glUniformMatrix4fv(viewMatrixHandle, 1, false, camera.viewMatrix, 0)
GLES20.glUniformMatrix4fv(projMatrixHandle, 1, false, camera.projMatrix, 0)

// Draw the text
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)

GLES20.glDisable(GLES20.GL_BLEND)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.github.lookupgroup27.lookup.util
package com.github.lookupgroup27.lookup.util.opengl

import java.nio.ByteBuffer
import java.nio.ByteOrder
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.github.lookupgroup27.lookup.model.map.renderables.label
package com.github.lookupgroup27.lookup.util.opengl

import android.graphics.Bitmap
import android.graphics.Canvas
Expand All @@ -15,19 +15,19 @@ object LabelUtils {
*/
fun createLabelBitmap(text: String): Bitmap {
val width = 256 // Width of the bitmap
val height = 128 // Height of the bitmap
val height = 256 // Height of the bitmap
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)

val canvas = Canvas(bitmap)
canvas.drawColor(android.graphics.Color.BLACK) // Background color

val paint = Paint()
paint.color = android.graphics.Color.WHITE // Text color
paint.textSize = 32f
paint.isAntiAlias = true

val x = 20f
val y = height / 2f
val x = width / 2f - paint.measureText(text) / 2
val y = height / 2f - (paint.descent() + paint.ascent()) / 2

val canvas = Canvas(bitmap)
canvas.drawColor(android.graphics.Color.TRANSPARENT) // Background color
canvas.drawText(text, x, y, paint)

return bitmap
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.github.lookupgroup27.lookup.util.opengl

data class Position(val x: Float, val y: Float, val z: Float)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.github.lookupgroup27.lookup.util
package com.github.lookupgroup27.lookup.util.opengl

import android.content.Context
import android.util.Log
Expand Down

0 comments on commit e7f729d

Please sign in to comment.