diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 429d5d1..62ec6ce 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -15,15 +15,15 @@ */ package ve.ucv.ciens.ccg.nxtar; -import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor; -import ve.ucv.ciens.ccg.nxtar.interfaces.MulticastEnabler; -import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener; -import ve.ucv.ciens.ccg.nxtar.interfaces.Toaster; +import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor; +import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener; +import ve.ucv.ciens.ccg.nxtar.interfaces.AndroidFunctionalityWrapper; import ve.ucv.ciens.ccg.nxtar.network.RobotControlThread; import ve.ucv.ciens.ccg.nxtar.network.SensorReportThread; import ve.ucv.ciens.ccg.nxtar.network.ServiceDiscoveryThread; import ve.ucv.ciens.ccg.nxtar.network.VideoStreamingThread; import ve.ucv.ciens.ccg.nxtar.states.BaseState; +import ve.ucv.ciens.ccg.nxtar.states.CameraCalibrationState; import ve.ucv.ciens.ccg.nxtar.states.InGameState; import ve.ucv.ciens.ccg.nxtar.states.MainMenuStateBase; import ve.ucv.ciens.ccg.nxtar.states.OuyaMainMenuState; @@ -39,12 +39,14 @@ import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.controllers.Controllers; import com.badlogic.gdx.controllers.mappings.Ouya; +import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; /** *

Core of the application.

@@ -55,17 +57,23 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; *
  • Starting and destroying the networking threads.
  • *
  • Rendering debug information.
  • * - * @author Miguel Angel Astor Romero */ -public class NxtARCore extends Game implements NetworkConnectionListener{ +public class NxtARCore extends Game implements ApplicationEventsListener{ + /** + * Tag used for logging. + */ private static final String TAG = "NXTAR_CORE_MAIN"; + + /** + * Class name used for logging. + */ private static final String CLASS_NAME = NxtARCore.class.getSimpleName(); /** * Valid game states. */ public enum game_states_t { - MAIN_MENU(0), IN_GAME(1), PAUSED(2); + MAIN_MENU(0), IN_GAME(1), PAUSED(2), CALIBRATION(3); private int value; @@ -76,6 +84,10 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ public int getValue(){ return this.value; } + + public static int getNumStates(){ + return 4; + } }; /** @@ -90,31 +102,98 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ public game_states_t nextState; // Screens. + /** + *

    The application states.

    + */ private BaseState[] states; // Assorted fields. + /** + *

    Global sprite batch used for rendering trough the application.

    + */ public SpriteBatch batch; - public CVProcessor cvProc; - private Toaster toaster; + + /** + *

    The OpenCV wrapper.

    + */ + public ImageProcessor cvProc; + + /** + *

    Wrapper around the Operating System methods.

    + */ + private AndroidFunctionalityWrapper osFunction; // Networking related fields. + /** + *

    The number of connections successfully established with the NxtAR-cam application.

    + */ private int connections; - private MulticastEnabler mcastEnabler; + + /** + *

    Worker thread used to broadcast this server over the network.

    + */ private ServiceDiscoveryThread serviceDiscoveryThread; + + /** + *

    Worker thread used to receive video frames over UDP.

    + */ private VideoStreamingThread videoThread; + + /** + *

    Worker thread used to send control commands to the NxtAR-cam application. + */ private RobotControlThread robotThread; + + /** + *

    Worker thread used to receive sensor data from the NxtAR-cam application.

    + */ private SensorReportThread sensorThread; // Overlays. + /** + *

    Camera used to render the debugging overlay.

    + */ private OrthographicCamera pixelPerfectCamera; - private float fontX; - private float fontY; + + /** + *

    The base x coordinate for rendering the debugging overlay.

    + */ + private float overlayX; + + /** + *

    The base y coordinate for rendering the debugging overlay.

    + */ + private float overlayY; + + /** + *

    The font used to render the debugging overlay.

    + */ private BitmapFont font; + // Fade in/out effect fields. + /** + *

    The graphic used to render the fading effect.

    + */ private Texture fadeTexture; + + /** + *

    The interpolation value for the fading effect.

    + */ private MutableFloat alpha; + + /** + *

    The fade out interpolator.

    + */ private Tween fadeOut; + + /** + *

    The fade in interpolator.

    + */ private Tween fadeIn; + + /** + *

    Flag used to indicate if a fading effect is active.

    + */ private boolean fading; /** @@ -122,52 +201,62 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ */ public NxtARCore(Application concreteApp){ super(); + connections = 0; + + // Check if the concrete application implements all required interfaces. try{ - this.toaster = (Toaster)concreteApp; + this.osFunction = (AndroidFunctionalityWrapper)concreteApp; }catch(ClassCastException cc){ Gdx.app.debug(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement the Toaster interface. Toasting disabled."); - this.toaster = null; + this.osFunction = null; } try{ - this.mcastEnabler = (MulticastEnabler)concreteApp; - }catch(ClassCastException cc){ - Gdx.app.error(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement MulticastEnabler. Quitting."); - Gdx.app.exit(); - } - - try{ - this.cvProc = (CVProcessor)concreteApp; + this.cvProc = (ImageProcessor)concreteApp; }catch(ClassCastException cc){ Gdx.app.error(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement the CVProcessor interface. Quitting."); Gdx.app.exit(); } } + /*;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; GAME SUPERCLASS METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + /** + *

    Initialize the member fields and launch the networking threads. Also creates and + * sets the application states.

    + */ public void create(){ // Create the state objects. - states = new BaseState[3]; + states = new BaseState[game_states_t.getNumStates()]; if(Ouya.runningOnOuya) states[game_states_t.MAIN_MENU.getValue()] = new OuyaMainMenuState(this); else states[game_states_t.MAIN_MENU.getValue()] = new TabletMainMenuState(this); states[game_states_t.IN_GAME.getValue()] = new InGameState(this); states[game_states_t.PAUSED.getValue()] = new PauseState(this); + states[game_states_t.CALIBRATION.getValue()] = new CameraCalibrationState(this); + // Register controller listeners. for(BaseState state : states){ Controllers.addListener(state); } - // Set up fields. + // Set up rendering fields and settings. batch = new SpriteBatch(); + batch.enableBlending(); + batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + ShaderProgram.pedantic = false; + + // Set up the overlay font. if(ProjectConstants.DEBUG){ - // Set up the overlay font. - fontX = -((Gdx.graphics.getWidth() * ProjectConstants.OVERSCAN) / 2) + 10; - fontY = ((Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN) / 2) - 10; + overlayX = -((Gdx.graphics.getWidth() * ProjectConstants.OVERSCAN) / 2) + 10; + overlayY = ((Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN) / 2) - 10; font = new BitmapFont(); font.setColor(1.0f, 1.0f, 0.0f, 1.0f); @@ -179,7 +268,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } // Start networking. - mcastEnabler.enableMulticast(); + osFunction.enableMulticast(); Gdx.app.debug(TAG, CLASS_NAME + ".create() :: Creating network threads"); serviceDiscoveryThread = ServiceDiscoveryThread.getInstance(); @@ -187,6 +276,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ robotThread = RobotControlThread.getInstance(); sensorThread = SensorReportThread.getInstance(); + // Launch networking threads. serviceDiscoveryThread.start(); videoThread.start(); @@ -205,7 +295,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ this.setScreen(states[currState.getValue()]); states[currState.getValue()].onStateSet(); - // Prepare the fadeToBlack sprite; + // Prepare the fading effect. Pixmap pixmap = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Format.RGBA4444); pixmap.setColor(0, 0, 0, 1); pixmap.fill(); @@ -222,12 +312,18 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ Gdx.input.setInputProcessor(states[currState.getValue()]); Controllers.addListener(states[currState.getValue()]); - // Anything else. - //Gdx.app.setLogLevel(Application.LOG_INFO); - //Gdx.app.setLogLevel(Application.LOG_DEBUG); - Gdx.app.setLogLevel(Application.LOG_NONE); + // Set log level + if(ProjectConstants.DEBUG){ + Gdx.app.setLogLevel(Application.LOG_DEBUG); + }else{ + Gdx.app.setLogLevel(Application.LOG_NONE); + } } + /** + *

    Update and render the currently enabled application state. This method + * also handles state switching, rendering state transitions and global overlays.

    + */ public void render(){ super.render(); @@ -236,21 +332,23 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ states[currState.getValue()].onStateUnset(); if(!fadeOut.isStarted()){ - Gdx.app.log(TAG, CLASS_NAME + ".onRender() :: Starting fade out."); + // Start the fade out effect. fadeOut.start(); fading = true; }else{ - Gdx.app.log(TAG, CLASS_NAME + ".onRender() :: Updating fade out."); + // Update the fade out effect. fadeOut.update(Gdx.graphics.getDeltaTime()); + // When the fade out effect finishes, change to the requested state + // and launh the fade in effect. if(fadeOut.isFinished()){ + // Change to the requested state. currState = nextState; nextState = null; - states[currState.getValue()].onStateSet(); - setScreen(states[currState.getValue()]); + // Reset the fade out effect and launch the fade in. Gdx.app.log(TAG, CLASS_NAME + ".onRender() :: Freeing fade out."); fadeOut.free(); fadeOut = Tween.to(alpha, 0, 0.5f).target(1.0f).ease(TweenEquations.easeInQuint); @@ -259,16 +357,20 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } } + // If there is a fade in effect in progress. if(fadeIn.isStarted()){ if(!fadeIn.isFinished()){ + // Update it until finished. fadeIn.update(Gdx.graphics.getDeltaTime()); }else{ + // Stop and reset it when done. fading = false; fadeIn.free(); fadeIn = Tween.to(alpha, 0, 0.5f).target(0.0f).ease(TweenEquations.easeInQuint); } } + // Render the fading sprite with alpha blending. if(fading){ batch.setProjectionMatrix(pixelPerfectCamera.combined); batch.begin();{ @@ -278,28 +380,44 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ }batch.end(); } + // Render the debug overlay. if(ProjectConstants.DEBUG){ batch.setProjectionMatrix(pixelPerfectCamera.combined); batch.begin();{ // Draw the FPS overlay. - font.draw(batch, String.format("Render FPS: %d", Gdx.graphics.getFramesPerSecond()), fontX, fontY); - font.draw(batch, String.format("Total stream FPS: %d", videoThread.getFps()), fontX, fontY - font.getCapHeight() - 5); - font.draw(batch, String.format("Lost stream FPS: %d", videoThread.getLostFrames()), fontX, fontY - (2 * font.getCapHeight()) - 10); - font.draw(batch, String.format("Light sensor data: %d", sensorThread.getLightSensorReading()), fontX, fontY - (3 * font.getCapHeight()) - 15); + font.draw(batch, String.format("Render FPS: %d", Gdx.graphics.getFramesPerSecond()), overlayX, overlayY); + font.draw(batch, String.format("Total stream FPS: %d", videoThread.getFps()), overlayX, overlayY - font.getCapHeight() - 5); + font.draw(batch, String.format("Lost stream FPS: %d", videoThread.getLostFrames()), overlayX, overlayY - (2 * font.getCapHeight()) - 10); + font.draw(batch, String.format("Light sensor data: %d", sensorThread.getLightSensorReading()), overlayX, overlayY - (3 * font.getCapHeight()) - 15); }batch.end(); } } + /** + *

    Pause a currently running thread. Pausing an already paused thread is a + * no op.

    + */ public void pause(){ if(videoThread != null) videoThread.pause(); + // TODO: Ignore pausing paused threads. + // TODO: Pause the other threads. } + /** + *

    Resume a currently paused thread. Resuming an already resumed thread is a + * no op.

    + */ public void resume(){ if(videoThread != null) videoThread.play(); + // TODO: Ignore resuming resumed threads. + // TODO: Resume the other threads. } + /** + *

    Clear graphic resources

    + */ public void dispose(){ // Finish network threads. videoThread.finish(); @@ -318,6 +436,19 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } } + /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; APPLICATION EVENTS LISTENER INTERFACE METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + // TODO: Disable start game button until camera has been sucessfully calibrated. + // TODO: Add calibration listener callback. + + /** + *

    Callback used by the networking threads to notify sucessfull connections + * to the application

    + * + * @param streamName The name of the thread notifying a connection. + */ @Override public synchronized void networkStreamConnected(String streamName){ Gdx.app.log(TAG, CLASS_NAME + ".networkStreamConnected() :: Stream " + streamName + " connected."); @@ -326,16 +457,26 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ if(connections >= 3){ Gdx.app.debug(TAG, CLASS_NAME + ".networkStreamConnected() :: Stopping service broadcast."); serviceDiscoveryThread.finish(); - mcastEnabler.disableMulticast(); - toaster.showShortToast("Client connected"); + osFunction.disableMulticast(); + osFunction.showShortToast("Client connected"); ((MainMenuStateBase)states[game_states_t.MAIN_MENU.getValue()]).onClientConnected(); } } + /*;;;;;;;;;;;;;;;;;; + ; HELPER METHODS ; + ;;;;;;;;;;;;;;;;;;*/ + + /** + *

    Show a toast message on screen using the O.S. functionality + * provider.

    + * @param msg The message to show. + * @param longToast True for a lasting toast. False for a short toast. + */ public void toast(String msg, boolean longToast){ - if(toaster != null){ - if(longToast) toaster.showLongToast(msg); - else toaster.showShortToast(msg); + if(osFunction != null){ + if(longToast) osFunction.showLongToast(msg); + else osFunction.showShortToast(msg); } } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java new file mode 100644 index 0000000..674386e --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.components; + +import com.artemis.Component; +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector3; + +public class GeometryComponent extends Component { + public Vector3 position; + public Matrix3 rotation; + public Vector3 scaling; + + public GeometryComponent(){ + this.position = new Vector3(); + this.rotation = new Matrix3(); + this.scaling = new Vector3(1.0f, 1.0f, 1.0f); + } + + public GeometryComponent(Vector3 position, Matrix3 rotation, Vector3 scaling){ + this.position = new Vector3(position); + this.rotation = new Matrix3(rotation); + this.scaling = new Vector3(scaling); + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/MarkerCodeComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/MarkerCodeComponent.java new file mode 100644 index 0000000..400f503 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/MarkerCodeComponent.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.components; + +import com.artemis.Component; + +public class MarkerCodeComponent extends Component { + public int code; + + public MarkerCodeComponent(int code) throws IllegalArgumentException{ + if(code < 0 || code > 1024) + throw new IllegalArgumentException("Marker code must be between [0, 1024]."); + this.code = code; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/components/MeshComponent.java similarity index 71% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java rename to src/ve/ucv/ciens/ccg/nxtar/components/MeshComponent.java index d7d09f3..b96db52 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/components/MeshComponent.java @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ve.ucv.ciens.ccg.nxtar.interfaces; +package ve.ucv.ciens.ccg.nxtar.components; -public interface CVProcessor { - public class CVData{ - public byte[] outFrame; - public int[] markerCodes; - // TODO: Add marker location data. +import com.artemis.Component; +import com.badlogic.gdx.graphics.Mesh; + +public class MeshComponent extends Component { + public Mesh model; + + public MeshComponent(Mesh model){ + this.model = model; } - - public CVData processFrame(byte[] frame, int w, int h); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/ShaderComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/ShaderComponent.java new file mode 100644 index 0000000..af0bdbc --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/ShaderComponent.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.components; + +import ve.ucv.ciens.ccg.nxtar.graphics.shaders.CustomShaderBase; + +import com.artemis.Component; + +public class ShaderComponent extends Component { + public CustomShaderBase shader; + + public ShaderComponent(CustomShaderBase shader) throws IllegalArgumentException{ + if(shader == null) + throw new IllegalArgumentException("Shader cannot be null."); + + this.shader = shader; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/entities/BombGameEntityCreator.java b/src/ve/ucv/ciens/ccg/nxtar/entities/BombGameEntityCreator.java new file mode 100644 index 0000000..c89f294 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/BombGameEntityCreator.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.entities; + +public class BombGameEntityCreator extends EntityCreatorBase { + public BombGameEntityCreator(){ + // TODO: Empty constructor. + } + + @Override + public void createAllEntities() { + // TODO Auto-generated method stub + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/entities/EntityCreatorBase.java b/src/ve/ucv/ciens/ccg/nxtar/entities/EntityCreatorBase.java new file mode 100644 index 0000000..a5a8fa0 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/EntityCreatorBase.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.entities; + +import com.artemis.World; + +public abstract class EntityCreatorBase { + protected World world; + + public void setWorld(World world) throws IllegalArgumentException{ + if(world == null) + throw new IllegalArgumentException("World cannot be null."); + + this.world = world; + } + + public abstract void createAllEntities(); + + public abstract void dispose(); +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/entities/MarkerTestEntityCreator.java b/src/ve/ucv/ciens/ccg/nxtar/entities/MarkerTestEntityCreator.java new file mode 100644 index 0000000..be01c0b --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/MarkerTestEntityCreator.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.entities; + +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; +import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent; +import ve.ucv.ciens.ccg.nxtar.components.MeshComponent; +import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; +import ve.ucv.ciens.ccg.nxtar.exceptions.ShaderFailedToLoadException; +import ve.ucv.ciens.ccg.nxtar.graphics.shaders.CustomShaderBase; +import ve.ucv.ciens.ccg.nxtar.graphics.shaders.SingleLightPhongShader; + +import com.artemis.Entity; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Mesh; +import com.badlogic.gdx.graphics.VertexAttribute; +import com.badlogic.gdx.graphics.VertexAttributes; +import com.badlogic.gdx.graphics.VertexAttributes.Usage; +import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector3; + +public class MarkerTestEntityCreator extends EntityCreatorBase { + private static final String TAG = "MARKER_TEST_ENTITY_CREATOR"; + private static final String CLASS_NAME = MarkerTestEntityCreator.class.getSimpleName(); + + private Mesh markerMesh; + private CustomShaderBase phongShader; + + @Override + public void createAllEntities() { + MeshBuilder builder; + Matrix3 identity = new Matrix3().idt(); + Entity marker; + + // Create mesh. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Creating the meshes."); + builder = new MeshBuilder(); + builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.Normal, 3, "a_normal"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_TRIANGLES);{ + builder.setColor(1.0f, 1.0f, 1.0f, 1.0f); + Vector3 v00 = new Vector3(-0.5f, -0.5f, 0.0f); + Vector3 v10 = new Vector3(-0.5f, 0.5f, 0.0f); + Vector3 v11 = new Vector3( 0.5f, 0.5f, 0.0f); + Vector3 v01 = new Vector3( 0.5f, -0.5f, 0.0f); + Vector3 n = new Vector3(0.0f, 1.0f, 0.0f); + builder.patch(v00, v10, v11, v01, n, 10, 10); + }markerMesh = builder.end(); + + // Load the phong shader. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Loading the phong shader."); + try{ + phongShader = new SingleLightPhongShader().loadShader(); + }catch(ShaderFailedToLoadException se){ + Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + se.getMessage()); + Gdx.app.exit(); + } + + // Create the entities. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Creating the enitites."); + marker = world.createEntity(); + marker.addComponent(new GeometryComponent(new Vector3(0.0f, 0.0f, 0.0f), identity, new Vector3(1.0f, 1.0f, 1.0f))); + marker.addComponent(new MeshComponent(markerMesh)); + marker.addComponent(new ShaderComponent(phongShader)); + marker.addComponent(new MarkerCodeComponent(213)); + + // Add the entities to the world. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Adding entities to the world."); + marker.addToWorld(); + } + + @Override + public void dispose() { + if(phongShader != null && phongShader.getShaderProgram() != null) + phongShader.getShaderProgram().dispose(); + + if(markerMesh != null) + markerMesh.dispose(); + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java b/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java new file mode 100644 index 0000000..9b069a4 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.entities; + +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; +import ve.ucv.ciens.ccg.nxtar.components.MeshComponent; +import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; +import ve.ucv.ciens.ccg.nxtar.exceptions.ShaderFailedToLoadException; +import ve.ucv.ciens.ccg.nxtar.graphics.shaders.CustomShaderBase; +import ve.ucv.ciens.ccg.nxtar.graphics.shaders.SingleLightPhongShader; + +import com.artemis.Entity; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Mesh; +import com.badlogic.gdx.graphics.VertexAttribute; +import com.badlogic.gdx.graphics.VertexAttributes; +import com.badlogic.gdx.graphics.VertexAttributes.Usage; +import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector3; + +public class TestGameEntityCreator extends EntityCreatorBase { + private static final String TAG = "TEST_ENTITY_CREATOR"; + private static final String CLASS_NAME = TestGameEntityCreator.class.getSimpleName(); + + private MeshBuilder builder; + private Mesh sphereMesh; + private Mesh cubeMesh; + private Mesh capsuleMesh; + private CustomShaderBase singleLightPhongShader; + + @Override + public void createAllEntities() { + Matrix3 identity = new Matrix3(); + Entity sphere; + Entity cube; + Entity capsule1; + Entity capsule2; + + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Started."); + + identity.idt(); + + // Create the sphere. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Creating the meshes."); + builder = new MeshBuilder(); + builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.Normal, 3, "a_normal"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_TRIANGLES);{ + builder.setColor(1.0f, 1.0f, 1.0f, 1.0f); + builder.sphere(1.0f, 1.0f, 1.0f, 10, 10); + }sphereMesh = builder.end(); + + // Create the cube. + builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.Normal, 3, "a_normal"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_TRIANGLES);{ + builder.setColor(0.2f, 0.5f, 1.0f, 1.0f); + builder.box(0.5f, 0.5f, 0.5f); + }cubeMesh = builder.end(); + + // Create the capsule. + builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.Normal, 3, "a_normal"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_TRIANGLES);{ + builder.setColor(1.0f, 1.0f, 1.0f, 1.0f); + builder.capsule(0.25f, 0.5f, 10); + }capsuleMesh = builder.end(); + + // Load the phong shader. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Loading the phong shader."); + try{ + singleLightPhongShader = new SingleLightPhongShader().loadShader(); + }catch(ShaderFailedToLoadException se){ + Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + se.getMessage()); + Gdx.app.exit(); + } + + // Create the entities. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Creating the enitites."); + sphere = world.createEntity(); + sphere.addComponent(new GeometryComponent(new Vector3(0.5f, 0.5f, 0.0f), identity, new Vector3(1.0f, 1.0f, 1.0f))); + sphere.addComponent(new MeshComponent(sphereMesh)); + sphere.addComponent(new ShaderComponent(singleLightPhongShader)); + + cube = world.createEntity(); + cube.addComponent(new GeometryComponent(new Vector3(-0.5f, -0.5f, 0.0f), identity, new Vector3(1.0f, 1.0f, 1.0f))); + cube.addComponent(new MeshComponent(cubeMesh)); + cube.addComponent(new ShaderComponent(singleLightPhongShader)); + + capsule1 = world.createEntity(); + capsule1.addComponent(new GeometryComponent(new Vector3(-0.5f, 0.5f, 0.0f), identity, new Vector3(1.5f, 1.0f, 1.0f))); + capsule1.addComponent(new MeshComponent(capsuleMesh)); + capsule1.addComponent(new ShaderComponent(singleLightPhongShader)); + + capsule2 = world.createEntity(); + capsule2.addComponent(new GeometryComponent(new Vector3(0.5f, -0.5f, 0.0f), identity, new Vector3(1.0f, 1.5f, 1.0f))); + capsule2.addComponent(new MeshComponent(capsuleMesh)); + capsule2.addComponent(new ShaderComponent(singleLightPhongShader)); + + // Add the entities to the world. + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Adding entities to the world."); + sphere.addToWorld(); + cube.addToWorld(); + capsule1.addToWorld(); + capsule2.addToWorld(); + + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Finished."); + } + + @Override + public void dispose() { + if(singleLightPhongShader != null && singleLightPhongShader.getShaderProgram() != null) + singleLightPhongShader.getShaderProgram().dispose(); + + if(sphereMesh != null) + sphereMesh.dispose(); + + if(cubeMesh != null) + cubeMesh.dispose(); + + if(capsuleMesh != null) + capsuleMesh.dispose(); + } + +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java b/src/ve/ucv/ciens/ccg/nxtar/exceptions/ShaderFailedToLoadException.java similarity index 67% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java rename to src/ve/ucv/ciens/ccg/nxtar/exceptions/ShaderFailedToLoadException.java index 80a1da2..c8ca5f3 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java +++ b/src/ve/ucv/ciens/ccg/nxtar/exceptions/ShaderFailedToLoadException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Miguel Angel Astor Romero + * Copyright (C) 2014 Miguel Angel Astor Romero * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ve.ucv.ciens.ccg.nxtar.interfaces; +package ve.ucv.ciens.ccg.nxtar.exceptions; -public interface MulticastEnabler { - public void enableMulticast(); - public void disableMulticast(); +public class ShaderFailedToLoadException extends Exception { + private static final long serialVersionUID = 9989L; + + public ShaderFailedToLoadException(String msg){ + super(msg); + } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/graphics/CustomPerspectiveCamera.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/CustomPerspectiveCamera.java new file mode 100644 index 0000000..bd0f89d --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/CustomPerspectiveCamera.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.graphics; + +import com.badlogic.gdx.graphics.PerspectiveCamera; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector3; + +/** + *

    Extension of the standard LibGDX perspective camera that allows setting an + * arbitrary projection matrix when updating.

    + */ +public class CustomPerspectiveCamera extends PerspectiveCamera{ + private final Vector3 tmp = new Vector3(); + + public CustomPerspectiveCamera(float fieldOfView, float viewportWidth, float viewportHeight){ + this.fieldOfView = fieldOfView; + this.viewportWidth = viewportWidth; + this.viewportHeight = viewportHeight; + update(); + } + + public void update(Matrix4 customProjection, boolean updateFrustum){ + projection.set(customProjection); + view.setToLookAt(position, tmp.set(position).add(direction), up); + combined.set(projection); + Matrix4.mul(combined.val, view.val); + + if(updateFrustum){ + invProjectionView.set(combined); + Matrix4.inv(invProjectionView.val); + frustum.update(invProjectionView); + } + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java new file mode 100644 index 0000000..d7dab46 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.graphics; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.Vector3; + +/** + *

    A 3D light source.

    + */ +public class LightSource{ + private Vector3 position; + private Color ambientColor; + private Color diffuseColor; + private Color specularColor; + private float shinyness; + + /** + *

    Creates a default white light source positioned at (0,0,0).

    + */ + public LightSource(){ + position = new Vector3(0.0f, 0.0f, 0.0f); + ambientColor = new Color(0.15f, 0.15f, 0.15f, 1.0f); + diffuseColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + specularColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + ambientColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + shinyness = 10.0f; + } + + /** + *

    Creates a white light source at the specified position.

    + * + * @param position The location of the light source. + */ + public LightSource(Vector3 position){ + this.position = new Vector3(); + + this.position.set(position); + ambientColor = new Color(0.15f, 0.15f, 0.15f, 1.0f); + diffuseColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + specularColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + ambientColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + shinyness = 10.0f; + } + + /** + *

    Creates a custom light source.

    + * + * @param position The location of the light source. + * @param ambientColor + * @param diffuseColor + * @param specularColor + * @param shinyness The shinyness component. Must be between (0.0, 128.0]. + * @throws IllegalArgumentException When shinyness is outside the valid range. + */ + public LightSource(Vector3 position, Color ambientColor, Color diffuseColor, Color specularColor, float shinyness) throws IllegalArgumentException { + if(shinyness <= 0.0 || shinyness > 128.0) + throw new IllegalArgumentException("Shinyness must be between (0.0, 128.0]."); + + this.position = new Vector3(); + this.ambientColor = new Color(); + this.diffuseColor = new Color(); + this.ambientColor = new Color(); + this.specularColor = new Color(); + + this.position.set(position); + this.ambientColor.set(ambientColor); + this.diffuseColor.set(diffuseColor); + this.specularColor.set(specularColor); + this.shinyness = shinyness; + } + + public LightSource(LightSource light){ + this.position = new Vector3(); + this.ambientColor = new Color(); + this.diffuseColor = new Color(); + this.ambientColor = new Color(); + this.specularColor = new Color(); + + set(light); + } + + public void set(LightSource light){ + this.position.set(light.getPosition()); + this.ambientColor.set(light.getAmbientColor()); + this.diffuseColor.set(light.getDiffuseColor()); + this.specularColor.set(light.getSpecularColor()); + this.shinyness = light.shinyness; + } + + public void setPosition(float x, float y, float z){ + position.set(x, y, z); + } + + public void setPosition(Vector3 position){ + this.position.set(position); + } + + public void setAmbientColor(float r, float g, float b, float a){ + ambientColor.set(r, g, b, a); + } + + public void setAmbientColor(Color ambientColor){ + this.ambientColor.set(ambientColor); + } + + public void setDiffuseColor(float r, float g, float b, float a){ + diffuseColor.set(r, g, b, a); + } + + public void setdiffuseColor(Color diffuseColor){ + this.diffuseColor.set(diffuseColor); + } + + public void setSpecularColor(float r, float g, float b, float a){ + specularColor.set(r, g, b, a); + } + + public void setSpecularColor(Color specularColor){ + this.specularColor.set(specularColor); + } + + public void setShinyness(float shinyness) throws IllegalArgumentException { + if(shinyness <= 0.0 || shinyness > 128.0) + throw new IllegalArgumentException("Shinyness must be between (0.0, 128.0]."); + + this.shinyness = shinyness; + } + + public Vector3 getPosition(){ + return position; + } + + public Color getAmbientColor(){ + return ambientColor; + } + + public Color getDiffuseColor(){ + return diffuseColor; + } + + public Color getSpecularColor(){ + return specularColor; + } + + public float getShinyness(){ + return shinyness; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/graphics/RenderParameters.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/RenderParameters.java new file mode 100644 index 0000000..12fd477 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/RenderParameters.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.graphics; + +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector3; + +public abstract class RenderParameters { + private static Matrix4 modelViewProjection; + private static Matrix4 geometricTransformation; + private static Vector3 eyePosition; + private static LightSource lightSource1; + private static LightSource lightSource2; + + static{ + modelViewProjection = new Matrix4(); + geometricTransformation = new Matrix4(); + eyePosition = new Vector3(0.0f, 0.0f, 1.4142f); + lightSource1 = new LightSource(); + lightSource2 = new LightSource(); + } + + public static synchronized void setModelViewProjectionMatrix(Matrix4 modelViewMatrix){ + modelViewProjection.set(modelViewMatrix); + } + + public static synchronized void setTransformationMatrix(Matrix4 transformationMatrix){ + geometricTransformation.set(transformationMatrix); + } + + public static synchronized void setEyePosition(Vector3 newEyePostition){ + eyePosition.set(newEyePostition); + } + + public static synchronized void setLightSource1(LightSource newLightSource1){ + lightSource1.set(newLightSource1); + } + + public static synchronized void setLightSource2(LightSource newLightSource2){ + lightSource2.set(newLightSource2); + } + + public static synchronized Matrix4 getModelViewProjectionMatrix(){ + return modelViewProjection; + } + + public static synchronized Matrix4 getTransformationMatrix(){ + return geometricTransformation; + } + + public static synchronized Vector3 getEyePosition(){ + return eyePosition; + } + + public static synchronized LightSource getLightSource1(){ + return lightSource1; + } + + public static synchronized LightSource getLightSource2(){ + return lightSource2; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/CustomShaderBase.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/CustomShaderBase.java new file mode 100644 index 0000000..648fb22 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/CustomShaderBase.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.graphics.shaders; + +import ve.ucv.ciens.ccg.nxtar.exceptions.ShaderFailedToLoadException; + +import com.badlogic.gdx.graphics.glutils.ShaderProgram; + +public abstract class CustomShaderBase{ + protected ShaderProgram shaderProgram; + + public abstract CustomShaderBase loadShader() throws ShaderFailedToLoadException; + + public abstract void setUniforms(); + + public ShaderProgram getShaderProgram(){ + return this.shaderProgram; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPhongShader.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPhongShader.java new file mode 100644 index 0000000..66dcd54 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPhongShader.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.graphics.shaders; + +import ve.ucv.ciens.ccg.nxtar.exceptions.ShaderFailedToLoadException; +import ve.ucv.ciens.ccg.nxtar.graphics.LightSource; +import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; + +public class SingleLightPhongShader extends CustomShaderBase{ + private static String VERTEX_SHADER_PATH = "shaders/singleDiffuseLight/singleDiffuseLight_vert.glsl"; + private static String FRAGMENT_SHADER_PATH = "shaders/singleDiffuseLight/singleDiffuseLight_frag.glsl"; + + @Override + public SingleLightPhongShader loadShader() throws ShaderFailedToLoadException{ + shaderProgram = new ShaderProgram(Gdx.files.internal(VERTEX_SHADER_PATH), Gdx.files.internal(FRAGMENT_SHADER_PATH)); + + if(!shaderProgram.isCompiled()){ + throw new ShaderFailedToLoadException("SingleLightPerPixelPhongShader failed to load.\n" + shaderProgram.getLog()); + } + + return this; + } + + @Override + public void setUniforms(){ + LightSource light = RenderParameters.getLightSource1(); + float[] diffuseColor = {light.getDiffuseColor().r, light.getDiffuseColor().g, light.getDiffuseColor().b, light.getDiffuseColor().a}; + float[] ambientColor = {light.getAmbientColor().r, light.getAmbientColor().g, light.getAmbientColor().b, light.getAmbientColor().a}; + float[] specularColor = {light.getSpecularColor().r, light.getSpecularColor().g, light.getSpecularColor().b, light.getSpecularColor().a}; + float[] position = {light.getPosition().x, light.getPosition().y, light.getPosition().z, 0.0f}; + float[] shinyness = {light.getShinyness()}; + + shaderProgram.setUniformMatrix("u_projTrans", RenderParameters.getModelViewProjectionMatrix()); + shaderProgram.setUniformMatrix("u_geomTrans", RenderParameters.getTransformationMatrix()); + shaderProgram.setUniform4fv("u_lightPos", position, 0, 4); + shaderProgram.setUniform4fv("u_lightDiffuse", diffuseColor, 0, 4); + shaderProgram.setUniform4fv("u_specular", specularColor, 0, 4); + shaderProgram.setUniform4fv("u_ambient", ambientColor, 0, 4); + shaderProgram.setUniform1fv("u_shiny", shinyness, 0, 1); + shaderProgram.setUniformf("u_cameraPos", RenderParameters.getEyePosition()); + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/Toaster.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/AndroidFunctionalityWrapper.java similarity index 86% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/Toaster.java rename to src/ve/ucv/ciens/ccg/nxtar/interfaces/AndroidFunctionalityWrapper.java index bee8e60..d233374 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/Toaster.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/AndroidFunctionalityWrapper.java @@ -15,7 +15,9 @@ */ package ve.ucv.ciens.ccg.nxtar.interfaces; -public interface Toaster { +public interface AndroidFunctionalityWrapper{ public void showShortToast(String msg); public void showLongToast(String msg); + public void enableMulticast(); + public void disableMulticast(); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/NetworkConnectionListener.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ApplicationEventsListener.java similarity index 94% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/NetworkConnectionListener.java rename to src/ve/ucv/ciens/ccg/nxtar/interfaces/ApplicationEventsListener.java index a5629f4..f759925 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/NetworkConnectionListener.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ApplicationEventsListener.java @@ -15,6 +15,6 @@ */ package ve.ucv.ciens.ccg.nxtar.interfaces; -public interface NetworkConnectionListener { +public interface ApplicationEventsListener { public void networkStreamConnected(String streamName); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java new file mode 100644 index 0000000..a2effea --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.interfaces; + +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; + +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector3; + +public interface ImageProcessor{ + public class MarkerData{ + public byte[] outFrame; + public int[] markerCodes; + public Vector3[] translationVectors; + public Matrix3[] rotationMatrices; + } + + public class CalibrationData{ + public byte[] outFrame; + public float[] calibrationPoints; + } + + /** + *

    Finds up to {@link ProjectConstants.MAXIMUM_NUMBER_OF_MARKERS} markers in the input + * image and returns their codes and pose estimation in the CVMarkerData structure. The + * markers are higlihted in the input image.

    + * + * @param frame The JPEG encoded input image. + * @return A data structure containing the processed output image, the + * detected marker codes and their respective locations. + */ + public MarkerData findMarkersInFrame(byte[] frame); + + /** + *

    Attempts to detect a checkerboard calibration pattern in the input image. + * If the pattenr is found the method returns an image with the pattern + * highlighted and the spatial location of the calibration points in the + * output data structure.

    + * + * @param frame The JPEG encoded input image. + * @return A data structure containing the processed output image and the + * location of the calibration points. If the pattern was not found, the returnd + * calibration points array is null. + */ + public CalibrationData findCalibrationPattern(byte[] frame); + + /** + *

    Obtains the intrinsic camera parameters necesary for calibration.

    + */ + public void calibrateCamera(float[][] calibrationSamples, byte[] frame); + + /** + *

    Removes camera lens distortion from the input image using the + * camera parameters obtained by the calibrateCamera method.

    + * + * @return A JPEG encoded image that is the input image after distortion correction. If the + * camera has not been calibrated or OpenCV failed to load returns null. + */ + public byte[] undistortFrame(byte[] frame); + + /** + *

    Indicates if OpenCV has been sucessfully initialized and used + * to obtain the camera parameters for calibration.

    + * + * @return True if and only if OpenCV initialized succesfully and calibrateCamera has been called previously. + */ + public boolean isCameraCalibrated(); + + public float getFocalPointX(); + public float getFocalPointY(); + public float getCameraCenterX(); + public float getCameraCenterY(); +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/network/RobotControlThread.java b/src/ve/ucv/ciens/ccg/nxtar/network/RobotControlThread.java index 9250ae2..52bfa8e 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/network/RobotControlThread.java +++ b/src/ve/ucv/ciens/ccg/nxtar/network/RobotControlThread.java @@ -24,7 +24,7 @@ import java.net.Socket; import ve.ucv.ciens.ccg.networkdata.MotorEvent; import ve.ucv.ciens.ccg.networkdata.MotorEventACK; -import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener; +import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener; import ve.ucv.ciens.ccg.nxtar.network.monitors.MotorEventQueue; import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; @@ -35,7 +35,7 @@ public class RobotControlThread extends Thread { private static final String TAG = "NXTAR_CORE_ROBOTTHREAD"; private static final String CLASS_NAME = RobotControlThread.class.getSimpleName(); - private NetworkConnectionListener netListener; + private ApplicationEventsListener netListener; private ServerSocket server; private Socket client; private MotorEventQueue queue; @@ -69,7 +69,7 @@ public class RobotControlThread extends Thread { return SingletonHolder.INSTANCE; } - public void addNetworkConnectionListener(NetworkConnectionListener listener){ + public void addNetworkConnectionListener(ApplicationEventsListener listener){ netListener = listener; } diff --git a/src/ve/ucv/ciens/ccg/nxtar/network/SensorReportThread.java b/src/ve/ucv/ciens/ccg/nxtar/network/SensorReportThread.java index a30ff01..f980e63 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/network/SensorReportThread.java +++ b/src/ve/ucv/ciens/ccg/nxtar/network/SensorReportThread.java @@ -20,7 +20,7 @@ import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; -import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener; +import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener; import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; import com.badlogic.gdx.Gdx; @@ -30,7 +30,7 @@ public class SensorReportThread extends Thread { private static final String TAG = "NXTAR_CORE_ROBOTTHREAD"; private static final String CLASS_NAME = SensorReportThread.class.getSimpleName(); - private NetworkConnectionListener netListener; + private ApplicationEventsListener netListener; private ServerSocket server; private Socket client; private Object pauseMonitor; @@ -63,7 +63,7 @@ public class SensorReportThread extends Thread { return SingletonHolder.INSTANCE; } - public void addNetworkConnectionListener(NetworkConnectionListener listener){ + public void addNetworkConnectionListener(ApplicationEventsListener listener){ netListener = listener; } diff --git a/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java b/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java index a8c12f2..ac2eb60 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java +++ b/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java @@ -23,7 +23,7 @@ import java.net.DatagramSocket; import java.net.Socket; import ve.ucv.ciens.ccg.networkdata.VideoFrameDataMessage; -import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener; +import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener; import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor; import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; @@ -34,7 +34,7 @@ public class VideoStreamingThread extends Thread{ private static final String TAG = "NXTAR_CORE_VIDEOTHREAD"; private static final String CLASS_NAME = VideoStreamingThread.class.getSimpleName(); - private NetworkConnectionListener netListener; + private ApplicationEventsListener netListener; private DatagramSocket socket; private boolean protocolStarted; private boolean done; @@ -79,7 +79,7 @@ public class VideoStreamingThread extends Thread{ return SingletonHolder.INSTANCE; } - public void addNetworkConnectionListener(NetworkConnectionListener listener){ + public void addNetworkConnectionListener(ApplicationEventsListener listener){ netListener = listener; } @@ -138,7 +138,7 @@ public class VideoStreamingThread extends Thread{ VideoFrameDataMessage dataMessage; Object tmpMessage; - Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Reading message size from socket."); + //Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Reading message size from socket."); try{ packet = new DatagramPacket(size, size.length); socket.receive(packet); @@ -148,11 +148,11 @@ public class VideoStreamingThread extends Thread{ return; } - Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Creating buffers."); + //Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Creating buffers."); intSize = byteArray2Int(size); data = new byte[intSize]; - Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Reading message from socket."); + //Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Reading message from socket."); try{ packet = new DatagramPacket(data, data.length); socket.receive(packet); @@ -164,17 +164,16 @@ public class VideoStreamingThread extends Thread{ ByteArrayInputStream bais = new ByteArrayInputStream(data); - Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Saving message in monitor."); + //Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Saving message in monitor."); try{ ObjectInputStream ois = new ObjectInputStream(bais); tmpMessage = ois.readObject(); if(tmpMessage instanceof VideoFrameDataMessage){ - Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received a data message."); + //Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received a data message."); dataMessage = (VideoFrameDataMessage) tmpMessage; - Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received frame dimensions are: " + - Integer.toString(dataMessage.imageWidth) + "x" + Integer.toString(dataMessage.imageHeight)); + //Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received frame dimensions are: " + Integer.toString(dataMessage.imageWidth) + "x" + Integer.toString(dataMessage.imageHeight)); frameMonitor.setFrameDimensions(dataMessage.imageWidth, dataMessage.imageHeight); frameMonitor.setNewFrame(dataMessage.data); @@ -218,7 +217,7 @@ public class VideoStreamingThread extends Thread{ try{ pauseMonitor.wait(); }catch(InterruptedException ie){ } } } - Gdx.app.debug(TAG, CLASS_NAME + ".run() :: Receiving."); + //Gdx.app.debug(TAG, CLASS_NAME + ".run() :: Receiving."); if(netListener != null && !coreNotified && frameMonitor.getCurrentFrame() != null){ coreNotified = true; netListener.networkStreamConnected(THREAD_NAME); diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java index 731bce3..b0c2be1 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java @@ -1,88 +1,165 @@ -/* - * Copyright (C) 2014 Miguel Angel Astor Romero - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ve.ucv.ciens.ccg.nxtar.states; - -import ve.ucv.ciens.ccg.nxtar.NxtARCore; - -import com.badlogic.gdx.InputProcessor; -import com.badlogic.gdx.Screen; -import com.badlogic.gdx.controllers.Controller; -import com.badlogic.gdx.controllers.ControllerListener; -import com.badlogic.gdx.controllers.PovDirection; -import com.badlogic.gdx.math.Vector3; - -public abstract class BaseState implements Screen, ControllerListener, InputProcessor { - protected NxtARCore core; - protected boolean stateActive; - - /* STATE METHODS */ - public abstract void onStateSet(); - public abstract void onStateUnset(); - - /* SCREEN METHODS*/ - @Override - public abstract void render(float delta); - @Override - public abstract void resize(int width, int height); - @Override - public abstract void show(); - @Override - public abstract void hide(); - @Override - public abstract void pause(); - @Override - public abstract void resume(); - @Override - public abstract void dispose(); - - /* INPUT PROCESSOR METHODS. */ - @Override - public abstract boolean keyDown(int keycode); - @Override - public abstract boolean keyUp(int keycode); - @Override - public abstract boolean keyTyped(char character); - @Override - public abstract boolean touchDown(int screenX, int screenY, int pointer, int button); - @Override - public abstract boolean touchUp(int screenX, int screenY, int pointer, int button); - @Override - public abstract boolean touchDragged(int screenX, int screenY, int pointer); - @Override - public abstract boolean mouseMoved(int screenX, int screenY); - @Override - public abstract boolean scrolled(int amount); - - /* CONTROLLER LISTENER METHODS. */ - @Override - public abstract void connected(Controller controller); - @Override - public abstract void disconnected(Controller controller); - @Override - public abstract boolean buttonDown(Controller controller, int buttonCode); - @Override - public abstract boolean buttonUp(Controller controller, int buttonCode); - @Override - public abstract boolean axisMoved(Controller controller, int axisCode, float value); - @Override - public abstract boolean povMoved(Controller controller, int povCode, PovDirection value); - @Override - public abstract boolean xSliderMoved(Controller controller, int sliderCode, boolean value); - @Override - public abstract boolean ySliderMoved(Controller controller, int sliderCode, boolean value); - @Override - public abstract boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value); -} +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.states; + +import ve.ucv.ciens.ccg.nxtar.NxtARCore; + +import com.badlogic.gdx.InputProcessor; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.controllers.Controller; +import com.badlogic.gdx.controllers.ControllerListener; +import com.badlogic.gdx.controllers.PovDirection; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; + +public abstract class BaseState implements Screen, ControllerListener, InputProcessor{ + protected NxtARCore core; + protected boolean stateActive; + protected OrthographicCamera pixelPerfectCamera; + protected Vector3 win2world; + protected Vector2 touchPointWorldCoords; + + /*;;;;;;;;;;;;;;;;; + ; STATE METHODS ; + ;;;;;;;;;;;;;;;;;*/ + + public abstract void onStateSet(); + public abstract void onStateUnset(); + + /*;;;;;;;;;;;;;;;;;; + ; SCREEN METHODS ; + ;;;;;;;;;;;;;;;;;;*/ + + @Override + public abstract void render(float delta); + + @Override + public abstract void dispose(); + + @Override + public void resize(int width, int height){ } + + @Override + public void show(){ } + + @Override + public void hide(){ } + + @Override + public void pause(){ } + + @Override + public void resume(){ } + + /*;;;;;;;;;;;;;;;;;; + ; HELPER METHODS ; + ;;;;;;;;;;;;;;;;;;*/ + + protected final void unprojectTouch(int screenX, int screenY){ + win2world.set(screenX, screenY, 0.0f); + pixelPerfectCamera.unproject(win2world); + touchPointWorldCoords.set(win2world.x, win2world.y); + } + + /*;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; INPUT PROCESSOR METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public boolean keyDown(int keycode){ + return false; + }; + + @Override + public boolean keyUp(int keycode){ + return false; + }; + + @Override + public boolean keyTyped(char character){ + return false; + }; + + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + return false; + }; + + @Override + public boolean touchUp(int screenX, int screenY, int pointer, int button){ + return false; + }; + + @Override + public boolean touchDragged(int screenX, int screenY, int pointer){ + return false; + }; + + @Override + public boolean mouseMoved(int screenX, int screenY){ + return false; + }; + + @Override + public boolean scrolled(int amount){ + return false; + }; + + /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; CONTROLLER LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public void connected(Controller controller){ }; + + @Override + public void disconnected(Controller controller){ }; + + @Override + public boolean buttonDown(Controller controller, int buttonCode){ + return false; + }; + + @Override + public boolean buttonUp(Controller controller, int buttonCode){ + return false; + }; + @Override + public boolean axisMoved(Controller controller, int axisCode, float value){ + return false; + }; + + @Override + public boolean povMoved(Controller controller, int povCode, PovDirection value){ + return false; + }; + + @Override + public boolean xSliderMoved(Controller controller, int sliderCode, boolean value){ + return false; + }; + + @Override + public boolean ySliderMoved(Controller controller, int sliderCode, boolean value){ + return false; + }; + + @Override + public boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value){ + return false; + }; +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java new file mode 100644 index 0000000..b27b0f8 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.states; + +import java.util.Arrays; + +import ve.ucv.ciens.ccg.nxtar.NxtARCore; +import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t; +import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.CalibrationData; +import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor; +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; +import ve.ucv.ciens.ccg.nxtar.utils.Size; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.controllers.Controller; +import com.badlogic.gdx.controllers.mappings.Ouya; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.Texture.TextureWrap; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; +import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; + +public class CameraCalibrationState extends BaseState{ + private static final String TAG = "CAMERA_CALIBRATION_STATE"; + private static final String CLASS_NAME = CameraCalibrationState.class.getSimpleName(); + private static final String SHADER_PATH = "shaders/bckg/bckg"; + + private NxtARCore core; + + private float u_scaling[]; + protected Sprite background; + private Texture backgroundTexture; + private ShaderProgram backgroundShader; + + // Cameras. + private OrthographicCamera camera; + + // Video stream graphics. + private Texture videoFrameTexture; + private Sprite renderableVideoFrame; + private Pixmap videoFrame; + + // Gui components. + private TextButton takeSampleButton; + private Rectangle takeSampleButtonBBox; + private Texture buttonEnabledTexture; + private Texture buttonDisabledTexture; + private Texture buttonPressedTexture; + private NinePatch buttonEnabled9p; + private NinePatch buttonDisabled9p; + private NinePatch buttonPressed9p; + private BitmapFont font; + + // Button touch helper fields. + private boolean takeSampleButtonTouched; + private int takeSampleButtonPointer; + + // Monitors. + private VideoFrameMonitor frameMonitor; + + private float[][] calibrationSamples; + private boolean takeSample; + private int lastSampleTaken; + + public CameraCalibrationState(final NxtARCore core){ + TextButtonStyle tbs; + FreeTypeFontGenerator generator; + + this.core = core; + frameMonitor = VideoFrameMonitor.getInstance(); + + // Set up the cameras. + pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + camera = new OrthographicCamera(1.0f, Gdx.graphics.getHeight() / Gdx.graphics.getWidth()); + + // Set up the background. + backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png")); + backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); + backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + background = new Sprite(backgroundTexture); + background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); + + // Load the background shader. + backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl")); + if(!backgroundShader.isCompiled()){ + Gdx.app.error(TAG, CLASS_NAME + ".CameraCalibrationState() :: Failed to compile the background shader."); + Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); + backgroundShader = null; + } + + // Set up the background scaling. + u_scaling = new float[2]; + u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f; + u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f; + + // Set up the sampling button. + // Create the font. + generator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf")); + font = generator.generateFont(ProjectConstants.MENU_BUTTON_FONT_SIZE, ProjectConstants.FONT_CHARS, false); + generator.dispose(); + + // Load the textures. + buttonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png")); + buttonEnabled9p = new NinePatch(new TextureRegion(buttonEnabledTexture, 0, 0, buttonEnabledTexture.getWidth(), buttonEnabledTexture.getHeight()), 49, 49, 45, 45); + buttonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png")); + buttonDisabled9p = new NinePatch(new TextureRegion(buttonDisabledTexture, 0, 0, buttonDisabledTexture.getWidth(), buttonDisabledTexture.getHeight()), 49, 49, 45, 45); + buttonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png")); + buttonPressed9p = new NinePatch(new TextureRegion(buttonPressedTexture, 0, 0, buttonPressedTexture.getWidth(), buttonPressedTexture.getHeight()), 49, 49, 45, 45); + + // Create the button style. + tbs = new TextButtonStyle(); + tbs.font = font; + tbs.up = new NinePatchDrawable(buttonEnabled9p); + tbs.checked = new NinePatchDrawable(buttonPressed9p); + tbs.disabled = new NinePatchDrawable(buttonDisabled9p); + tbs.disabledFontColor = new Color(0, 0, 0, 1); + + // Create the button itself. + takeSampleButton = new TextButton("Take calibration sample", tbs); + takeSampleButton.setText("Take calibration sample"); + takeSampleButton.setDisabled(true); + takeSampleButtonBBox = new Rectangle(0, 0, takeSampleButton.getWidth(), takeSampleButton.getHeight()); + takeSampleButton.setPosition(-(takeSampleButton.getWidth() / 2), -(Gdx.graphics.getHeight()/2) - 1 + (takeSampleButton.getHeight() / 2)); + takeSampleButtonBBox.setPosition(takeSampleButton.getX(), takeSampleButton.getY()); + + // Set up the touch collision detection variables. + win2world = new Vector3(0.0f, 0.0f, 0.0f); + touchPointWorldCoords = new Vector2(); + takeSampleButtonTouched = false; + takeSampleButtonPointer = -1; + + // Initialize the calibration samples vector. + calibrationSamples = new float[ProjectConstants.CALIBRATION_SAMPLES][]; + for(int i = 0; i < calibrationSamples.length; i++){ + calibrationSamples[i] = new float[ProjectConstants.CALIBRATION_PATTERN_POINTS * 2]; + } + } + + @Override + public void onStateSet(){ + Gdx.input.setInputProcessor(this); + Gdx.input.setCatchBackKey(true); + Gdx.input.setCatchMenuKey(true); + + takeSample = false; + lastSampleTaken = 0; + + for(int i = 0; i < calibrationSamples.length; i++){ + for(int j = 0; j < calibrationSamples[i].length; j++){ + calibrationSamples[i][j] = 0.0f; + } + } + } + + @Override + public void onStateUnset(){ } + + @Override + public void render(float delta){ + String msg; + byte[] frame; + byte[] prevFrame = null; + Size dimensions = null; + + // Clear the screen. + Gdx.gl.glClearColor(1, 1, 1, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + // Render the background. + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.begin();{ + if(backgroundShader != null){ + core.batch.setShader(backgroundShader); + backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2); + } + background.draw(core.batch); + if(backgroundShader != null) core.batch.setShader(null); + }core.batch.end(); + + // Fetch the current video frame. + frame = frameMonitor.getCurrentFrame(); + + // Apply the undistortion method if the camera has been calibrated already. + /*if(core.cvProc.isCameraCalibrated()){ + frame = core.cvProc.undistortFrame(frame); + }*/ + + // Find the calibration points in the video frame. + CalibrationData data = core.cvProc.findCalibrationPattern(frame); + + // Disable the sampling button if the calibration pattern was not found. + if(data.calibrationPoints != null && !core.cvProc.isCameraCalibrated()){ + takeSampleButton.setDisabled(false); + }else{ + takeSampleButton.setDisabled(true); + } + + // If the user requested a sample be taken. + if(takeSample && !core.cvProc.isCameraCalibrated() && data.calibrationPoints != null){ + // Disable sample taking. + takeSample = false; + Gdx.app.log(TAG, CLASS_NAME + ".render(): Sample taken."); + + // Save the calibration points to the samples array. + for(int i = 0; i < data.calibrationPoints.length; i += 2){ + Gdx.app.log(TAG, CLASS_NAME + ".render(): Value " + Integer.toString(i) + " = (" + Float.toString(data.calibrationPoints[i]) + ", " + Float.toString(data.calibrationPoints[i + 1]) + ")"); + calibrationSamples[lastSampleTaken][i] = data.calibrationPoints[i]; + calibrationSamples[lastSampleTaken][i + 1] = data.calibrationPoints[i + 1]; + } + + // Move to the next sample. + lastSampleTaken++; + + msg = Integer.toString(lastSampleTaken) + " samples taken. "; + msg += Integer.toString(ProjectConstants.CALIBRATION_SAMPLES - lastSampleTaken) + " samples left."; + core.toast(msg, false); + + // If enough samples has been taken then calibrate the camera. + if(lastSampleTaken == ProjectConstants.CALIBRATION_SAMPLES){ + Gdx.app.log(TAG, CLASS_NAME + "render(): Last sample taken."); + + core.cvProc.calibrateCamera(calibrationSamples, frame); + msg = "Camera successfully calibrated"; + core.toast(msg, true); + } + } + + if(frame != null && data != null && data.outFrame != null && !Arrays.equals(frame, prevFrame)){ + // If the received frame is valid and is different from the previous frame. + // Make a texture from the frame. + dimensions = frameMonitor.getFrameDimensions(); + videoFrame = new Pixmap(data.outFrame, 0, dimensions.getWidth() * dimensions.getHeight()); + videoFrameTexture = new Texture(videoFrame); + videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + videoFrame.dispose(); + + // Set up the frame texture as a rendereable sprite. + TextureRegion region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); + renderableVideoFrame = new Sprite(region); + renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); + if(!Ouya.runningOnOuya){ + renderableVideoFrame.setSize(1.0f, renderableVideoFrame.getHeight() / renderableVideoFrame.getWidth() ); + renderableVideoFrame.rotate90(true); + renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, 0.5f - renderableVideoFrame.getHeight()); + }else{ + float xSize = Gdx.graphics.getHeight() * (dimensions.getWidth() / dimensions.getHeight()); + renderableVideoFrame.setSize(xSize * ProjectConstants.OVERSCAN, Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN); + renderableVideoFrame.rotate90(true); + renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2); + } + + // Render the frame. + if(!Ouya.runningOnOuya){ + core.batch.setProjectionMatrix(camera.combined); + }else{ + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + } + core.batch.begin();{ + renderableVideoFrame.draw(core.batch); + }core.batch.end(); + + // Clear texture memory. + videoFrameTexture.dispose(); + } + + // Render the user interface. + if(!Ouya.runningOnOuya){ + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.begin();{ + takeSampleButton.draw(core.batch, 1.0f); + }core.batch.end(); + }else{ + // TODO: Render OUYA gui. + } + + // Save this frame as previous to avoid processing the same frame twice when network latency is high. + prevFrame = frame; + } + + @Override + public void resize(int width, int height){ } + + @Override + public void show(){ } + + @Override + public void hide(){ } + + @Override + public void pause(){ } + + @Override + public void resume(){ } + + @Override + public void dispose(){ + if(videoFrameTexture != null) + videoFrameTexture.dispose(); + backgroundTexture.dispose(); + if(backgroundShader != null) backgroundShader.dispose(); + } + + /*;;;;;;;;;;;;;;;;;;;;;;;;;; + ; INPUT LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public boolean keyDown(int keycode){ + if(keycode == Input.Keys.BACK){ + core.nextState = game_states_t.MAIN_MENU; + return true; + } + return false; + } + + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + unprojectTouch(screenX, screenY); + + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button)); + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); + + if(!takeSampleButton.isDisabled() && takeSampleButtonBBox.contains(touchPointWorldCoords) && !takeSampleButtonTouched){ + takeSampleButton.setChecked(true); + takeSampleButtonTouched = true; + takeSampleButtonPointer = pointer; + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Sample button pressed."); + } + + return true; + } + + @Override + public boolean touchUp(int screenX, int screenY, int pointer, int button){ + unprojectTouch(screenX, screenY); + + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button)); + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); + + if(!takeSampleButton.isDisabled() && takeSampleButtonBBox.contains(touchPointWorldCoords) && takeSampleButtonTouched){ + takeSampleButton.setChecked(false); + takeSampleButtonTouched = false; + takeSampleButtonPointer = -1; + takeSample = true; + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Sample button released."); + } + + return true; + } + + @Override + public boolean touchDragged(int screenX, int screenY, int pointer){ + unprojectTouch(screenX, screenY); + + if(!takeSampleButton.isDisabled() && takeSampleButtonTouched && pointer == takeSampleButtonPointer && !takeSampleButtonBBox.contains(touchPointWorldCoords)){ + takeSampleButtonPointer = -1; + takeSampleButtonTouched = false; + takeSampleButton.setChecked(false); + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Sample button released."); + } + + return true; + } + + @Override + public boolean buttonDown(Controller controller, int buttonCode){ + // TODO: Handle OUYA controls. + + return false; + } + + @Override + public boolean buttonUp(Controller controller, int buttonCode){ + // TODO: Handle OUYA controls. + + return false; + } + + @Override + public boolean axisMoved(Controller controller, int axisCode, float value){ + // TODO: Handle OUYA controls. + + return false; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index e8d2c38..81a0073 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -1,860 +1,961 @@ -/* - * Copyright (C) 2014 Miguel Angel Astor Romero - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ve.ucv.ciens.ccg.nxtar.states; - -import java.util.Arrays; - -import ve.ucv.ciens.ccg.networkdata.MotorEvent; -import ve.ucv.ciens.ccg.networkdata.MotorEvent.motor_t; -import ve.ucv.ciens.ccg.nxtar.NxtARCore; -import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t; -import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor.CVData; -import ve.ucv.ciens.ccg.nxtar.network.monitors.MotorEventQueue; -import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor; -import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; -import ve.ucv.ciens.ccg.nxtar.utils.Size; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Input; -import com.badlogic.gdx.controllers.Controller; -import com.badlogic.gdx.controllers.PovDirection; -import com.badlogic.gdx.controllers.mappings.Ouya; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Pixmap; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.Texture.TextureFilter; -import com.badlogic.gdx.graphics.Texture.TextureWrap; -import com.badlogic.gdx.graphics.g2d.Sprite; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.graphics.glutils.ShaderProgram; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.math.Vector3; - -public class InGameState extends BaseState{ - private static final String TAG = "IN_GAME_STATE"; - private static final String CLASS_NAME = InGameState.class.getSimpleName(); - - private static final String SHADER_PATH = "shaders/bckg/bckg"; - - private NxtARCore core; - - private float u_scaling[]; - protected Sprite background; - private Texture backgroundTexture; - private ShaderProgram backgroundShader; - - // Cameras. - private OrthographicCamera camera; - private OrthographicCamera pixelPerfectCamera; - - // Video stream graphics. - private Texture videoFrameTexture; - private Sprite renderableVideoFrame; - private Pixmap videoFrame; - - // Interface buttons. - private Texture buttonTexture; - private Texture buttonTexture2; - private Sprite motorA; - private Sprite motorB; - private Sprite motorC; - private Sprite motorD; - private Sprite headA; - private Sprite headB; - private Sprite headC; - - // Button touch helper fields. - private Vector3 win2world; - private Vector2 touchPointWorldCoords; - private boolean[] motorButtonsTouched; - private int[] motorButtonsPointers; - private boolean[] motorGamepadButtonPressed; - - // Monitors. - private VideoFrameMonitor frameMonitor; - private MotorEventQueue queue; - - public InGameState(final NxtARCore core){ - this.core = core; - frameMonitor = VideoFrameMonitor.getInstance(); - queue = MotorEventQueue.getInstance(); - - // Set up rendering fields; - videoFrame = null; - - // Set up the cameras. - pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); - camera = new OrthographicCamera(1.0f, Gdx.graphics.getHeight() / Gdx.graphics.getWidth()); - - if(!Ouya.runningOnOuya) setUpButtons(); - - // Set up input handling support fields. - win2world = new Vector3(0.0f, 0.0f, 0.0f); - touchPointWorldCoords = new Vector2(); - - motorButtonsTouched = new boolean[7]; - motorButtonsTouched[0] = false; - motorButtonsTouched[1] = false; - motorButtonsTouched[2] = false; - motorButtonsTouched[3] = false; - motorButtonsTouched[4] = false; - motorButtonsTouched[5] = false; - motorButtonsTouched[6] = false; - - motorButtonsPointers = new int[7]; - motorButtonsPointers[0] = -1; - motorButtonsPointers[1] = -1; - motorButtonsPointers[2] = -1; - motorButtonsPointers[3] = -1; - motorButtonsPointers[4] = -1; - motorButtonsPointers[5] = -1; - motorButtonsPointers[6] = -1; - - motorGamepadButtonPressed = new boolean[7]; - motorGamepadButtonPressed[0] = false; - motorGamepadButtonPressed[1] = false; - motorGamepadButtonPressed[2] = false; - motorGamepadButtonPressed[3] = false; - motorGamepadButtonPressed[4] = false; - motorGamepadButtonPressed[5] = false; - motorGamepadButtonPressed[6] = false; - - backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png")); - backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); - backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); - background = new Sprite(backgroundTexture); - background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); - background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); - - backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + ".vert"), Gdx.files.internal(SHADER_PATH + ".frag")); - if(!backgroundShader.isCompiled()){ - Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader."); - Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); - backgroundShader = null; - } - - u_scaling = new float[2]; - u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f; - u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f; - } - - @Override - public void render(float delta){ - int fW, fH; - byte[] frame; - byte[] prevFrame = null; - Size dimensions = null; - CVData data; - - Gdx.gl.glClearColor(1, 1, 1, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); - core.batch.begin();{ - if(backgroundShader != null){ - core.batch.setShader(backgroundShader); - backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2); - } - background.draw(core.batch); - if(backgroundShader != null) core.batch.setShader(null); - }core.batch.end(); - - frame = frameMonitor.getCurrentFrame(); - fW = frameMonitor.getFrameDimensions().getWidth(); - fH = frameMonitor.getFrameDimensions().getHeight(); - - data = core.cvProc.processFrame(frame, fW, fH); - - if(data != null){ - for(int i = 0; i < data.markerCodes.length; i++){ - Gdx.app.log(TAG, CLASS_NAME + String.format(".render(): Marker code[%d] = %d", i, data.markerCodes[i])); - } - } - - if(data != null && data.outFrame != null && !Arrays.equals(frame, prevFrame)){ - dimensions = frameMonitor.getFrameDimensions(); - videoFrame = new Pixmap(data.outFrame, 0, dimensions.getWidth() * dimensions.getHeight()); - videoFrameTexture = new Texture(videoFrame); - videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); - videoFrame.dispose(); - - TextureRegion region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); - - renderableVideoFrame = new Sprite(region); - renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); - if(!Ouya.runningOnOuya){ - renderableVideoFrame.setSize(1.0f, renderableVideoFrame.getHeight() / renderableVideoFrame.getWidth() ); - renderableVideoFrame.rotate90(true); - renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, 0.5f - renderableVideoFrame.getHeight()); - }else{ - float xSize = Gdx.graphics.getHeight() * (dimensions.getWidth() / dimensions.getHeight()); - renderableVideoFrame.setSize(xSize * ProjectConstants.OVERSCAN, Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN); - renderableVideoFrame.rotate90(true); - renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2); - } - - if(!Ouya.runningOnOuya){ - core.batch.setProjectionMatrix(camera.combined); - }else{ - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); - } - core.batch.begin();{ - renderableVideoFrame.draw(core.batch); - }core.batch.end(); - - videoFrameTexture.dispose(); - } - - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); - core.batch.begin();{ - if(!Ouya.runningOnOuya){ - motorA.draw(core.batch); - motorB.draw(core.batch); - motorC.draw(core.batch); - motorD.draw(core.batch); - headA.draw(core.batch); - headB.draw(core.batch); - headC.draw(core.batch); - } - }core.batch.end(); - - prevFrame = frame; - } - - @Override - public void resize(int width, int height){ - // TODO Auto-generated method stub - - } - - @Override - public void show(){ } - - @Override - public void hide(){ } - - @Override - public void pause(){ } - - @Override - public void resume(){ } - - @Override - public void dispose(){ - if(videoFrameTexture != null) - videoFrameTexture.dispose(); - if(buttonTexture != null) - buttonTexture.dispose(); - if(buttonTexture2 != null) - buttonTexture2.dispose(); - backgroundTexture.dispose(); - if(backgroundShader != null) backgroundShader.dispose(); - } - - /*;;;;;;;;;;;;;;;;;; - ; HELPER METHODS ; - ;;;;;;;;;;;;;;;;;;*/ - - @Override - public void onStateSet(){ - stateActive = true; - Gdx.input.setInputProcessor(this); - Gdx.input.setCatchBackKey(true); - Gdx.input.setCatchMenuKey(true); - } - - @Override - public void onStateUnset(){ - stateActive = false; - Gdx.input.setInputProcessor(null); - Gdx.input.setCatchBackKey(false); - Gdx.input.setCatchMenuKey(false); - } - - private void setUpButtons(){ - buttonTexture = new Texture(Gdx.files.internal("data/gfx/gui/PBCrichton_Flat_Button.png")); - buttonTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); - - TextureRegion region = new TextureRegion(buttonTexture, 0, 0, buttonTexture.getWidth(), buttonTexture.getHeight()); - - motorA = new Sprite(region); - motorA.setSize(motorA.getWidth() * 0.7f, motorA.getHeight() * 0.7f); - - motorB = new Sprite(region); - motorB.setSize(motorB.getWidth() * 0.7f, motorB.getHeight() * 0.7f); - - motorC = new Sprite(region); - motorC.setSize(motorC.getWidth() * 0.7f, motorC.getHeight() * 0.7f); - - motorD = new Sprite(region); - motorD.setSize(motorD.getWidth() * 0.7f, motorD.getHeight() * 0.7f); - - motorA.setPosition(-(Gdx.graphics.getWidth() / 2) + 10, -(Gdx.graphics.getHeight() / 2) + motorB.getHeight() + 20); - motorB.setPosition(-(Gdx.graphics.getWidth() / 2) + 20 + (motorA.getWidth() / 2), -(Gdx.graphics.getHeight() / 2) + 10); - motorC.setPosition((Gdx.graphics.getWidth() / 2) - (1.5f * (motorD.getWidth())) - 20, -(Gdx.graphics.getHeight() / 2) + 10); - motorD.setPosition((Gdx.graphics.getWidth() / 2) - motorD.getWidth() - 10, -(Gdx.graphics.getHeight() / 2) + 20 + motorC.getHeight()); - - buttonTexture2 = new Texture(Gdx.files.internal("data/gfx/gui/orange_glowy_button.png")); - - headA = new Sprite(buttonTexture2); - headA.setSize(headA.getWidth() * 0.3f, headA.getHeight() * 0.6f); - - headB = new Sprite(buttonTexture2); - headB.setSize(headB.getWidth() * 0.3f, headB.getHeight() * 0.6f); - - headA.setPosition(-headA.getWidth() - 10, motorA.getY() + (headA.getHeight() / 2)); - headB.setPosition(10, motorA.getY() + (headA.getHeight() / 2)); - - headC = new Sprite(buttonTexture2); - headC.setSize(headC.getWidth() * 0.3f, headC.getHeight() * 0.6f); - headC.setPosition(-(headC.getWidth() / 2), headA.getY() - headA.getHeight() - 10); - } - - /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; BEGIN INPUT PROCESSOR METHODS ; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ - - @Override - public boolean touchDown(int screenX, int screenY, int pointer, int button){ - MotorEvent event; - - if(!Ouya.runningOnOuya){ - win2world.set(screenX, screenY, 0.0f); - camera.unproject(win2world); - touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); - - Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button)); - Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); - - if(motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor A button pressed"); - - motorButtonsTouched[0] = true; - motorButtonsPointers[0] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte)100); - queue.addEvent(event); - - }else if(motorB.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor B button pressed"); - - motorButtonsTouched[1] = true; - motorButtonsPointers[1] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte)-100); - queue.addEvent(event); - - }else if(motorC.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor C button pressed"); - - motorButtonsTouched[2] = true; - motorButtonsPointers[2] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte)-100); - queue.addEvent(event); - - }else if(motorD.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor D button pressed"); - - motorButtonsTouched[3] = true; - motorButtonsPointers[3] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte)100); - queue.addEvent(event); - - }else if(headA.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Head A button pressed"); - - motorButtonsTouched[4] = true; - motorButtonsPointers[4] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte)-40); - queue.addEvent(event); - - }else if(headB.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Head B button pressed"); - - motorButtonsTouched[5] = true; - motorButtonsPointers[5] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte)40); - queue.addEvent(event); - - }else if(headC.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Head C button pressed"); - - if(!motorButtonsTouched[4] && !motorButtonsTouched[5]){ - motorButtonsTouched[6] = true; - motorButtonsPointers[6] = pointer; - - event = new MotorEvent(); - event.setMotor(motor_t.RECENTER); - event.setPower((byte)0x00); - queue.addEvent(event); - } - } - } - return true; - } - - @Override - public boolean touchUp(int screenX, int screenY, int pointer, int button){ - MotorEvent event; - - if(!Ouya.runningOnOuya){ - win2world.set(screenX, screenY, 0.0f); - camera.unproject(win2world); - touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); - - Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button)); - Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); - - if(motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor A button released"); - - motorButtonsPointers[0] = -1; - motorButtonsTouched[0] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[1]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(motorB.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor B button released"); - - motorButtonsPointers[1] = -1; - motorButtonsTouched[1] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[0]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(motorC.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor C button released"); - - motorButtonsPointers[2] = -1; - motorButtonsTouched[2] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[3]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(motorD.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor D button released"); - - motorButtonsPointers[3] = -1; - motorButtonsTouched[3] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[2]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(headA.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Head A button released"); - - motorButtonsPointers[4] = -1; - motorButtonsTouched[4] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[5]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(headB.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Head B button released"); - - motorButtonsPointers[5] = -1; - motorButtonsTouched[5] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[4]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(headC.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Head C button released"); - - motorButtonsPointers[6] = -1; - motorButtonsTouched[6] = false; - } - } - return true; - } - - @Override - public boolean touchDragged(int screenX, int screenY, int pointer){ - MotorEvent event; - - if(!Ouya.runningOnOuya){ - win2world.set(screenX, screenY, 0.0f); - camera.unproject(win2world); - touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); - - if(pointer == motorButtonsPointers[0] && !motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor A button released"); - - motorButtonsPointers[0] = -1; - motorButtonsTouched[0] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[1]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(pointer == motorButtonsPointers[1] && !motorB.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor B button released"); - - motorButtonsPointers[1] = -1; - motorButtonsTouched[1] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[0]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(pointer == motorButtonsPointers[2] && !motorC.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor C button released"); - - motorButtonsPointers[2] = -1; - motorButtonsTouched[2] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[3]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(pointer == motorButtonsPointers[3] && !motorD.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor D button released"); - - motorButtonsPointers[3] = -1; - motorButtonsTouched[3] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[2]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(pointer == motorButtonsPointers[4] && !headA.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Head A button released"); - - motorButtonsPointers[4] = -1; - motorButtonsTouched[4] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[5]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(pointer == motorButtonsPointers[5] && !headB.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Head B button released"); - - motorButtonsPointers[5] = -1; - motorButtonsTouched[5] = false; - - // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. - if(!motorButtonsTouched[4]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte) 0); - queue.addEvent(event); - } - - }else if(pointer == motorButtonsPointers[6] && !headC.getBoundingRectangle().contains(touchPointWorldCoords)){ - Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Head C button released"); - - motorButtonsPointers[6] = -1; - motorButtonsTouched[6] = false; - } - } - return true; - } - - @Override - public boolean keyDown(int keycode){ - if(keycode == Input.Keys.BACK){ - // TODO: Go to pause state. - core.nextState = game_states_t.MAIN_MENU; - return true; - } - return false; - } - - /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; BEGIN CONTROLLER LISTENER METHODS ; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ - - @Override - public boolean buttonDown(Controller controller, int buttonCode){ - MotorEvent event; - - if(stateActive /*&& Ouya.runningOnOuya*/){ - Gdx.app.log(TAG, CLASS_NAME + ".buttonDown() :: " + controller.getName() + " :: " + Integer.toString(buttonCode)); - - if(buttonCode == Ouya.BUTTON_L1){ - motorGamepadButtonPressed[0] = true; - - if(!motorGamepadButtonPressed[4]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte)-100); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_R1){ - motorGamepadButtonPressed[1] = true; - - if(!motorGamepadButtonPressed[5]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte)-100); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_DPAD_LEFT){ - motorGamepadButtonPressed[2] = false; - - if(!motorGamepadButtonPressed[3]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte)-40); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_DPAD_RIGHT){ - motorGamepadButtonPressed[3] = false; - - if(!motorGamepadButtonPressed[2]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte)40); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_L2){ - motorGamepadButtonPressed[4] = false; - - if(!motorGamepadButtonPressed[0]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte)100); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_R2){ - motorGamepadButtonPressed[5] = false; - - if(!motorGamepadButtonPressed[1]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte)100); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_Y){ - motorGamepadButtonPressed[6] = true; - - event = new MotorEvent(); - event.setMotor(motor_t.RECENTER); - event.setPower((byte)0x00); - queue.addEvent(event); - } - - return true; - }else{ - return false; - } - } - - @Override - public boolean buttonUp(Controller controller, int buttonCode){ - MotorEvent event; - - if(stateActive /*&& Ouya.runningOnOuya*/){ - Gdx.app.log(TAG, CLASS_NAME + ".buttonDown() :: " + controller.getName() + " :: " + Integer.toString(buttonCode)); - - if(buttonCode == Ouya.BUTTON_L1){ - motorGamepadButtonPressed[0] = false; - - if(!motorGamepadButtonPressed[4]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte)0); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_R1){ - motorGamepadButtonPressed[1] = false; - - if(!motorGamepadButtonPressed[5]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte)0); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_DPAD_LEFT){ - motorGamepadButtonPressed[2] = false; - - if(!motorGamepadButtonPressed[3]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte)0); - queue.addEvent(event); - } - }else if(buttonCode == Ouya.BUTTON_DPAD_RIGHT){ - motorGamepadButtonPressed[3] = false; - - if(!motorGamepadButtonPressed[2]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_B); - event.setPower((byte)0); - queue.addEvent(event); - } - }else if(buttonCode == Ouya.BUTTON_L2){ - motorGamepadButtonPressed[4] = false; - - if(!motorGamepadButtonPressed[0]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_A); - event.setPower((byte)0); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_R2){ - motorGamepadButtonPressed[5] = false; - - if(!motorGamepadButtonPressed[1]){ - event = new MotorEvent(); - event.setMotor(motor_t.MOTOR_C); - event.setPower((byte)0); - queue.addEvent(event); - } - - }else if(buttonCode == Ouya.BUTTON_Y){ - motorGamepadButtonPressed[6] = false; - } - - return true; - }else{ - return false; - } - } - - @Override - public boolean axisMoved(Controller controller, int axisCode, float value){ - return false; - } - - @Override - public void connected(Controller controller){ } - - @Override - public void disconnected(Controller controller){ } - - /*;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; UNUSED LISTENER METHODS ; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ - - @Override - public boolean mouseMoved(int screenX, int screenY){ - return false; - } - - @Override - public boolean keyUp(int keycode){ - return false; - } - - @Override - public boolean keyTyped(char character){ - return false; - } - - @Override - public boolean povMoved(Controller controller, int povCode, PovDirection value){ - return false; - } - - @Override - public boolean xSliderMoved(Controller controller, int sliderCode, boolean value){ - return false; - } - - @Override - public boolean ySliderMoved(Controller controller, int sliderCode, boolean value){ - return false; - } - - @Override - public boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value){ - return false; - } - - @Override - public boolean scrolled(int amount){ - return false; - } -} +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.states; + +import ve.ucv.ciens.ccg.networkdata.MotorEvent; +import ve.ucv.ciens.ccg.networkdata.MotorEvent.motor_t; +import ve.ucv.ciens.ccg.nxtar.NxtARCore; +import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t; +import ve.ucv.ciens.ccg.nxtar.entities.EntityCreatorBase; +import ve.ucv.ciens.ccg.nxtar.entities.MarkerTestEntityCreator; +import ve.ucv.ciens.ccg.nxtar.graphics.CustomPerspectiveCamera; +import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; +import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData; +import ve.ucv.ciens.ccg.nxtar.network.monitors.MotorEventQueue; +import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor; +import ve.ucv.ciens.ccg.nxtar.systems.MarkerPositioningSystem; +import ve.ucv.ciens.ccg.nxtar.systems.MarkerRenderingSystem; +import ve.ucv.ciens.ccg.nxtar.systems.ObjectRenderingSystem; +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; + +import com.artemis.World; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.controllers.Controller; +import com.badlogic.gdx.controllers.mappings.Ouya; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.Texture.TextureWrap; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.glutils.FrameBuffer; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; + +public class InGameState extends BaseState{ + private static final String TAG = "IN_GAME_STATE"; + private static final String CLASS_NAME = InGameState.class.getSimpleName(); + private static final String BACKGROUND_SHADER_PATH = "shaders/bckg/bckg"; + private static final float NEAR = 0.01f; + private static final float FAR = 100.0f; + private static final float FAR_PLUS_NEAR = FAR + NEAR; + private static final float FAR_LESS_NEAR = FAR - NEAR; + + // Background related fields. + private float uScaling[]; + protected Sprite background; + private Texture backgroundTexture; + private ShaderProgram backgroundShader; + + // 3D rendering fields. + private Matrix4 projectionMatrix; + private FrameBuffer frameBuffer; + private Sprite frameBufferSprite; + + // Game objects. + private World gameWorld; + private EntityCreatorBase entityCreator; + + // Cameras. + private OrthographicCamera unitaryOrthoCamera; + private OrthographicCamera pixelPerfectOrthoCamera; + private CustomPerspectiveCamera perspectiveCamera; + + // Video stream graphics. + private Texture videoFrameTexture; + private Sprite renderableVideoFrame; + private Pixmap videoFrame; + + // Interface buttons. + private Texture buttonTexture; + private Texture buttonTexture2; + private Sprite motorA; + private Sprite motorB; + private Sprite motorC; + private Sprite motorD; + private Sprite headA; + private Sprite headB; + private Sprite headC; + + // Button touch helper fields. + private boolean[] motorButtonsTouched; + private int[] motorButtonsPointers; + private boolean[] motorGamepadButtonPressed; + + // Monitors. + private VideoFrameMonitor frameMonitor; + private MotorEventQueue queue; + + public InGameState(final NxtARCore core){ + this.core = core; + frameMonitor = VideoFrameMonitor.getInstance(); + queue = MotorEventQueue.getInstance(); + + // Set up rendering fields; + videoFrame = null; + + // Set up the cameras. + pixelPerfectOrthoCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + unitaryOrthoCamera = new OrthographicCamera(1.0f, Gdx.graphics.getHeight() / Gdx.graphics.getWidth()); + + if(!Ouya.runningOnOuya) setUpButtons(); + + // Set up input handling support fields. + win2world = new Vector3(0.0f, 0.0f, 0.0f); + touchPointWorldCoords = new Vector2(); + + motorButtonsTouched = new boolean[7]; + motorButtonsTouched[0] = false; + motorButtonsTouched[1] = false; + motorButtonsTouched[2] = false; + motorButtonsTouched[3] = false; + motorButtonsTouched[4] = false; + motorButtonsTouched[5] = false; + motorButtonsTouched[6] = false; + + motorButtonsPointers = new int[7]; + motorButtonsPointers[0] = -1; + motorButtonsPointers[1] = -1; + motorButtonsPointers[2] = -1; + motorButtonsPointers[3] = -1; + motorButtonsPointers[4] = -1; + motorButtonsPointers[5] = -1; + motorButtonsPointers[6] = -1; + + motorGamepadButtonPressed = new boolean[7]; + motorGamepadButtonPressed[0] = false; + motorGamepadButtonPressed[1] = false; + motorGamepadButtonPressed[2] = false; + motorGamepadButtonPressed[3] = false; + motorGamepadButtonPressed[4] = false; + motorGamepadButtonPressed[5] = false; + motorGamepadButtonPressed[6] = false; + + // Set up the background. + backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png")); + backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); + backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + background = new Sprite(backgroundTexture); + background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); + + // Set up the shader. + backgroundShader = new ShaderProgram(Gdx.files.internal(BACKGROUND_SHADER_PATH + "_vert.glsl"), Gdx.files.internal(BACKGROUND_SHADER_PATH + "_frag.glsl")); + if(!backgroundShader.isCompiled()){ + Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader."); + Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); + backgroundShader = null; + } + + uScaling = new float[2]; + uScaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f; + uScaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f; + + // Set up the 3D rendering. + projectionMatrix = new Matrix4().idt(); + frameBuffer = null; + perspectiveCamera = null; + frameBufferSprite = null; + + // Set up the game world. + gameWorld = new World(); + entityCreator = new MarkerTestEntityCreator(); + entityCreator.setWorld(gameWorld); + entityCreator.createAllEntities(); + gameWorld.setSystem(new MarkerPositioningSystem()); + gameWorld.setSystem(new MarkerRenderingSystem(), true); + gameWorld.setSystem(new ObjectRenderingSystem(), true); + gameWorld.initialize(); + } + + /*;;;;;;;;;;;;;;;;;;;;;; + ; BASE STATE METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public void render(float delta){ + int w, h; + byte[] frame; + MarkerData data; + TextureRegion region; + float focalPointX, focalPointY, cameraCenterX, cameraCenterY; + + // Clear the screen. + Gdx.gl.glClearColor(1, 1, 1, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + // Render the background. + core.batch.setProjectionMatrix(pixelPerfectOrthoCamera.combined); + core.batch.begin();{ + if(backgroundShader != null){ + core.batch.setShader(backgroundShader); + backgroundShader.setUniform2fv("u_scaling", uScaling, 0, 2); + } + background.draw(core.batch); + if(backgroundShader != null) core.batch.setShader(null); + }core.batch.end(); + + // Fetch the current video frame. + frame = frameMonitor.getCurrentFrame(); + w = frameMonitor.getFrameDimensions().getWidth(); + h = frameMonitor.getFrameDimensions().getHeight(); + + // Create the 3D perspective camera and the frame buffer object if they don't exist. + if(perspectiveCamera == null && frameBuffer == null){ + frameBuffer = new FrameBuffer(Format.RGBA8888, w, h, true); + frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); + + perspectiveCamera = new CustomPerspectiveCamera(67, w, h); + perspectiveCamera.translate(0.0f, 0.0f, 0.0f); + perspectiveCamera.near = NEAR; + perspectiveCamera.far = FAR; + perspectiveCamera.lookAt(0.0f, 0.0f, -1.0f); + perspectiveCamera.update(); + } + + // Apply the undistortion method if the camera has been calibrated already. + /*if(core.cvProc.isCameraCalibrated()){ + frame = core.cvProc.undistortFrame(frame); + }*/ + + // Attempt to find the markers in the current video frame. + data = core.cvProc.findMarkersInFrame(frame); + + // If a valid frame was fetched. + if(data != null && data.outFrame != null){ + // Update the game state. + gameWorld.setDelta(Gdx.graphics.getDeltaTime() * 1000); + gameWorld.getSystem(MarkerPositioningSystem.class).setMarkerData(data); + gameWorld.process(); + + // Decode the video frame. + videoFrame = new Pixmap(data.outFrame, 0, w * h); + videoFrameTexture = new Texture(videoFrame); + videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + videoFrame.dispose(); + + // Convert the decoded frame into a renderable texture. + region = new TextureRegion(videoFrameTexture, 0, 0, w, h); + if(renderableVideoFrame == null) + renderableVideoFrame = new Sprite(region); + else + renderableVideoFrame.setRegion(region); + renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); + renderableVideoFrame.setPosition(0, 0); + + // Set the 3D frame buffer for rendering. + frameBuffer.begin();{ + // Set OpenGL state. + Gdx.gl.glDisable(GL20.GL_CULL_FACE); + Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); + Gdx.gl.glClearColor(0, 0, 0, 0); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); + + // Build the projection matrix. + focalPointX = core.cvProc.getFocalPointX(); + focalPointY = core.cvProc.getFocalPointY(); + cameraCenterX = core.cvProc.getCameraCenterX(); + cameraCenterY = core.cvProc.getCameraCenterY(); + + projectionMatrix.val[Matrix4.M00] = -2.0f * focalPointX / w; + projectionMatrix.val[Matrix4.M10] = 0.0f; + projectionMatrix.val[Matrix4.M20] = 0.0f; + projectionMatrix.val[Matrix4.M30] = 0.0f; + + projectionMatrix.val[Matrix4.M01] = 0.0f; + projectionMatrix.val[Matrix4.M11] = 2.0f * focalPointY / h; + projectionMatrix.val[Matrix4.M21] = 0.0f; + projectionMatrix.val[Matrix4.M31] = 0.0f; + + projectionMatrix.val[Matrix4.M02] = 2.0f * cameraCenterX / w - 1.0f; + projectionMatrix.val[Matrix4.M12] = 2.0f * cameraCenterY / h - 1.0f; + projectionMatrix.val[Matrix4.M22] = -FAR_PLUS_NEAR / FAR_LESS_NEAR; + projectionMatrix.val[Matrix4.M32] = -1.0f; + + projectionMatrix.val[Matrix4.M03] = 0.0f; + projectionMatrix.val[Matrix4.M13] = 0.0f; + projectionMatrix.val[Matrix4.M23] = -2.0f * FAR * NEAR / FAR_LESS_NEAR; + projectionMatrix.val[Matrix4.M33] = 0.0f; + + // Set rendering parameters. + perspectiveCamera.update(projectionMatrix, true); + RenderParameters.setModelViewProjectionMatrix(perspectiveCamera.combined); + RenderParameters.setEyePosition(perspectiveCamera.position); + + // Call rendering systems. + gameWorld.getSystem(MarkerRenderingSystem.class).setMarkerData(data); + gameWorld.getSystem(MarkerRenderingSystem.class).process(); + gameWorld.getSystem(ObjectRenderingSystem.class).process(); + + Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); + }frameBuffer.end(); + + // Set the frame buffer object texture to a renderable sprite. + region = new TextureRegion(frameBuffer.getColorBufferTexture(), 0, 0, frameBuffer.getWidth(), frameBuffer.getHeight()); + region.flip(false, true); + if(frameBufferSprite == null) + frameBufferSprite = new Sprite(region); + else + frameBufferSprite.setRegion(region); + frameBufferSprite.setOrigin(frameBufferSprite.getWidth() / 2, frameBufferSprite.getHeight() / 2); + frameBufferSprite.setPosition(0, 0); + + // Set the position and orientation of the renderable video frame and the frame buffer. + if(!Ouya.runningOnOuya){ + renderableVideoFrame.setSize(1.0f, renderableVideoFrame.getHeight() / renderableVideoFrame.getWidth() ); + renderableVideoFrame.rotate90(true); + renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, 0.5f - renderableVideoFrame.getHeight()); + + frameBufferSprite.setSize(1.0f, frameBufferSprite.getHeight() / frameBufferSprite.getWidth() ); + frameBufferSprite.rotate90(true); + frameBufferSprite.translate(-frameBufferSprite.getWidth() / 2, 0.5f - frameBufferSprite.getHeight()); + }else{ + float xSize = Gdx.graphics.getHeight() * (w / h); + renderableVideoFrame.setSize(xSize * ProjectConstants.OVERSCAN, Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN); + renderableVideoFrame.rotate90(true); + renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2); + + frameBufferSprite.setSize(xSize * ProjectConstants.OVERSCAN, Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN); + frameBufferSprite.rotate90(true); + frameBufferSprite.translate(-frameBufferSprite.getWidth() / 2, -frameBufferSprite.getHeight() / 2); + } + + // Set the correct camera for the device. + if(!Ouya.runningOnOuya){ + core.batch.setProjectionMatrix(unitaryOrthoCamera.combined); + }else{ + core.batch.setProjectionMatrix(pixelPerfectOrthoCamera.combined); + } + + // Render the video frame and the frame buffer. + core.batch.begin();{ + renderableVideoFrame.draw(core.batch); + frameBufferSprite.draw(core.batch); + }core.batch.end(); + + // Clear the video frame from memory. + videoFrameTexture.dispose(); + } + + // Render the interface buttons. + if(!Ouya.runningOnOuya){ + core.batch.setProjectionMatrix(pixelPerfectOrthoCamera.combined); + core.batch.begin();{ + motorA.draw(core.batch); + motorB.draw(core.batch); + motorC.draw(core.batch); + motorD.draw(core.batch); + headA.draw(core.batch); + headB.draw(core.batch); + headC.draw(core.batch); + }core.batch.end(); + } + + data = null; + } + + @Override + public void dispose(){ + if(entityCreator != null) + entityCreator.dispose(); + + if(videoFrameTexture != null) + videoFrameTexture.dispose(); + + if(buttonTexture != null) + buttonTexture.dispose(); + + if(buttonTexture2 != null) + buttonTexture2.dispose(); + + backgroundTexture.dispose(); + + if(backgroundShader != null) + backgroundShader.dispose(); + + if(frameBuffer != null) + frameBuffer.dispose(); + } + + /*;;;;;;;;;;;;;;;;;; + ; HELPER METHODS ; + ;;;;;;;;;;;;;;;;;;*/ + + @Override + public void onStateSet(){ + stateActive = true; + Gdx.input.setInputProcessor(this); + Gdx.input.setCatchBackKey(true); + Gdx.input.setCatchMenuKey(true); + } + + @Override + public void onStateUnset(){ + stateActive = false; + Gdx.input.setInputProcessor(null); + Gdx.input.setCatchBackKey(false); + Gdx.input.setCatchMenuKey(false); + } + + private void setUpButtons(){ + buttonTexture = new Texture(Gdx.files.internal("data/gfx/gui/PBCrichton_Flat_Button.png")); + buttonTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + + TextureRegion region = new TextureRegion(buttonTexture, 0, 0, buttonTexture.getWidth(), buttonTexture.getHeight()); + + motorA = new Sprite(region); + motorA.setSize(motorA.getWidth() * 0.7f, motorA.getHeight() * 0.7f); + + motorB = new Sprite(region); + motorB.setSize(motorB.getWidth() * 0.7f, motorB.getHeight() * 0.7f); + + motorC = new Sprite(region); + motorC.setSize(motorC.getWidth() * 0.7f, motorC.getHeight() * 0.7f); + + motorD = new Sprite(region); + motorD.setSize(motorD.getWidth() * 0.7f, motorD.getHeight() * 0.7f); + + motorA.setPosition(-(Gdx.graphics.getWidth() / 2) + 10, -(Gdx.graphics.getHeight() / 2) + motorB.getHeight() + 20); + motorB.setPosition(-(Gdx.graphics.getWidth() / 2) + 20 + (motorA.getWidth() / 2), -(Gdx.graphics.getHeight() / 2) + 10); + motorC.setPosition((Gdx.graphics.getWidth() / 2) - (1.5f * (motorD.getWidth())) - 20, -(Gdx.graphics.getHeight() / 2) + 10); + motorD.setPosition((Gdx.graphics.getWidth() / 2) - motorD.getWidth() - 10, -(Gdx.graphics.getHeight() / 2) + 20 + motorC.getHeight()); + + buttonTexture2 = new Texture(Gdx.files.internal("data/gfx/gui/orange_glowy_button.png")); + + headA = new Sprite(buttonTexture2); + headA.setSize(headA.getWidth() * 0.3f, headA.getHeight() * 0.6f); + + headB = new Sprite(buttonTexture2); + headB.setSize(headB.getWidth() * 0.3f, headB.getHeight() * 0.6f); + + headA.setPosition(-headA.getWidth() - 10, motorA.getY() + (headA.getHeight() / 2)); + headB.setPosition(10, motorA.getY() + (headA.getHeight() / 2)); + + headC = new Sprite(buttonTexture2); + headC.setSize(headC.getWidth() * 0.3f, headC.getHeight() * 0.6f); + headC.setPosition(-(headC.getWidth() / 2), headA.getY() - headA.getHeight() - 10); + } + + /*;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; INPUT PROCESSOR METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + MotorEvent event; + + if(!Ouya.runningOnOuya){ + win2world.set(screenX, screenY, 0.0f); + unitaryOrthoCamera.unproject(win2world); + touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); + + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button)); + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); + + if(motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor A button pressed"); + + motorButtonsTouched[0] = true; + motorButtonsPointers[0] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte)100); + queue.addEvent(event); + + }else if(motorB.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor B button pressed"); + + motorButtonsTouched[1] = true; + motorButtonsPointers[1] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte)-100); + queue.addEvent(event); + + }else if(motorC.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor C button pressed"); + + motorButtonsTouched[2] = true; + motorButtonsPointers[2] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte)-100); + queue.addEvent(event); + + }else if(motorD.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Motor D button pressed"); + + motorButtonsTouched[3] = true; + motorButtonsPointers[3] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte)100); + queue.addEvent(event); + + }else if(headA.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Head A button pressed"); + + motorButtonsTouched[4] = true; + motorButtonsPointers[4] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte)-40); + queue.addEvent(event); + + }else if(headB.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Head B button pressed"); + + motorButtonsTouched[5] = true; + motorButtonsPointers[5] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte)40); + queue.addEvent(event); + + }else if(headC.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Head C button pressed"); + + if(!motorButtonsTouched[4] && !motorButtonsTouched[5]){ + motorButtonsTouched[6] = true; + motorButtonsPointers[6] = pointer; + + event = new MotorEvent(); + event.setMotor(motor_t.RECENTER); + event.setPower((byte)0x00); + queue.addEvent(event); + } + }else{ + // TODO: Send input to the input handler system. + } + + return true; + } + + return false; + } + + @Override + public boolean touchUp(int screenX, int screenY, int pointer, int button){ + MotorEvent event; + + if(!Ouya.runningOnOuya){ + win2world.set(screenX, screenY, 0.0f); + unitaryOrthoCamera.unproject(win2world); + touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); + + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button)); + Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); + + if(motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor A button released"); + + motorButtonsPointers[0] = -1; + motorButtonsTouched[0] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[1]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(motorB.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor B button released"); + + motorButtonsPointers[1] = -1; + motorButtonsTouched[1] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[0]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(motorC.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor C button released"); + + motorButtonsPointers[2] = -1; + motorButtonsTouched[2] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[3]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(motorD.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Motor D button released"); + + motorButtonsPointers[3] = -1; + motorButtonsTouched[3] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[2]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(headA.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Head A button released"); + + motorButtonsPointers[4] = -1; + motorButtonsTouched[4] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[5]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(headB.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Head B button released"); + + motorButtonsPointers[5] = -1; + motorButtonsTouched[5] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[4]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(headC.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchUp() :: Head C button released"); + + motorButtonsPointers[6] = -1; + motorButtonsTouched[6] = false; + }else{ + // TODO: Pass input to the input handler system. + } + + return true; + } + + return false; + } + + @Override + public boolean touchDragged(int screenX, int screenY, int pointer){ + MotorEvent event; + + if(!Ouya.runningOnOuya){ + win2world.set(screenX, screenY, 0.0f); + unitaryOrthoCamera.unproject(win2world); + touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); + + if(pointer == motorButtonsPointers[0] && !motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor A button released"); + + motorButtonsPointers[0] = -1; + motorButtonsTouched[0] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[1]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(pointer == motorButtonsPointers[1] && !motorB.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor B button released"); + + motorButtonsPointers[1] = -1; + motorButtonsTouched[1] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[0]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(pointer == motorButtonsPointers[2] && !motorC.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor C button released"); + + motorButtonsPointers[2] = -1; + motorButtonsTouched[2] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[3]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(pointer == motorButtonsPointers[3] && !motorD.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Motor D button released"); + + motorButtonsPointers[3] = -1; + motorButtonsTouched[3] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[2]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(pointer == motorButtonsPointers[4] && !headA.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Head A button released"); + + motorButtonsPointers[4] = -1; + motorButtonsTouched[4] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[5]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(pointer == motorButtonsPointers[5] && !headB.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Head B button released"); + + motorButtonsPointers[5] = -1; + motorButtonsTouched[5] = false; + + // Enqueue the event corresponding to releasing this button if the opposing button is not pressed already. + if(!motorButtonsTouched[4]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte) 0); + queue.addEvent(event); + } + + }else if(pointer == motorButtonsPointers[6] && !headC.getBoundingRectangle().contains(touchPointWorldCoords)){ + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Head C button released"); + + motorButtonsPointers[6] = -1; + motorButtonsTouched[6] = false; + }else{ + // TODO: Pass input to the input handler system. + } + + return true; + } + + return false; + } + + @Override + public boolean keyDown(int keycode){ + if(keycode == Input.Keys.BACK){ + core.nextState = game_states_t.MAIN_MENU; + return true; + } + + return false; + } + + /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; CONTROLLER LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + + @Override + public boolean buttonDown(Controller controller, int buttonCode){ + MotorEvent event; + + if(stateActive){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown() :: " + controller.getName() + " :: " + Integer.toString(buttonCode)); + + if(buttonCode == Ouya.BUTTON_L1){ + motorGamepadButtonPressed[0] = true; + + if(!motorGamepadButtonPressed[4]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte)-100); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_R1){ + motorGamepadButtonPressed[1] = true; + + if(!motorGamepadButtonPressed[5]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte)-100); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_DPAD_LEFT){ + motorGamepadButtonPressed[2] = false; + + if(!motorGamepadButtonPressed[3]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte)-40); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_DPAD_RIGHT){ + motorGamepadButtonPressed[3] = false; + + if(!motorGamepadButtonPressed[2]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte)40); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_L2){ + motorGamepadButtonPressed[4] = false; + + if(!motorGamepadButtonPressed[0]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte)100); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_R2){ + motorGamepadButtonPressed[5] = false; + + if(!motorGamepadButtonPressed[1]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte)100); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_Y){ + motorGamepadButtonPressed[6] = true; + + event = new MotorEvent(); + event.setMotor(motor_t.RECENTER); + event.setPower((byte)0x00); + queue.addEvent(event); + }else{ + // TODO: Pass input to the input handler system. + } + + return true; + }else{ + return false; + } + } + + @Override + public boolean buttonUp(Controller controller, int buttonCode){ + MotorEvent event; + + if(stateActive){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown() :: " + controller.getName() + " :: " + Integer.toString(buttonCode)); + + if(buttonCode == Ouya.BUTTON_L1){ + motorGamepadButtonPressed[0] = false; + + if(!motorGamepadButtonPressed[4]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte)0); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_R1){ + motorGamepadButtonPressed[1] = false; + + if(!motorGamepadButtonPressed[5]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte)0); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_DPAD_LEFT){ + motorGamepadButtonPressed[2] = false; + + if(!motorGamepadButtonPressed[3]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte)0); + queue.addEvent(event); + } + }else if(buttonCode == Ouya.BUTTON_DPAD_RIGHT){ + motorGamepadButtonPressed[3] = false; + + if(!motorGamepadButtonPressed[2]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_B); + event.setPower((byte)0); + queue.addEvent(event); + } + }else if(buttonCode == Ouya.BUTTON_L2){ + motorGamepadButtonPressed[4] = false; + + if(!motorGamepadButtonPressed[0]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_A); + event.setPower((byte)0); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_R2){ + motorGamepadButtonPressed[5] = false; + + if(!motorGamepadButtonPressed[1]){ + event = new MotorEvent(); + event.setMotor(motor_t.MOTOR_C); + event.setPower((byte)0); + queue.addEvent(event); + } + + }else if(buttonCode == Ouya.BUTTON_Y){ + motorGamepadButtonPressed[6] = false; + }else{ + // TODO: Pass input to the input handler system. + } + + return true; + }else{ + return false; + } + } + + @Override + public boolean axisMoved(Controller controller, int axisCode, float value){ + // TODO: Pass input to the input handler system. + return false; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java index 13b5af2..7f3b5b9 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java @@ -20,9 +20,6 @@ import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; -import com.badlogic.gdx.controllers.Controller; -import com.badlogic.gdx.controllers.PovDirection; -import com.badlogic.gdx.controllers.mappings.Ouya; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; @@ -42,78 +39,94 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; - public abstract class MainMenuStateBase extends BaseState{ protected static final String TAG = "MAIN_MENU"; private static final String CLASS_NAME = MainMenuStateBase.class.getSimpleName(); - private static final String SHADER_PATH = "shaders/bckg/bckg"; + protected final int NUM_MENU_BUTTONS = 2; + // Helper fields. protected boolean clientConnected; private float u_scaling[]; - protected OrthographicCamera pixelPerfectCamera; // Buttons and other gui components. protected TextButton startButton; protected Rectangle startButtonBBox; protected Sprite clientConnectedLedOn; protected Sprite clientConnectedLedOff; + + protected TextButton calibrationButton; + protected Rectangle calibrationButtonBBox; + protected Sprite cameraCalibratedLedOn; + protected Sprite cameraCalibratedLedOff; + protected Sprite background; // Graphic data for the start button. - private Texture startButtonEnabledTexture; - private Texture startButtonDisabledTexture; - private Texture startButtonPressedTexture; - private NinePatch startButtonEnabled9p; - private NinePatch startButtonDisabled9p; - private NinePatch startButtonPressed9p; + private Texture menuButtonEnabledTexture; + private Texture menuButtonDisabledTexture; + private Texture menuButtonPressedTexture; + private NinePatch menuButtonEnabled9p; + private NinePatch menuButtonDisabled9p; + private NinePatch menuButtonPressed9p; private BitmapFont font; // Other graphics. + private Texture cameraCalibratedLedOffTexture; + private Texture cameraCalibratedLedOnTexture; private Texture clientConnectedLedOffTexture; private Texture clientConnectedLedOnTexture; private Texture backgroundTexture; private ShaderProgram backgroundShader; // Button touch helper fields. - private Vector3 win2world; - protected Vector2 touchPointWorldCoords; protected boolean startButtonTouched; protected int startButtonTouchPointer; + protected boolean calibrationButtonTouched; + protected int calibrationButtonTouchPointer; public MainMenuStateBase(){ TextureRegion region; + TextButtonStyle tbs; + FreeTypeFontGenerator generator; this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); // Create the start button background. - startButtonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png")); - startButtonEnabled9p = new NinePatch(new TextureRegion(startButtonEnabledTexture, 0, 0, startButtonEnabledTexture.getWidth(), startButtonEnabledTexture.getHeight()), 49, 49, 45, 45); + menuButtonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png")); + menuButtonEnabled9p = new NinePatch(new TextureRegion(menuButtonEnabledTexture, 0, 0, menuButtonEnabledTexture.getWidth(), menuButtonEnabledTexture.getHeight()), 49, 49, 45, 45); - startButtonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png")); - startButtonDisabled9p = new NinePatch(new TextureRegion(startButtonDisabledTexture, 0, 0, startButtonDisabledTexture.getWidth(), startButtonDisabledTexture.getHeight()), 49, 49, 45, 45); + menuButtonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png")); + menuButtonDisabled9p = new NinePatch(new TextureRegion(menuButtonDisabledTexture, 0, 0, menuButtonDisabledTexture.getWidth(), menuButtonDisabledTexture.getHeight()), 49, 49, 45, 45); - startButtonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png")); - startButtonPressed9p = new NinePatch(new TextureRegion(startButtonPressedTexture, 0, 0, startButtonPressedTexture.getWidth(), startButtonPressedTexture.getHeight()), 49, 49, 45, 45); + menuButtonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png")); + menuButtonPressed9p = new NinePatch(new TextureRegion(menuButtonPressedTexture, 0, 0, menuButtonPressedTexture.getWidth(), menuButtonPressedTexture.getHeight()), 49, 49, 45, 45); // Create the start button font. - FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf")); - font = generator.generateFont(Ouya.runningOnOuya ? 60 : 40, ProjectConstants.FONT_CHARS, false); + generator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf")); + font = generator.generateFont(ProjectConstants.MENU_BUTTON_FONT_SIZE, ProjectConstants.FONT_CHARS, false); generator.dispose(); - // Create the start button itself. - TextButtonStyle tbs = new TextButtonStyle(); + // Create the start button. + tbs = new TextButtonStyle(); tbs.font = font; - tbs.up = new NinePatchDrawable(startButtonEnabled9p); - tbs.checked = new NinePatchDrawable(startButtonPressed9p); - tbs.disabled = new NinePatchDrawable(startButtonDisabled9p); + tbs.up = new NinePatchDrawable(menuButtonEnabled9p); + tbs.checked = new NinePatchDrawable(menuButtonPressed9p); + tbs.disabled = new NinePatchDrawable(menuButtonDisabled9p); tbs.disabledFontColor = new Color(0, 0, 0, 1); + startButton = new TextButton("Start server", tbs); startButton.setText("Start game"); startButton.setDisabled(true); startButtonBBox = new Rectangle(0, 0, startButton.getWidth(), startButton.getHeight()); + // Create the calibration button. + calibrationButton = new TextButton("Calibrate camera", tbs); + calibrationButton.setText("Calibrate camera"); + calibrationButton.setDisabled(true); + calibrationButtonBBox = new Rectangle(0, 0, calibrationButton.getWidth(), calibrationButton.getHeight()); + // Create the connection leds. clientConnectedLedOnTexture = new Texture("data/gfx/gui/Anonymous_Button_Green.png"); region = new TextureRegion(clientConnectedLedOnTexture); @@ -123,6 +136,14 @@ public abstract class MainMenuStateBase extends BaseState{ region = new TextureRegion(clientConnectedLedOffTexture); clientConnectedLedOff = new Sprite(region); + cameraCalibratedLedOnTexture = new Texture("data/gfx/gui/Anonymous_Button_Green.png"); + region = new TextureRegion(cameraCalibratedLedOnTexture); + cameraCalibratedLedOn = new Sprite(region); + + cameraCalibratedLedOffTexture = new Texture("data/gfx/gui/Anonymous_Button_Red.png"); + region = new TextureRegion(cameraCalibratedLedOffTexture); + cameraCalibratedLedOff = new Sprite(region); + // Set up the background. backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png")); backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); @@ -132,7 +153,7 @@ public abstract class MainMenuStateBase extends BaseState{ background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); - backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + ".vert"), Gdx.files.internal(SHADER_PATH + ".frag")); + backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl")); if(!backgroundShader.isCompiled()){ Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader."); Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); @@ -148,6 +169,8 @@ public abstract class MainMenuStateBase extends BaseState{ touchPointWorldCoords = new Vector2(); startButtonTouched = false; startButtonTouchPointer = -1; + calibrationButtonTouched = false; + calibrationButtonTouchPointer = -1; clientConnected = false; stateActive = false; @@ -172,11 +195,13 @@ public abstract class MainMenuStateBase extends BaseState{ @Override public void dispose(){ - startButtonEnabledTexture.dispose(); - startButtonDisabledTexture.dispose(); - startButtonPressedTexture.dispose(); + menuButtonEnabledTexture.dispose(); + menuButtonDisabledTexture.dispose(); + menuButtonPressedTexture.dispose(); clientConnectedLedOnTexture.dispose(); clientConnectedLedOffTexture.dispose(); + cameraCalibratedLedOnTexture.dispose(); + cameraCalibratedLedOffTexture.dispose(); backgroundTexture.dispose(); if(backgroundShader != null) backgroundShader.dispose(); font.dispose(); @@ -210,16 +235,7 @@ public abstract class MainMenuStateBase extends BaseState{ public void onClientConnected(){ clientConnected = true; startButton.setDisabled(false); - } - - /*;;;;;;;;;;;;;;;;;; - ; HELPER METHODS ; - ;;;;;;;;;;;;;;;;;;*/ - - protected void unprojectTouch(int screenX, int screenY){ - win2world.set(screenX, screenY, 0.0f); - pixelPerfectCamera.unproject(win2world); - touchPointWorldCoords.set(win2world.x, win2world.y); + calibrationButton.setDisabled(false); } /*;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -233,11 +249,16 @@ public abstract class MainMenuStateBase extends BaseState{ Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button)); Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); - if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords)){ + if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords) && !calibrationButtonTouched){ startButton.setChecked(true); startButtonTouched = true; startButtonTouchPointer = pointer; Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button pressed."); + }else if(!calibrationButton.isDisabled() && calibrationButtonBBox.contains(touchPointWorldCoords) && !startButtonTouched){ + calibrationButton.setChecked(true); + calibrationButtonTouched = true; + calibrationButtonTouchPointer = pointer; + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Calibration button pressed."); } return true; @@ -250,12 +271,18 @@ public abstract class MainMenuStateBase extends BaseState{ Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button)); Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y)); - if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords)){ + if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords) && startButtonTouched){ startButton.setChecked(false); startButtonTouched = false; startButtonTouchPointer = -1; core.nextState = game_states_t.IN_GAME; Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released."); + }else if(!calibrationButton.isDisabled() && calibrationButtonBBox.contains(touchPointWorldCoords) && calibrationButtonTouched){ + calibrationButton.setChecked(false); + calibrationButtonTouched = false; + calibrationButtonTouchPointer = -1; + core.nextState = game_states_t.CALIBRATION; + Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Calibration button released."); } return true; @@ -270,6 +297,11 @@ public abstract class MainMenuStateBase extends BaseState{ startButtonTouched = false; startButton.setChecked(false); Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released."); + }else if(!calibrationButton.isDisabled() && calibrationButtonTouched && pointer == calibrationButtonTouchPointer && !calibrationButtonBBox.contains(touchPointWorldCoords)){ + calibrationButtonTouchPointer = -1; + calibrationButtonTouched = false; + calibrationButton.setChecked(false); + Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released."); } return true; @@ -283,69 +315,4 @@ public abstract class MainMenuStateBase extends BaseState{ } return false; } - - /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; INPUT LISTENER METHOD STUBS ; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ - - @Override - public boolean keyUp(int keycode){ - return false; - } - - @Override - public boolean keyTyped(char character){ - return false; - } - - @Override - public boolean mouseMoved(int screenX, int screenY){ - return false; - } - - @Override - public boolean scrolled(int amount){ - return false; - } - - @Override - public void connected(Controller controller){ } - - @Override - public void disconnected(Controller controller){ } - - @Override - public boolean buttonDown(Controller controller, int buttonCode){ - return false; - } - - @Override - public boolean buttonUp(Controller controller, int buttonCode){ - return false; - } - - @Override - public boolean axisMoved(Controller controller, int axisCode, float value){ - return false; - } - - @Override - public boolean povMoved(Controller controller, int povCode, PovDirection value){ - return false; - } - - @Override - public boolean xSliderMoved(Controller controller, int sliderCode, boolean value){ - return false; - } - - @Override - public boolean ySliderMoved(Controller controller, int sliderCode, boolean value){ - return false; - } - - @Override - public boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value){ - return false; - } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java b/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java index ac1be8a..838b634 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java @@ -32,26 +32,34 @@ public class OuyaMainMenuState extends MainMenuStateBase{ private Texture ouyaOButtonTexture; private Sprite ouyaOButton; private boolean oButtonPressed; + private int oButtonSelection; public OuyaMainMenuState(final NxtARCore core){ + super(); + this.core = core; startButton.setPosition(-(startButton.getWidth() / 2), -(startButton.getHeight() / 2)); startButtonBBox.setPosition(startButton.getX(), startButton.getY()); - float ledYPos = (-(Gdx.graphics.getHeight() / 2) * 0.5f) + (startButton.getY() * 0.5f); + calibrationButton.setPosition(-(calibrationButton.getWidth() / 2), (startButton.getY() + startButton.getHeight()) + 10); + calibrationButtonBBox.setPosition(calibrationButton.getX(), calibrationButton.getY()); + + float ledYPos = (-(Gdx.graphics.getHeight() / 2) * 0.5f) + (calibrationButton.getY() * 0.5f); clientConnectedLedOn.setSize(clientConnectedLedOn.getWidth() * 0.5f, clientConnectedLedOn.getHeight() * 0.5f); clientConnectedLedOn.setPosition(-(clientConnectedLedOn.getWidth() / 2), ledYPos); clientConnectedLedOff.setSize(clientConnectedLedOff.getWidth() * 0.5f, clientConnectedLedOff.getHeight() * 0.5f); clientConnectedLedOff.setPosition(-(clientConnectedLedOff.getWidth() / 2), ledYPos); + // TODO: Set calibration led attributes. + ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png"); TextureRegion region = new TextureRegion(ouyaOButtonTexture, ouyaOButtonTexture.getWidth(), ouyaOButtonTexture.getHeight()); ouyaOButton = new Sprite(region); ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f); - ouyaOButton.setPosition(startButton.getX() - ouyaOButton.getWidth() - 20, startButton.getY() + (ouyaOButton.getHeight() / 2)); + oButtonSelection = 0; oButtonPressed = false; } @@ -65,13 +73,25 @@ public class OuyaMainMenuState extends MainMenuStateBase{ core.batch.disableBlending(); drawBackground(core.batch); core.batch.enableBlending(); + if(clientConnected){ clientConnectedLedOn.draw(core.batch); }else{ clientConnectedLedOff.draw(core.batch); } + + // TODO: Render calibration leds. + startButton.draw(core.batch, 1.0f); + calibrationButton.draw(core.batch, 1.0f); + + if(oButtonSelection == 0){ + ouyaOButton.setPosition(startButton.getX() - ouyaOButton.getWidth() - 20, startButton.getY() + (ouyaOButton.getHeight() / 2)); + }else if(oButtonSelection == 1){ + ouyaOButton.setPosition(calibrationButton.getX() - ouyaOButton.getWidth() - 20, calibrationButton.getY() + (ouyaOButton.getHeight() / 2)); + } ouyaOButton.draw(core.batch); + }core.batch.end(); } @@ -86,38 +106,64 @@ public class OuyaMainMenuState extends MainMenuStateBase{ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ @Override - public boolean buttonDown(Controller controller, int buttonCode) { + public boolean buttonDown(Controller controller, int buttonCode){ + // TODO: Test this. + if(stateActive){ if(buttonCode == Ouya.BUTTON_O){ - if(!clientConnected){ - core.toast("Can't start the game. No client is connected.", true); - }else{ - oButtonPressed = true; - startButton.setChecked(true); + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed."); + + if(oButtonSelection == 0){ + if(!clientConnected){ + core.toast("Can't start the game. No client is connected.", true); + }else{ + oButtonPressed = true; + startButton.setChecked(true); + } + }else if(oButtonSelection == 1){ + if(!clientConnected){ + core.toast("Can't calibrate the camera. No client is connected.", true); + }else{ + oButtonPressed = true; + calibrationButton.setChecked(true); + } } + }else if(buttonCode == Ouya.BUTTON_DPAD_UP){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): Dpad up button pressed."); + oButtonSelection = oButtonSelection - 1 < 0 ? NUM_MENU_BUTTONS - 1 : oButtonSelection - 1; + }else if(buttonCode == Ouya.BUTTON_DPAD_DOWN){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): Dpad down button pressed."); + oButtonSelection = (oButtonSelection + 1) % NUM_MENU_BUTTONS; } return true; - }else{ return false; } } @Override - public boolean buttonUp(Controller controller, int buttonCode) { + public boolean buttonUp(Controller controller, int buttonCode){ + // TODO: Test this. + if(stateActive){ if(buttonCode == Ouya.BUTTON_O){ + Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button released."); + if(oButtonPressed){ oButtonPressed = false; - startButton.setChecked(false); - core.nextState = game_states_t.IN_GAME; - Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released."); + + if(oButtonSelection == 0){ + startButton.setChecked(false); + core.nextState = game_states_t.IN_GAME; + }else if(oButtonSelection == 1){ + calibrationButton.setChecked(false); + core.nextState = game_states_t.IN_GAME; + } } } return true; - }else{ return false; } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java b/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java index 13bcfbb..61afb16 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java @@ -21,17 +21,26 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL10; public class TabletMainMenuState extends MainMenuStateBase{ + public TabletMainMenuState(final NxtARCore core){ + super(); + this.core = core; + startButton.setPosition(-(startButton.getWidth() / 2), -(startButton.getHeight() / 2)); startButtonBBox.setPosition(startButton.getX(), startButton.getY()); - float ledYPos = (-(Gdx.graphics.getHeight() / 2) * 0.5f) + (startButton.getY() * 0.5f); + calibrationButton.setPosition(-(calibrationButton.getWidth() / 2), (startButton.getY() + startButton.getHeight()) + 10); + calibrationButtonBBox.setPosition(calibrationButton.getX(), calibrationButton.getY()); + + float ledYPos = (-(Gdx.graphics.getHeight() / 2) * 0.5f) + (calibrationButton.getY() * 0.5f); clientConnectedLedOn.setSize(clientConnectedLedOn.getWidth() * 0.5f, clientConnectedLedOn.getHeight() * 0.5f); clientConnectedLedOn.setPosition(-(clientConnectedLedOn.getWidth() / 2), ledYPos); clientConnectedLedOff.setSize(clientConnectedLedOff.getWidth() * 0.5f, clientConnectedLedOff.getHeight() * 0.5f); clientConnectedLedOff.setPosition(-(clientConnectedLedOff.getWidth() / 2), ledYPos); + + // TODO: Set calibration led attributes. } @Override @@ -41,6 +50,7 @@ public class TabletMainMenuState extends MainMenuStateBase{ core.batch.setProjectionMatrix(pixelPerfectCamera.combined); core.batch.begin();{ + core.batch.disableBlending(); drawBackground(core.batch); core.batch.enableBlending(); @@ -50,7 +60,12 @@ public class TabletMainMenuState extends MainMenuStateBase{ }else{ clientConnectedLedOff.draw(core.batch); } + + // TODO: Render calibration led. + startButton.draw(core.batch, 1.0f); + calibrationButton.draw(core.batch, 1.0f); + }core.batch.end(); } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java new file mode 100644 index 0000000..f544007 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.systems; + +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; +import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent; +import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData; +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; + +import com.artemis.Aspect; +import com.artemis.ComponentMapper; +import com.artemis.Entity; +import com.artemis.annotations.Mapper; +import com.artemis.systems.EntityProcessingSystem; +import com.badlogic.gdx.Gdx; + +public class MarkerPositioningSystem extends EntityProcessingSystem { + @Mapper ComponentMapper markerMapper; + @Mapper ComponentMapper geometryMapper; + + private static final String TAG = "MARKER_POSITIONING_SYSTEM"; + private static final String CLASS_NAME = MarkerPositioningSystem.class.getSimpleName(); + + private MarkerData markers; + + @SuppressWarnings("unchecked") + public MarkerPositioningSystem(){ + super(Aspect.getAspectForAll(MarkerCodeComponent.class, GeometryComponent.class)); + + markers = null; + } + + public void setMarkerData(MarkerData markers){ + this.markers = markers; + } + + @Override + protected void process(Entity e) { + MarkerCodeComponent marker; + GeometryComponent geometry; + + if(markers == null) + return; + + Gdx.app.log(TAG, CLASS_NAME + ".process(): Getting components."); + marker = markerMapper.get(e); + geometry = geometryMapper.get(e); + + Gdx.app.log(TAG, CLASS_NAME + ".process(): Processing markers."); + for(int i = 0; i < ProjectConstants.MAXIMUM_NUMBER_OF_MARKERS; i++){ + if(markers.markerCodes[i] != 1){ + if(markers.markerCodes[i] == marker.code){ + Gdx.app.log(TAG, CLASS_NAME + ".process(): Processing marker code " + Integer.toString(markers.markerCodes[i]) + "."); + geometry.position.set(markers.translationVectors[i]); + geometry.rotation.set(markers.rotationMatrices[i]); + break; + } + }else{ + Gdx.app.log(TAG, CLASS_NAME + ".process(): Skipping marker number " + Integer.toString(i) + "."); + } + } + + markers = null; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java new file mode 100644 index 0000000..2f72ac8 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java @@ -0,0 +1,127 @@ +package ve.ucv.ciens.ccg.nxtar.systems; + +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; +import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent; +import ve.ucv.ciens.ccg.nxtar.components.MeshComponent; +import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; +import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; +import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData; +import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; + +import com.artemis.Aspect; +import com.artemis.ComponentMapper; +import com.artemis.Entity; +import com.artemis.annotations.Mapper; +import com.artemis.systems.EntityProcessingSystem; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.math.Matrix4; + +public class MarkerRenderingSystem extends EntityProcessingSystem { + @Mapper ComponentMapper markerMapper; + @Mapper ComponentMapper geometryMapper; + @Mapper ComponentMapper shaderMapper; + @Mapper ComponentMapper meshMapper; + + private static final String TAG = "MARKER_RENDERING_SYSTEM"; + private static final String CLASS_NAME = MarkerRenderingSystem.class.getSimpleName(); + + /** + *

    A matrix representing 3D translations.

    + */ + private Matrix4 translationMatrix; + + /** + *

    A matrix representing 3D rotations.

    + */ + private Matrix4 rotationMatrix; + + /** + *

    A matrix representing 3D scalings.

    + */ + private Matrix4 scalingMatrix; + + /** + *

    The total transformation to be applied to an entity.

    + */ + private Matrix4 combinedTransformationMatrix; + + MarkerData markers; + + @SuppressWarnings("unchecked") + public MarkerRenderingSystem(){ + super(Aspect.getAspectForAll(MarkerCodeComponent.class, GeometryComponent.class, ShaderComponent.class, MeshComponent.class)); + + markers = null; + translationMatrix = new Matrix4().setToTranslation(0.0f, 0.0f, 0.0f); + rotationMatrix = new Matrix4().idt(); + scalingMatrix = new Matrix4().setToScaling(0.0f, 0.0f, 0.0f); + combinedTransformationMatrix = new Matrix4(); + } + + public void setMarkerData(MarkerData markers){ + this.markers = markers; + } + + @Override + protected void process(Entity e) { + MarkerCodeComponent marker; + GeometryComponent geometry; + ShaderComponent shaderComp; + MeshComponent meshComp; + + if(markers == null) + return; + + Gdx.app.log(TAG, CLASS_NAME + ".process(): Getting components."); + marker = markerMapper.get(e); + geometry = geometryMapper.get(e); + shaderComp = shaderMapper.get(e); + meshComp = meshMapper.get(e); + + Gdx.app.log(TAG, CLASS_NAME + ".process(): Processing markers."); + for(int i = 0; i < ProjectConstants.MAXIMUM_NUMBER_OF_MARKERS; i++){ + if(markers.markerCodes[i] != 1){ + if(markers.markerCodes[i] == marker.code){ + Gdx.app.log(TAG, CLASS_NAME + ".process(): Rendering marker code " + Integer.toString(markers.markerCodes[i]) + "."); + // Set the geometric transformations. + translationMatrix.setToTranslation(geometry.position); + + rotationMatrix.val[0] = geometry.rotation.val[0]; + rotationMatrix.val[1] = geometry.rotation.val[1]; + rotationMatrix.val[2] = geometry.rotation.val[2]; + rotationMatrix.val[3] = 0; + rotationMatrix.val[4] = geometry.rotation.val[3]; + rotationMatrix.val[5] = geometry.rotation.val[4]; + rotationMatrix.val[6] = geometry.rotation.val[5]; + rotationMatrix.val[7] = 0; + rotationMatrix.val[8] = geometry.rotation.val[6]; + rotationMatrix.val[9] = geometry.rotation.val[7]; + rotationMatrix.val[10] = geometry.rotation.val[8]; + rotationMatrix.val[11] = 0; + rotationMatrix.val[12] = 0; + rotationMatrix.val[13] = 0; + rotationMatrix.val[14] = 0; + rotationMatrix.val[15] = 1; + + scalingMatrix.setToScaling(geometry.scaling); + combinedTransformationMatrix.idt().mul(translationMatrix).mul(rotationMatrix).mul(scalingMatrix); + RenderParameters.setTransformationMatrix(combinedTransformationMatrix); + + // Render the marker; + shaderComp.shader.getShaderProgram().begin();{ + shaderComp.shader.setUniforms(); + meshComp.model.render(shaderComp.shader.getShaderProgram(), GL20.GL_TRIANGLES); + }shaderComp.shader.getShaderProgram().end(); + + break; + } + }else{ + Gdx.app.log(TAG, CLASS_NAME + ".process(): Skipping marker number " + Integer.toString(i) + "."); + } + } + + markers = null; + } + +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java new file mode 100644 index 0000000..6d0b9d3 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.systems; + +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; +import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent; +import ve.ucv.ciens.ccg.nxtar.components.MeshComponent; +import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; +import ve.ucv.ciens.ccg.nxtar.graphics.LightSource; +import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; + +import com.artemis.Aspect; +import com.artemis.ComponentMapper; +import com.artemis.Entity; +import com.artemis.annotations.Mapper; +import com.artemis.systems.EntityProcessingSystem; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector3; + +/** + *

    Entity processing system in charge of rendering 3D objects using OpenGL. The + * entities to be rendered must have a geometry, shader and mesh component associated.

    + */ +public class ObjectRenderingSystem extends EntityProcessingSystem { + @Mapper ComponentMapper geometryMapper; + @Mapper ComponentMapper shaderMapper; + @Mapper ComponentMapper modelMapper; + + private static final Vector3 LIGHT_POSITION = new Vector3(2.0f, 2.0f, 4.0f); + private static final Color AMBIENT_COLOR = new Color(0.0f, 0.1f, 0.2f, 1.0f); + private static final Color DIFFUSE_COLOR = new Color(1.0f, 1.0f, 1.0f, 1.0f); + private static final Color SPECULAR_COLOR = new Color(1.0f, 0.8f, 0.0f, 1.0f); + private static final float SHINYNESS = 50.0f; + + /** + *

    A matrix representing 3D translations.

    + */ + private Matrix4 translationMatrix; + + /** + *

    A matrix representing 3D rotations.

    + */ + private Matrix4 rotationMatrix; + + /** + *

    A matrix representing 3D scalings.

    + */ + private Matrix4 scalingMatrix; + + /** + *

    The total transformation to be applied to an entity.

    + */ + private Matrix4 combinedTransformationMatrix; + + @SuppressWarnings("unchecked") + public ObjectRenderingSystem() { + super(Aspect.getAspectForAll(GeometryComponent.class, ShaderComponent.class, MeshComponent.class).exclude(MarkerCodeComponent.class)); + + RenderParameters.setLightSource1(new LightSource(LIGHT_POSITION, AMBIENT_COLOR, DIFFUSE_COLOR, SPECULAR_COLOR, SHINYNESS)); + + translationMatrix = new Matrix4().setToTranslation(0.0f, 0.0f, 0.0f); + rotationMatrix = new Matrix4().idt(); + scalingMatrix = new Matrix4().setToScaling(0.0f, 0.0f, 0.0f); + combinedTransformationMatrix = new Matrix4(); + } + + /** + *

    Renders the entity passed by parameter, calculating it's corresponding geometric + * transformation and setting and calling it's associated shader program.

    + * + * @param e The entity to be processed. + */ + @Override + protected void process(Entity e) { + GeometryComponent geometryComponent; + ShaderComponent shaderComponent; + MeshComponent meshComponent; + + // Get the necessary components. + geometryComponent = geometryMapper.get(e); + meshComponent = modelMapper.get(e); + shaderComponent = shaderMapper.get(e); + + // Calculate the geometric transformation for this entity. + translationMatrix.setToTranslation(geometryComponent.position); + rotationMatrix.set(geometryComponent.rotation); + scalingMatrix.setToScaling(geometryComponent.scaling); + combinedTransformationMatrix.idt().mul(translationMatrix).mul(rotationMatrix).mul(scalingMatrix); + + // Set up the global rendering parameters for this frame. + RenderParameters.setTransformationMatrix(combinedTransformationMatrix); + + // Render this entity. + shaderComponent.shader.getShaderProgram().begin();{ + shaderComponent.shader.setUniforms(); + meshComponent.model.render(shaderComponent.shader.getShaderProgram(), GL20.GL_TRIANGLES); + }shaderComponent.shader.getShaderProgram().end(); + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java index d53873a..8d3c2c6 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -18,26 +18,30 @@ package ve.ucv.ciens.ccg.nxtar.utils; import com.badlogic.gdx.controllers.mappings.Ouya; public abstract class ProjectConstants{ - public static final int SERVICE_DISCOVERY_PORT = 9988; - public static final int VIDEO_STREAMING_PORT = 9989; - public static final int MOTOR_CONTROL_PORT = 9990; - public static final int SENSOR_REPORT_PORT = 9991; - public static final int APP_CONTROL_PORT = 9992; + public static final int SERVICE_DISCOVERY_PORT = 9988; + public static final int VIDEO_STREAMING_PORT = 9989; + public static final int MOTOR_CONTROL_PORT = 9990; + public static final int SENSOR_REPORT_PORT = 9991; + public static final int APP_CONTROL_PORT = 9992; + public static final String MULTICAST_ADDRESS = "230.0.0.1"; - public static final String MULTICAST_ADDRESS = "230.0.0.1"; + public static final int EXIT_SUCCESS = 0; + public static final int EXIT_FAILURE = 1; - public static final int EXIT_SUCCESS = 0; - public static final int EXIT_FAILURE = 1; + public static final boolean DEBUG = true; - public static final boolean DEBUG = true; + public static final int[] POWERS_OF_2 = {64, 128, 256, 512, 1024, 2048}; - public static final int[] POWERS_OF_2 = {64, 128, 256, 512, 1024, 2048}; + public static final float OVERSCAN; + public static final int MENU_BUTTON_FONT_SIZE; + public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - public static final float OVERSCAN; - - public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + public static final int MAXIMUM_NUMBER_OF_MARKERS = 5; + public static final int CALIBRATION_PATTERN_POINTS = 54; + public static final int CALIBRATION_SAMPLES = 10; static{ OVERSCAN = Ouya.runningOnOuya ? 0.9f : 1.0f; + MENU_BUTTON_FONT_SIZE = Ouya.runningOnOuya ? 60 : 40; } }