From 06d74a6474d44515c5e4764c29a088a0efe61c5e Mon Sep 17 00:00:00 2001 From: Miguel Angel Astor Romero Date: Sat, 5 Apr 2014 15:05:20 -0430 Subject: [PATCH 01/19] Added some logging. --- .../ciens/ccg/nxtar/states/InGameState.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index e8d2c38..1474514 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -162,6 +162,7 @@ public class InGameState extends BaseState{ Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame buffer cleared."); core.batch.setProjectionMatrix(pixelPerfectCamera.combined); core.batch.begin();{ @@ -172,18 +173,20 @@ public class InGameState extends BaseState{ background.draw(core.batch); if(backgroundShader != null) core.batch.setShader(null); }core.batch.end(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Background drawn."); frame = frameMonitor.getCurrentFrame(); fW = frameMonitor.getFrameDimensions().getWidth(); fH = frameMonitor.getFrameDimensions().getHeight(); data = core.cvProc.processFrame(frame, fW, fH); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame processed."); - if(data != null){ + /*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(); @@ -191,6 +194,7 @@ public class InGameState extends BaseState{ videoFrameTexture = new Texture(videoFrame); videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); videoFrame.dispose(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture created."); TextureRegion region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); @@ -206,6 +210,7 @@ public class InGameState extends BaseState{ renderableVideoFrame.rotate90(true); renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2); } + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture resized and positioned."); if(!Ouya.runningOnOuya){ core.batch.setProjectionMatrix(camera.combined); @@ -215,13 +220,15 @@ public class InGameState extends BaseState{ core.batch.begin();{ renderableVideoFrame.draw(core.batch); }core.batch.end(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture drawn."); videoFrameTexture.dispose(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture released."); } - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); - core.batch.begin();{ - if(!Ouya.runningOnOuya){ + if(!Ouya.runningOnOuya){ + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.begin();{ motorA.draw(core.batch); motorB.draw(core.batch); motorC.draw(core.batch); @@ -229,10 +236,11 @@ public class InGameState extends BaseState{ headA.draw(core.batch); headB.draw(core.batch); headC.draw(core.batch); - } - }core.batch.end(); + }core.batch.end(); + } prevFrame = frame; + Gdx.app.log(TAG, CLASS_NAME + ".render(): Render complete."); } @Override From e93d227b626c674bf4b2a8821b92d6b1004480ea Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Apr 2014 17:57:31 -0430 Subject: [PATCH 02/19] Updated the interfaces and renamed some methods. --- src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java | 6 +++--- .../ccg/nxtar/interfaces/CVProcessor.java | 2 +- .../nxtar/interfaces/MulticastEnabler.java | 21 ------------------- ...ster.java => OSFunctionalityProvider.java} | 4 +++- .../ciens/ccg/nxtar/states/InGameState.java | 2 +- .../ccg/nxtar/utils/ProjectConstants.java | 2 ++ 6 files changed, 10 insertions(+), 27 deletions(-) delete mode 100644 src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java rename src/ve/ucv/ciens/ccg/nxtar/interfaces/{Toaster.java => OSFunctionalityProvider.java} (87%) diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 429d5d1..015fd8c 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -18,7 +18,7 @@ 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.OSFunctionalityProvider; import ve.ucv.ciens.ccg.nxtar.network.RobotControlThread; import ve.ucv.ciens.ccg.nxtar.network.SensorReportThread; import ve.ucv.ciens.ccg.nxtar.network.ServiceDiscoveryThread; @@ -95,7 +95,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ // Assorted fields. public SpriteBatch batch; public CVProcessor cvProc; - private Toaster toaster; + private OSFunctionalityProvider toaster; // Networking related fields. private int connections; @@ -124,7 +124,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ super(); connections = 0; try{ - this.toaster = (Toaster)concreteApp; + this.toaster = (OSFunctionalityProvider)concreteApp; }catch(ClassCastException cc){ Gdx.app.debug(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement the Toaster interface. Toasting disabled."); this.toaster = null; diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java index d7d09f3..64b55c9 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java @@ -22,5 +22,5 @@ public interface CVProcessor { // TODO: Add marker location data. } - public CVData processFrame(byte[] frame, int w, int h); + public CVData findMarkersInFrame(byte[] frame, int w, int h); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java deleted file mode 100644 index 80a1da2..0000000 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/MulticastEnabler.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2013 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; - -public interface MulticastEnabler { - public void enableMulticast(); - public void disableMulticast(); -} diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/Toaster.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/OSFunctionalityProvider.java similarity index 87% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/Toaster.java rename to src/ve/ucv/ciens/ccg/nxtar/interfaces/OSFunctionalityProvider.java index bee8e60..76cd6aa 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/Toaster.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/OSFunctionalityProvider.java @@ -15,7 +15,9 @@ */ package ve.ucv.ciens.ccg.nxtar.interfaces; -public interface Toaster { +public interface OSFunctionalityProvider{ 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/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 1474514..17143b2 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -179,7 +179,7 @@ public class InGameState extends BaseState{ fW = frameMonitor.getFrameDimensions().getWidth(); fH = frameMonitor.getFrameDimensions().getHeight(); - data = core.cvProc.processFrame(frame, fW, fH); + data = core.cvProc.findMarkersInFrame(frame, fW, fH); Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame processed."); /*if(data != null){ diff --git a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java index d53873a..03e69d8 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -37,6 +37,8 @@ public abstract class ProjectConstants{ public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + public static final int CALIBRATION_PATTERN_POINTS = 54; + static{ OVERSCAN = Ouya.runningOnOuya ? 0.9f : 1.0f; } From 139bb620670991e606dfa78dc5b5a4aec02b9b6a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Apr 2014 10:14:01 -0430 Subject: [PATCH 03/19] Started programming the calibration state. --- src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java | 27 ++---- .../ccg/nxtar/interfaces/CVProcessor.java | 2 + .../ucv/ciens/ccg/nxtar/states/BaseState.java | 80 ++++++++++++---- .../nxtar/states/CameraCalibrationState.java | 94 +++++++++++++++++++ .../ciens/ccg/nxtar/states/InGameState.java | 51 ---------- .../ccg/nxtar/states/MainMenuStateBase.java | 68 -------------- .../ccg/nxtar/utils/ProjectConstants.java | 1 + 7 files changed, 168 insertions(+), 155 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 015fd8c..76bd4c3 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -16,7 +16,6 @@ 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.OSFunctionalityProvider; import ve.ucv.ciens.ccg.nxtar.network.RobotControlThread; @@ -95,11 +94,10 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ // Assorted fields. public SpriteBatch batch; public CVProcessor cvProc; - private OSFunctionalityProvider toaster; + private OSFunctionalityProvider osFunction; // Networking related fields. private int connections; - private MulticastEnabler mcastEnabler; private ServiceDiscoveryThread serviceDiscoveryThread; private VideoStreamingThread videoThread; private RobotControlThread robotThread; @@ -124,17 +122,10 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ super(); connections = 0; try{ - this.toaster = (OSFunctionalityProvider)concreteApp; + this.osFunction = (OSFunctionalityProvider)concreteApp; }catch(ClassCastException cc){ Gdx.app.debug(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement the Toaster interface. Toasting disabled."); - this.toaster = 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(); + this.osFunction = null; } try{ @@ -179,7 +170,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(); @@ -326,16 +317,16 @@ 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(); } } 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/interfaces/CVProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java index 64b55c9..39629e3 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java @@ -23,4 +23,6 @@ public interface CVProcessor { } public CVData findMarkersInFrame(byte[] frame, int w, int h); + + public void calibrateCamera(); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java index 731bce3..adb99df 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java @@ -31,7 +31,7 @@ public abstract class BaseState implements Screen, ControllerListener, InputProc /* STATE METHODS */ public abstract void onStateSet(); public abstract void onStateUnset(); - + /* SCREEN METHODS*/ @Override public abstract void render(float delta); @@ -50,39 +50,83 @@ public abstract class BaseState implements Screen, ControllerListener, InputProc /* INPUT PROCESSOR METHODS. */ @Override - public abstract boolean keyDown(int keycode); + public boolean keyDown(int keycode){ + return false; + }; + @Override - public abstract boolean keyUp(int keycode); + public boolean keyUp(int keycode){ + return false; + }; + @Override - public abstract boolean keyTyped(char character); + public boolean keyTyped(char character){ + return false; + }; + @Override - public abstract boolean touchDown(int screenX, int screenY, int pointer, int button); + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + return false; + }; + @Override - public abstract boolean touchUp(int screenX, int screenY, int pointer, int button); + public boolean touchUp(int screenX, int screenY, int pointer, int button){ + return false; + }; + @Override - public abstract boolean touchDragged(int screenX, int screenY, int pointer); + public boolean touchDragged(int screenX, int screenY, int pointer){ + return false; + }; + @Override - public abstract boolean mouseMoved(int screenX, int screenY); + public boolean mouseMoved(int screenX, int screenY){ + return false; + }; + @Override - public abstract boolean scrolled(int amount); + public boolean scrolled(int amount){ + return false; + }; /* CONTROLLER LISTENER METHODS. */ @Override - public abstract void connected(Controller controller); + public void connected(Controller controller){ }; + @Override - public abstract void disconnected(Controller controller); + public void disconnected(Controller controller){ }; + @Override - public abstract boolean buttonDown(Controller controller, int buttonCode); + public boolean buttonDown(Controller controller, int buttonCode){ + return false; + }; + @Override - public abstract boolean buttonUp(Controller controller, int buttonCode); + public boolean buttonUp(Controller controller, int buttonCode){ + return false; + }; @Override - public abstract boolean axisMoved(Controller controller, int axisCode, float value); + public boolean axisMoved(Controller controller, int axisCode, float value){ + return false; + }; + @Override - public abstract boolean povMoved(Controller controller, int povCode, PovDirection value); + public boolean povMoved(Controller controller, int povCode, PovDirection value){ + return false; + }; + @Override - public abstract boolean xSliderMoved(Controller controller, int sliderCode, boolean value); + public boolean xSliderMoved(Controller controller, int sliderCode, boolean value){ + return false; + }; + @Override - public abstract boolean ySliderMoved(Controller controller, int sliderCode, boolean value); + public boolean ySliderMoved(Controller controller, int sliderCode, boolean value){ + return false; + }; + @Override - public abstract boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value); + 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..e20d0f8 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -0,0 +1,94 @@ +/* + * 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.utils.ProjectConstants; + +import com.badlogic.gdx.controllers.Controller; + +public class CameraCalibrationState extends BaseState{ + private float[][] calibrationSamples; + + public CameraCalibrationState(){ + 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(){ + 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){ } + + @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(){ } + + @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 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; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 17143b2..b7e7c03 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -30,7 +30,6 @@ 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; @@ -815,54 +814,4 @@ public class InGameState extends BaseState{ 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; - } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java index 13b5af2..93c5e99 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java @@ -20,8 +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; @@ -42,7 +40,6 @@ 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(); @@ -283,69 +280,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/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java index 03e69d8..4884fdb 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -38,6 +38,7 @@ public abstract class ProjectConstants{ public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; public static final int CALIBRATION_PATTERN_POINTS = 54; + public static final int CALIBRATION_SAMPLES = 10; static{ OVERSCAN = Ouya.runningOnOuya ? 0.9f : 1.0f; From 11ebf2b96eaadd6862343fb5aaeb360e377d1db2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Apr 2014 16:21:03 -0430 Subject: [PATCH 04/19] Continued implementation of the calibration state and interface. --- .../ccg/nxtar/interfaces/CVProcessor.java | 14 +- .../nxtar/states/CameraCalibrationState.java | 164 +++++++++++++++++- .../ciens/ccg/nxtar/states/InGameState.java | 14 +- 3 files changed, 175 insertions(+), 17 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java index 39629e3..0bce123 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java @@ -16,13 +16,19 @@ package ve.ucv.ciens.ccg.nxtar.interfaces; public interface CVProcessor { - public class CVData{ + public class CVMarkerData{ public byte[] outFrame; public int[] markerCodes; // TODO: Add marker location data. } - public CVData findMarkersInFrame(byte[] frame, int w, int h); - - public void calibrateCamera(); + public class CVCalibrationData{ + public byte[] outFrame; + public float[] calibrationPoints; + } + + public CVMarkerData findMarkersInFrame(byte[] frame); + public CVCalibrationData findCalibrationPattern(byte[] frame); + public void calibrateCamera(float[][] calibrationSamples, byte[] frame); + public byte[] undistortFrame(byte[] frame); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index e20d0f8..272fd1e 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -15,14 +15,92 @@ */ package ve.ucv.ciens.ccg.nxtar.states; -import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; +import java.util.Arrays; +import ve.ucv.ciens.ccg.nxtar.NxtARCore; +import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor.CVCalibrationData; +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.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.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 CameraCalibrationState extends BaseState{ + private static final String TAG = "IN_GAME_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; + private OrthographicCamera pixelPerfectCamera; + + // Video stream graphics. + private Texture videoFrameTexture; + private Sprite renderableVideoFrame; + private Pixmap videoFrame; + + // Button touch helper fields. + private Vector3 win2world; + private Vector2 touchPointWorldCoords; + private boolean[] motorButtonsTouched; + private int[] motorButtonsPointers; + private boolean[] motorGamepadButtonPressed; + + // Monitors. + private VideoFrameMonitor frameMonitor; + private float[][] calibrationSamples; - public CameraCalibrationState(){ + public CameraCalibrationState(final NxtARCore core){ + 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"), 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; + } + + // 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; + + // 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]; @@ -42,7 +120,87 @@ public class CameraCalibrationState extends BaseState{ public void onStateUnset(){ } @Override - public void render(float delta){ } + public void render(float delta){ + 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); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame buffer cleared."); + + // 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(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Background drawn."); + + // Fetch the current video frame and find the calibration pattern in it. + frame = frameMonitor.getCurrentFrame(); + CVCalibrationData data = core.cvProc.findCalibrationPattern(frame); + + 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(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture created."); + + // 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); + } + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture resized and positioned."); + + // 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(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture drawn."); + + // Clear texture memory. + videoFrameTexture.dispose(); + Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture released."); + } + + // Render the user interface. + if(!Ouya.runningOnOuya){ + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.begin();{ + }core.batch.end(); + }else{ + } + + // Save this frame as previous to avoid processing the same frame twice + // when network latency is high. + prevFrame = frame; + Gdx.app.log(TAG, CLASS_NAME + ".render(): Render complete."); + } @Override public void resize(int width, int height){ } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index b7e7c03..2236967 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -21,7 +21,7 @@ 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.interfaces.CVProcessor.CVMarkerData; 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; @@ -153,11 +153,10 @@ public class InGameState extends BaseState{ @Override public void render(float delta){ - int fW, fH; byte[] frame; byte[] prevFrame = null; Size dimensions = null; - CVData data; + CVMarkerData data; Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); @@ -175,10 +174,8 @@ public class InGameState extends BaseState{ Gdx.app.log(TAG, CLASS_NAME + ".render(): Background drawn."); frame = frameMonitor.getCurrentFrame(); - fW = frameMonitor.getFrameDimensions().getWidth(); - fH = frameMonitor.getFrameDimensions().getHeight(); - data = core.cvProc.findMarkersInFrame(frame, fW, fH); + data = core.cvProc.findMarkersInFrame(frame); Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame processed."); /*if(data != null){ @@ -243,10 +240,7 @@ public class InGameState extends BaseState{ } @Override - public void resize(int width, int height){ - // TODO Auto-generated method stub - - } + public void resize(int width, int height){ } @Override public void show(){ } From e976a17de0356a124044dafb402bb16c18879077 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 May 2014 11:16:40 -0430 Subject: [PATCH 05/19] Added menu transition to calibration state. --- src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java | 20 +++-- .../ccg/nxtar/interfaces/CVProcessor.java | 5 +- .../nxtar/states/CameraCalibrationState.java | 24 +++++- .../ciens/ccg/nxtar/states/InGameState.java | 1 - .../ccg/nxtar/states/MainMenuStateBase.java | 79 +++++++++++++++---- .../ccg/nxtar/states/OuyaMainMenuState.java | 62 ++++++++++++--- .../ccg/nxtar/states/TabletMainMenuState.java | 13 ++- .../ccg/nxtar/utils/ProjectConstants.java | 2 + 8 files changed, 166 insertions(+), 40 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 76bd4c3..7be016d 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -23,6 +23,7 @@ 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; @@ -64,7 +65,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ * 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; @@ -75,6 +76,10 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ public int getValue(){ return this.value; } + + public static int getNumStates(){ + return 4; + } }; /** @@ -138,13 +143,14 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ 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); for(BaseState state : states){ Controllers.addListener(state); @@ -213,10 +219,12 @@ 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); + } } public void render(){ diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java index 0bce123..e3b6c54 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java @@ -15,7 +15,7 @@ */ package ve.ucv.ciens.ccg.nxtar.interfaces; -public interface CVProcessor { +public interface CVProcessor{ public class CVMarkerData{ public byte[] outFrame; public int[] markerCodes; @@ -26,9 +26,10 @@ public interface CVProcessor { public byte[] outFrame; public float[] calibrationPoints; } - + public CVMarkerData findMarkersInFrame(byte[] frame); public CVCalibrationData findCalibrationPattern(byte[] frame); public void calibrateCamera(float[][] calibrationSamples, byte[] frame); public byte[] undistortFrame(byte[] frame); + public boolean cameraIsCalibrated(); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index 272fd1e..a3b4509 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -18,12 +18,14 @@ 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.CVProcessor.CVCalibrationData; 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.GL20; @@ -109,6 +111,10 @@ public class CameraCalibrationState extends BaseState{ @Override public void onStateSet(){ + Gdx.input.setInputProcessor(this); + Gdx.input.setCatchBackKey(true); + Gdx.input.setCatchMenuKey(true); + for(int i = 0; i < calibrationSamples.length; i++){ for(int j = 0; j < calibrationSamples[i].length; j++){ calibrationSamples[i][j] = 0.0f; @@ -145,7 +151,7 @@ public class CameraCalibrationState extends BaseState{ // Fetch the current video frame and find the calibration pattern in it. frame = frameMonitor.getCurrentFrame(); CVCalibrationData data = core.cvProc.findCalibrationPattern(frame); - + 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. @@ -218,7 +224,21 @@ public class CameraCalibrationState extends BaseState{ public void resume(){ } @Override - public void dispose(){ } + public void dispose(){ + if(videoFrameTexture != null) + videoFrameTexture.dispose(); + backgroundTexture.dispose(); + if(backgroundShader != null) backgroundShader.dispose(); + } + + @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){ diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 2236967..02875c9 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -46,7 +46,6 @@ 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; diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java index 93c5e99..4926ad0 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java @@ -20,7 +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.mappings.Ouya; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; @@ -43,9 +42,10 @@ 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[]; @@ -56,18 +56,26 @@ public abstract class MainMenuStateBase extends BaseState{ 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 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; @@ -78,39 +86,49 @@ public abstract class MainMenuStateBase extends BaseState{ protected Vector2 touchPointWorldCoords; protected boolean startButtonTouched; protected int startButtonTouchPointer; + protected boolean calibrationButtonTouched; + protected int calibrationButtonTouchPointer; public MainMenuStateBase(){ TextureRegion region; + TextButtonStyle tbs; 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); + menuButtonEnabled9p = new NinePatch(new TextureRegion(startButtonEnabledTexture, 0, 0, startButtonEnabledTexture.getWidth(), startButtonEnabledTexture.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); + menuButtonDisabled9p = new NinePatch(new TextureRegion(startButtonDisabledTexture, 0, 0, startButtonDisabledTexture.getWidth(), startButtonDisabledTexture.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); + menuButtonPressed9p = new NinePatch(new TextureRegion(startButtonPressedTexture, 0, 0, startButtonPressedTexture.getWidth(), startButtonPressedTexture.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); + 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); @@ -120,6 +138,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); @@ -145,6 +171,8 @@ public abstract class MainMenuStateBase extends BaseState{ touchPointWorldCoords = new Vector2(); startButtonTouched = false; startButtonTouchPointer = -1; + calibrationButtonTouched = false; + calibrationButtonTouchPointer = -1; clientConnected = false; stateActive = false; @@ -174,6 +202,8 @@ public abstract class MainMenuStateBase extends BaseState{ startButtonPressedTexture.dispose(); clientConnectedLedOnTexture.dispose(); clientConnectedLedOffTexture.dispose(); + cameraCalibratedLedOnTexture.dispose(); + cameraCalibratedLedOffTexture.dispose(); backgroundTexture.dispose(); if(backgroundShader != null) backgroundShader.dispose(); font.dispose(); @@ -207,6 +237,7 @@ public abstract class MainMenuStateBase extends BaseState{ public void onClientConnected(){ clientConnected = true; startButton.setDisabled(false); + calibrationButton.setDisabled(false); } /*;;;;;;;;;;;;;;;;;; @@ -230,11 +261,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; @@ -247,12 +283,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; @@ -267,6 +309,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; diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java b/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java index ac1be8a..6958f05 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java @@ -32,14 +32,20 @@ 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); @@ -50,8 +56,8 @@ public class OuyaMainMenuState extends MainMenuStateBase{ 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 +71,23 @@ 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); } + 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(); } @@ -89,16 +105,32 @@ public class OuyaMainMenuState extends MainMenuStateBase{ public boolean buttonDown(Controller controller, int buttonCode) { 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; } @@ -108,16 +140,22 @@ public class OuyaMainMenuState extends MainMenuStateBase{ public boolean buttonUp(Controller controller, int buttonCode) { 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..095e58d 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java @@ -21,12 +21,19 @@ 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); @@ -41,6 +48,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 +58,10 @@ public class TabletMainMenuState extends MainMenuStateBase{ }else{ clientConnectedLedOff.draw(core.batch); } + startButton.draw(core.batch, 1.0f); + calibrationButton.draw(core.batch, 1.0f); + }core.batch.end(); } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java index 4884fdb..c2d7173 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -34,6 +34,7 @@ public abstract class ProjectConstants{ 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"; @@ -42,5 +43,6 @@ public abstract class ProjectConstants{ static{ OVERSCAN = Ouya.runningOnOuya ? 0.9f : 1.0f; + MENU_BUTTON_FONT_SIZE = Ouya.runningOnOuya ? 60 : 40; } } From d8922182e0150788e53126f8defeb1a553c66ec3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 May 2014 13:59:15 -0430 Subject: [PATCH 06/19] Camera calibration successfully ported. --- .../ucv/ciens/ccg/nxtar/states/BaseState.java | 19 +++ .../nxtar/states/CameraCalibrationState.java | 161 +++++++++++++++--- .../ciens/ccg/nxtar/states/InGameState.java | 6 +- .../ccg/nxtar/states/MainMenuStateBase.java | 40 ++--- 4 files changed, 178 insertions(+), 48 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java index adb99df..3886705 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java @@ -22,11 +22,16 @@ 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(); @@ -35,19 +40,33 @@ public abstract class BaseState implements Screen, ControllerListener, InputProc /* 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(); + /* 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){ diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index a3b4509..3bd1f2a 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -28,20 +28,28 @@ 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 = "IN_GAME_STATE"; + 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"; @@ -54,26 +62,38 @@ public class CameraCalibrationState extends BaseState{ // Cameras. private OrthographicCamera camera; - private OrthographicCamera pixelPerfectCamera; // 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 Vector3 win2world; - private Vector2 touchPointWorldCoords; - private boolean[] motorButtonsTouched; - private int[] motorButtonsPointers; - private boolean[] motorGamepadButtonPressed; + 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(); @@ -92,7 +112,7 @@ public class CameraCalibrationState extends BaseState{ // Load the background shader. 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 + ".CameraCalibrationState() :: Failed to compile the background shader."); Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); backgroundShader = null; } @@ -102,6 +122,42 @@ public class CameraCalibrationState extends BaseState{ 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++){ @@ -115,6 +171,9 @@ public class CameraCalibrationState extends BaseState{ 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; @@ -134,7 +193,6 @@ public class CameraCalibrationState extends BaseState{ // Clear the screen. Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame buffer cleared."); // Render the background. core.batch.setProjectionMatrix(pixelPerfectCamera.combined); @@ -146,12 +204,42 @@ public class CameraCalibrationState extends BaseState{ background.draw(core.batch); if(backgroundShader != null) core.batch.setShader(null); }core.batch.end(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Background drawn."); // Fetch the current video frame and find the calibration pattern in it. frame = frameMonitor.getCurrentFrame(); + + if(core.cvProc.cameraIsCalibrated()){ + frame = core.cvProc.undistortFrame(frame); + } + CVCalibrationData data = core.cvProc.findCalibrationPattern(frame); + if(data.calibrationPoints != null && !core.cvProc.cameraIsCalibrated()){ + takeSampleButton.setDisabled(false); + }else{ + takeSampleButton.setDisabled(true); + } + + if(takeSample && !core.cvProc.cameraIsCalibrated() && data.calibrationPoints != null){ + takeSample = false; + Gdx.app.log(TAG, CLASS_NAME + ".render(): Sample taken."); + + 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]; + } + + lastSampleTaken++; + + if(lastSampleTaken == ProjectConstants.CALIBRATION_SAMPLES){ + Gdx.app.log(TAG, CLASS_NAME + "render(): Last sample taken."); + + core.toast("Calibrating camera", false); + core.cvProc.calibrateCamera(calibrationSamples, frame); + } + } + 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. @@ -160,7 +248,6 @@ public class CameraCalibrationState extends BaseState{ videoFrameTexture = new Texture(videoFrame); videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); videoFrame.dispose(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture created."); // Set up the frame texture as a rendereable sprite. TextureRegion region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); @@ -176,7 +263,6 @@ public class CameraCalibrationState extends BaseState{ renderableVideoFrame.rotate90(true); renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2); } - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture resized and positioned."); // Render the frame. if(!Ouya.runningOnOuya){ @@ -187,25 +273,22 @@ public class CameraCalibrationState extends BaseState{ core.batch.begin();{ renderableVideoFrame.draw(core.batch); }core.batch.end(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture drawn."); // Clear texture memory. videoFrameTexture.dispose(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture released."); } // 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{ } - // Save this frame as previous to avoid processing the same frame twice - // when network latency is high. + // Save this frame as previous to avoid processing the same frame twice when network latency is high. prevFrame = frame; - Gdx.app.log(TAG, CLASS_NAME + ".render(): Render complete."); } @Override @@ -231,6 +314,10 @@ public class CameraCalibrationState extends BaseState{ if(backgroundShader != null) backgroundShader.dispose(); } + /*;;;;;;;;;;;;;;;;;;;;;;;;;; + ; INPUT LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + @Override public boolean keyDown(int keycode){ if(keycode == Input.Keys.BACK){ @@ -242,17 +329,51 @@ public class CameraCalibrationState extends BaseState{ @Override public boolean touchDown(int screenX, int screenY, int pointer, int button){ - return false; + 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){ - return false; + 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){ - return false; + 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 diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 02875c9..798d916 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -76,8 +76,6 @@ public class InGameState extends BaseState{ private Sprite headC; // Button touch helper fields. - private Vector3 win2world; - private Vector2 touchPointWorldCoords; private boolean[] motorButtonsTouched; private int[] motorButtonsPointers; private boolean[] motorGamepadButtonPressed; @@ -174,6 +172,10 @@ public class InGameState extends BaseState{ frame = frameMonitor.getCurrentFrame(); + if(core.cvProc.cameraIsCalibrated()){ + frame = core.cvProc.undistortFrame(frame); + } + data = core.cvProc.findMarkersInFrame(frame); Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame processed."); diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java index 4926ad0..add544d 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java @@ -49,7 +49,6 @@ public abstract class MainMenuStateBase extends BaseState{ // Helper fields. protected boolean clientConnected; private float u_scaling[]; - protected OrthographicCamera pixelPerfectCamera; // Buttons and other gui components. protected TextButton startButton; @@ -65,9 +64,9 @@ public abstract class MainMenuStateBase extends BaseState{ protected Sprite background; // Graphic data for the start button. - private Texture startButtonEnabledTexture; - private Texture startButtonDisabledTexture; - private Texture startButtonPressedTexture; + private Texture menuButtonEnabledTexture; + private Texture menuButtonDisabledTexture; + private Texture menuButtonPressedTexture; private NinePatch menuButtonEnabled9p; private NinePatch menuButtonDisabled9p; private NinePatch menuButtonPressed9p; @@ -82,8 +81,6 @@ public abstract class MainMenuStateBase extends BaseState{ private ShaderProgram backgroundShader; // Button touch helper fields. - private Vector3 win2world; - protected Vector2 touchPointWorldCoords; protected boolean startButtonTouched; protected int startButtonTouchPointer; protected boolean calibrationButtonTouched; @@ -92,21 +89,22 @@ public abstract class MainMenuStateBase extends BaseState{ 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")); - menuButtonEnabled9p = 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")); - menuButtonDisabled9p = 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")); - menuButtonPressed9p = 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")); + 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(); @@ -197,9 +195,9 @@ 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(); @@ -240,16 +238,6 @@ public abstract class MainMenuStateBase extends BaseState{ calibrationButton.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); - } - /*;;;;;;;;;;;;;;;;;;;;;;;;;; ; INPUT LISTENER METHODS ; ;;;;;;;;;;;;;;;;;;;;;;;;;;*/ From 1146a260b6440f5b90c230b67d768ff0298d433e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 May 2014 12:32:06 -0430 Subject: [PATCH 07/19] Added intradocumentation. --- .../nxtar/states/CameraCalibrationState.java | 11 +++++- .../ciens/ccg/nxtar/states/InGameState.java | 36 ++++++++++--------- .../ccg/nxtar/utils/ProjectConstants.java | 32 ++++++++--------- 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index 3bd1f2a..081705e 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -205,33 +205,41 @@ public class CameraCalibrationState extends BaseState{ if(backgroundShader != null) core.batch.setShader(null); }core.batch.end(); - // Fetch the current video frame and find the calibration pattern in it. + // Fetch the current video frame. frame = frameMonitor.getCurrentFrame(); + // Apply the undistortion method if the camera has been calibrated already. if(core.cvProc.cameraIsCalibrated()){ frame = core.cvProc.undistortFrame(frame); } + // Find the calibration points in the video frame. CVCalibrationData data = core.cvProc.findCalibrationPattern(frame); + // Disable the sampling button if the calibration pattern was not found. if(data.calibrationPoints != null && !core.cvProc.cameraIsCalibrated()){ takeSampleButton.setDisabled(false); }else{ takeSampleButton.setDisabled(true); } + // If the user requested a sample be taken. if(takeSample && !core.cvProc.cameraIsCalibrated() && 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++; + // 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."); @@ -285,6 +293,7 @@ public class CameraCalibrationState extends BaseState{ 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. diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 798d916..583fe95 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -129,6 +129,7 @@ public class InGameState extends BaseState{ 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); @@ -136,6 +137,7 @@ public class InGameState extends BaseState{ 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(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."); @@ -154,11 +156,13 @@ public class InGameState extends BaseState{ byte[] prevFrame = null; Size dimensions = null; CVMarkerData data; + TextureRegion region; + // Clear the screen. Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame buffer cleared."); + // Render the background. core.batch.setProjectionMatrix(pixelPerfectCamera.combined); core.batch.begin();{ if(backgroundShader != null){ @@ -168,35 +172,33 @@ public class InGameState extends BaseState{ background.draw(core.batch); if(backgroundShader != null) core.batch.setShader(null); }core.batch.end(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Background drawn."); + // Fetch the current video frame. frame = frameMonitor.getCurrentFrame(); + // Apply the undistortion method if the camera has been calibrated already. if(core.cvProc.cameraIsCalibrated()){ frame = core.cvProc.undistortFrame(frame); } + // Attempt to find the markers in the current video frame. data = core.cvProc.findMarkersInFrame(frame); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Frame processed."); - - /*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 a valid frame was fetched. if(data != null && data.outFrame != null && !Arrays.equals(frame, prevFrame)){ + // Decode the video 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(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture created."); - - TextureRegion region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); + // Convert the decoded frame into a renderable texture. + region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); renderableVideoFrame = new Sprite(region); renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); + + // Set the position and orientation of the renderable video frame. if(!Ouya.runningOnOuya){ renderableVideoFrame.setSize(1.0f, renderableVideoFrame.getHeight() / renderableVideoFrame.getWidth() ); renderableVideoFrame.rotate90(true); @@ -207,22 +209,24 @@ public class InGameState extends BaseState{ renderableVideoFrame.rotate90(true); renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2); } - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture resized and positioned."); + // Set the correct camera for the device. if(!Ouya.runningOnOuya){ core.batch.setProjectionMatrix(camera.combined); }else{ core.batch.setProjectionMatrix(pixelPerfectCamera.combined); } + + // Render the video frame. core.batch.begin();{ renderableVideoFrame.draw(core.batch); }core.batch.end(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture drawn."); + // Clear the video frame from memory. videoFrameTexture.dispose(); - Gdx.app.log(TAG, CLASS_NAME + ".render(): Texture released."); } + // Render the interface buttons. if(!Ouya.runningOnOuya){ core.batch.setProjectionMatrix(pixelPerfectCamera.combined); core.batch.begin();{ @@ -236,8 +240,8 @@ public class InGameState extends BaseState{ }core.batch.end(); } + // Save this frame as previous to avoid processing the same frame twice when network latency is high. prevFrame = frame; - Gdx.app.log(TAG, CLASS_NAME + ".render(): Render complete."); } @Override diff --git a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java index c2d7173..ed0090a 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -18,28 +18,26 @@ 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 int MENU_BUTTON_FONT_SIZE; - - public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - - public static final int CALIBRATION_PATTERN_POINTS = 54; - public static final int CALIBRATION_SAMPLES = 10; + public static final int CALIBRATION_PATTERN_POINTS = 54; + public static final int CALIBRATION_SAMPLES = 10; static{ OVERSCAN = Ouya.runningOnOuya ? 0.9f : 1.0f; From 271b7d003a882ab9dcfab348011311df351a07d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 May 2014 15:25:01 -0430 Subject: [PATCH 08/19] Started sketching the 3D rendering. --- .../ciens/ccg/nxtar/states/InGameState.java | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 583fe95..9a7b5eb 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -33,12 +33,15 @@ 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.PerspectiveCamera; 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.Vector2; import com.badlogic.gdx.math.Vector3; @@ -50,14 +53,20 @@ public class InGameState extends BaseState{ private NxtARCore core; + // Background related fields. private float u_scaling[]; protected Sprite background; private Texture backgroundTexture; private ShaderProgram backgroundShader; + // 3D rendering fields. + private FrameBuffer frameBuffer; + private Sprite frameBufferSprite; + // Cameras. private OrthographicCamera camera; private OrthographicCamera pixelPerfectCamera; + private PerspectiveCamera camera3D; // Video stream graphics. private Texture videoFrameTexture; @@ -148,6 +157,11 @@ public class InGameState extends BaseState{ 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 3D rendering. + frameBuffer = null; + camera3D = null; + frameBufferSprite = new Sprite(); } @Override @@ -176,6 +190,17 @@ public class InGameState extends BaseState{ // Fetch the current video frame. frame = frameMonitor.getCurrentFrame(); + if(camera3D == null && frameBuffer == null){ + int w, h; + + w = (int)((float)frameMonitor.getFrameDimensions().getWidth() * ProjectConstants.OVERSCAN); + h = (int)((float)frameMonitor.getFrameDimensions().getHeight() * ProjectConstants.OVERSCAN); + + frameBuffer = new FrameBuffer(Format.RGB565, w, h, true); + + camera3D = new PerspectiveCamera(60, w, h); + } + // Apply the undistortion method if the camera has been calibrated already. if(core.cvProc.cameraIsCalibrated()){ frame = core.cvProc.undistortFrame(frame); @@ -198,16 +223,36 @@ public class InGameState extends BaseState{ renderableVideoFrame = new Sprite(region); renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); - // Set the position and orientation of the renderable video frame. + // TODO: Render the 3D scene here. + frameBuffer.begin();{ + Gdx.gl.glClearColor(1, 1, 1, 0); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); + + // TODO: Call 3D scene renderer. + + }frameBuffer.end(); + + // Set the renderable 3D sprite. + frameBufferSprite.setTexture(frameBuffer.getColorBufferTexture()); + + // 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() * (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); + + 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. @@ -216,10 +261,11 @@ public class InGameState extends BaseState{ }else{ core.batch.setProjectionMatrix(pixelPerfectCamera.combined); } - - // Render the video frame. + + // Render the video frame and the frame buffer. core.batch.begin();{ renderableVideoFrame.draw(core.batch); + frameBufferSprite.draw(core.batch, 1.0f); }core.batch.end(); // Clear the video frame from memory. @@ -263,12 +309,20 @@ public class InGameState extends BaseState{ 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(); + + if(backgroundShader != null) + backgroundShader.dispose(); + + if(frameBuffer != null) + frameBuffer.dispose(); } /*;;;;;;;;;;;;;;;;;; From 90427419e0cb383aa059d8f9fdb3cf4bbdb04e6c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 May 2014 16:35:19 -0430 Subject: [PATCH 09/19] Frame buffer object correctly created and positioned. --- .../nxtar/states/CameraCalibrationState.java | 13 +++- .../ciens/ccg/nxtar/states/InGameState.java | 67 ++++++++++++++++--- .../ccg/nxtar/states/MainMenuStateBase.java | 2 +- .../ccg/nxtar/states/OuyaMainMenuState.java | 12 +++- .../ccg/nxtar/states/TabletMainMenuState.java | 4 ++ 5 files changed, 83 insertions(+), 15 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index 081705e..8927df6 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -110,7 +110,7 @@ public class CameraCalibrationState extends BaseState{ background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); // Load the background shader. - 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 + ".CameraCalibrationState() :: Failed to compile the background shader."); Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog()); @@ -186,6 +186,7 @@ public class CameraCalibrationState extends BaseState{ @Override public void render(float delta){ + String msg; byte[] frame; byte[] prevFrame = null; Size dimensions = null; @@ -239,6 +240,10 @@ public class CameraCalibrationState extends BaseState{ // 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."); @@ -387,16 +392,22 @@ public class CameraCalibrationState extends BaseState{ @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 9a7b5eb..aa9dd8f 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -32,6 +32,7 @@ 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.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.Pixmap; @@ -39,8 +40,12 @@ 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.VertexAttribute; +import com.badlogic.gdx.graphics.VertexAttributes; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader; +import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.math.Vector2; @@ -84,6 +89,10 @@ public class InGameState extends BaseState{ private Sprite headB; private Sprite headC; + private MeshBuilder builder; + private Mesh mesh; + private ShaderProgram meshShader; + // Button touch helper fields. private boolean[] motorButtonsTouched; private int[] motorButtonsPointers; @@ -147,7 +156,7 @@ public class InGameState extends BaseState{ background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); // Set up the shader. - 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()); @@ -161,7 +170,15 @@ public class InGameState extends BaseState{ // Set up the 3D rendering. frameBuffer = null; camera3D = null; - frameBufferSprite = new Sprite(); + frameBufferSprite = null; + + builder = new MeshBuilder(); + builder.begin(new VertexAttributes(VertexAttribute.Position(), VertexAttribute.Color(), VertexAttribute.Normal()), GL20.GL_TRIANGLES);{ + builder.capsule(0.5f, 1.0f, 10); + }mesh = builder.end(); + + meshShader = new ShaderProgram(DefaultShader.getDefaultVertexShader(), DefaultShader.getDefaultFragmentShader()); + ShaderProgram.pedantic = false; } @Override @@ -193,12 +210,18 @@ public class InGameState extends BaseState{ if(camera3D == null && frameBuffer == null){ int w, h; - w = (int)((float)frameMonitor.getFrameDimensions().getWidth() * ProjectConstants.OVERSCAN); - h = (int)((float)frameMonitor.getFrameDimensions().getHeight() * ProjectConstants.OVERSCAN); + w = frameMonitor.getFrameDimensions().getWidth(); + h = frameMonitor.getFrameDimensions().getHeight(); - frameBuffer = new FrameBuffer(Format.RGB565, w, h, true); + frameBuffer = new FrameBuffer(Format.RGBA4444, w, h, true); + frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); camera3D = new PerspectiveCamera(60, w, h); + camera3D.position.x = 0.0f; + camera3D.position.y = 0.0f; + camera3D.position.z = (float)Math.sqrt(2); + camera3D.lookAt(0.0f, 0.0f, -1.0f); + camera3D.update(); } // Apply the undistortion method if the camera has been calibrated already. @@ -220,20 +243,34 @@ public class InGameState extends BaseState{ // Convert the decoded frame into a renderable texture. region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); - renderableVideoFrame = new Sprite(region); + if(renderableVideoFrame == null) + renderableVideoFrame = new Sprite(region); + else + renderableVideoFrame.setRegion(region); renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); + renderableVideoFrame.setPosition(0, 0); - // TODO: Render the 3D scene here. frameBuffer.begin();{ Gdx.gl.glClearColor(1, 1, 1, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); - // TODO: Call 3D scene renderer. + // TODO: Render something. + meshShader.begin();{ + meshShader.setUniformMatrix("u_projViewTrans", camera3D.combined); + meshShader.setUniform4fv("u_diffuseColor", new float[] {0.0f, 0.0f, 0.0f, 1.0f}, 0, 4); + mesh.render(meshShader, GL20.GL_TRIANGLES); + }meshShader.end(); }frameBuffer.end(); - // Set the renderable 3D sprite. - frameBufferSprite.setTexture(frameBuffer.getColorBufferTexture()); + // Set the frame buffer object texture to a renderable sprite. + region = new TextureRegion(frameBuffer.getColorBufferTexture(), 0, 0, frameBuffer.getWidth(), frameBuffer.getHeight()); + 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){ @@ -263,9 +300,11 @@ public class InGameState extends BaseState{ } // Render the video frame and the frame buffer. + core.batch.enableBlending(); + core.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); core.batch.begin();{ renderableVideoFrame.draw(core.batch); - frameBufferSprite.draw(core.batch, 1.0f); + frameBufferSprite.draw(core.batch); }core.batch.end(); // Clear the video frame from memory. @@ -323,6 +362,12 @@ public class InGameState extends BaseState{ if(frameBuffer != null) frameBuffer.dispose(); + + if(meshShader != null) + meshShader.dispose(); + + if(mesh != null) + mesh.dispose(); } /*;;;;;;;;;;;;;;;;;; diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java index add544d..7f3b5b9 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/MainMenuStateBase.java @@ -153,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()); diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java b/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java index 6958f05..838b634 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/OuyaMainMenuState.java @@ -52,6 +52,8 @@ public class OuyaMainMenuState extends MainMenuStateBase{ 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); @@ -78,6 +80,8 @@ public class OuyaMainMenuState extends MainMenuStateBase{ clientConnectedLedOff.draw(core.batch); } + // TODO: Render calibration leds. + startButton.draw(core.batch, 1.0f); calibrationButton.draw(core.batch, 1.0f); @@ -102,7 +106,9 @@ 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){ Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed."); @@ -137,7 +143,9 @@ public class OuyaMainMenuState extends MainMenuStateBase{ } @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."); diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java b/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java index 095e58d..61afb16 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/TabletMainMenuState.java @@ -39,6 +39,8 @@ public class TabletMainMenuState extends MainMenuStateBase{ clientConnectedLedOff.setSize(clientConnectedLedOff.getWidth() * 0.5f, clientConnectedLedOff.getHeight() * 0.5f); clientConnectedLedOff.setPosition(-(clientConnectedLedOff.getWidth() / 2), ledYPos); + + // TODO: Set calibration led attributes. } @Override @@ -59,6 +61,8 @@ public class TabletMainMenuState extends MainMenuStateBase{ clientConnectedLedOff.draw(core.batch); } + // TODO: Render calibration led. + startButton.draw(core.batch, 1.0f); calibrationButton.draw(core.batch, 1.0f); From de64cd972b20cad1c6250b6b09a764554086f622 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 May 2014 16:41:25 -0430 Subject: [PATCH 10/19] Successfully rendered a 3D sphere. --- .../ciens/ccg/nxtar/states/InGameState.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index aa9dd8f..6db799f 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -42,9 +42,9 @@ import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.Texture.TextureWrap; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes; +import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader; import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.ShaderProgram; @@ -54,7 +54,7 @@ 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 static final String BACKGROUND_SHADER_PATH = "shaders/bckg/bckg"; private NxtARCore core; @@ -156,7 +156,7 @@ public class InGameState extends BaseState{ background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2)); // Set up the shader. - backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl")); + 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()); @@ -173,11 +173,16 @@ public class InGameState extends BaseState{ frameBufferSprite = null; builder = new MeshBuilder(); - builder.begin(new VertexAttributes(VertexAttribute.Position(), VertexAttribute.Color(), VertexAttribute.Normal()), GL20.GL_TRIANGLES);{ - builder.capsule(0.5f, 1.0f, 10); + builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_TRIANGLES);{ + builder.setColor(1.0f, 1.0f, 0.0f, 1.0f); + builder.sphere(1.0f, 1.0f, 1.0f, 10, 10); }mesh = builder.end(); - meshShader = new ShaderProgram(DefaultShader.getDefaultVertexShader(), DefaultShader.getDefaultFragmentShader()); + meshShader = new ShaderProgram(Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_vert.glsl"), Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_frag.glsl")); + if(!meshShader.isCompiled()){ + Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + meshShader.getLog()); + Gdx.app.exit(); + } ShaderProgram.pedantic = false; } @@ -216,11 +221,11 @@ public class InGameState extends BaseState{ frameBuffer = new FrameBuffer(Format.RGBA4444, w, h, true); frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); - camera3D = new PerspectiveCamera(60, w, h); - camera3D.position.x = 0.0f; - camera3D.position.y = 0.0f; - camera3D.position.z = (float)Math.sqrt(2); - camera3D.lookAt(0.0f, 0.0f, -1.0f); + camera3D = new PerspectiveCamera(67, w, h); + camera3D.translate(0.0f, 0.0f, 3.0f); + camera3D.near = 0.01f; + camera3D.far = 100.0f; + camera3D.lookAt(0.0f, 0.0f, 0.0f); camera3D.update(); } @@ -251,16 +256,17 @@ public class InGameState extends BaseState{ renderableVideoFrame.setPosition(0, 0); frameBuffer.begin();{ + Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); Gdx.gl.glClearColor(1, 1, 1, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); // TODO: Render something. meshShader.begin();{ - meshShader.setUniformMatrix("u_projViewTrans", camera3D.combined); - meshShader.setUniform4fv("u_diffuseColor", new float[] {0.0f, 0.0f, 0.0f, 1.0f}, 0, 4); + meshShader.setUniformMatrix("u_projTrans", camera3D.combined); mesh.render(meshShader, GL20.GL_TRIANGLES); }meshShader.end(); + Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); }frameBuffer.end(); // Set the frame buffer object texture to a renderable sprite. From 6b54b1364f2091a2497d77829e729b5b15e8ce91 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 May 2014 16:21:30 -0430 Subject: [PATCH 11/19] Fixed test rendering problems. --- .../ciens/ccg/nxtar/states/InGameState.java | 1854 +++++++++-------- 1 file changed, 933 insertions(+), 921 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 6db799f..ec61303 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -1,921 +1,933 @@ -/* - * 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.CVMarkerData; -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.mappings.Ouya; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Mesh; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.PerspectiveCamera; -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.VertexAttribute; -import com.badlogic.gdx.graphics.VertexAttributes; -import com.badlogic.gdx.graphics.VertexAttributes.Usage; -import com.badlogic.gdx.graphics.g2d.Sprite; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; -import com.badlogic.gdx.graphics.glutils.FrameBuffer; -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 BACKGROUND_SHADER_PATH = "shaders/bckg/bckg"; - - private NxtARCore core; - - // Background related fields. - private float u_scaling[]; - protected Sprite background; - private Texture backgroundTexture; - private ShaderProgram backgroundShader; - - // 3D rendering fields. - private FrameBuffer frameBuffer; - private Sprite frameBufferSprite; - - // Cameras. - private OrthographicCamera camera; - private OrthographicCamera pixelPerfectCamera; - private PerspectiveCamera camera3D; - - // 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; - - private MeshBuilder builder; - private Mesh mesh; - private ShaderProgram meshShader; - - // 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. - 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; - - // 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; - } - - 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 3D rendering. - frameBuffer = null; - camera3D = null; - frameBufferSprite = null; - - builder = new MeshBuilder(); - builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_TRIANGLES);{ - builder.setColor(1.0f, 1.0f, 0.0f, 1.0f); - builder.sphere(1.0f, 1.0f, 1.0f, 10, 10); - }mesh = builder.end(); - - meshShader = new ShaderProgram(Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_vert.glsl"), Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_frag.glsl")); - if(!meshShader.isCompiled()){ - Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + meshShader.getLog()); - Gdx.app.exit(); - } - ShaderProgram.pedantic = false; - } - - @Override - public void render(float delta){ - byte[] frame; - byte[] prevFrame = null; - Size dimensions = null; - CVMarkerData data; - TextureRegion region; - - // 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(); - - if(camera3D == null && frameBuffer == null){ - int w, h; - - w = frameMonitor.getFrameDimensions().getWidth(); - h = frameMonitor.getFrameDimensions().getHeight(); - - frameBuffer = new FrameBuffer(Format.RGBA4444, w, h, true); - frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); - - camera3D = new PerspectiveCamera(67, w, h); - camera3D.translate(0.0f, 0.0f, 3.0f); - camera3D.near = 0.01f; - camera3D.far = 100.0f; - camera3D.lookAt(0.0f, 0.0f, 0.0f); - camera3D.update(); - } - - // Apply the undistortion method if the camera has been calibrated already. - if(core.cvProc.cameraIsCalibrated()){ - 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 && !Arrays.equals(frame, prevFrame)){ - // Decode the video 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(); - - // Convert the decoded frame into a renderable texture. - region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); - if(renderableVideoFrame == null) - renderableVideoFrame = new Sprite(region); - else - renderableVideoFrame.setRegion(region); - renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); - renderableVideoFrame.setPosition(0, 0); - - frameBuffer.begin();{ - Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); - Gdx.gl.glClearColor(1, 1, 1, 0); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); - - // TODO: Render something. - meshShader.begin();{ - meshShader.setUniformMatrix("u_projTrans", camera3D.combined); - mesh.render(meshShader, GL20.GL_TRIANGLES); - }meshShader.end(); - - 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()); - 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() * (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); - - 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(camera.combined); - }else{ - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); - } - - // Render the video frame and the frame buffer. - core.batch.enableBlending(); - core.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); - 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(pixelPerfectCamera.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(); - } - - // 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(); - - if(buttonTexture != null) - buttonTexture.dispose(); - - if(buttonTexture2 != null) - buttonTexture2.dispose(); - - backgroundTexture.dispose(); - - if(backgroundShader != null) - backgroundShader.dispose(); - - if(frameBuffer != null) - frameBuffer.dispose(); - - if(meshShader != null) - meshShader.dispose(); - - if(mesh != null) - mesh.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; - } -} +/* + * 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.CVMarkerData; +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.mappings.Ouya; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Mesh; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.PerspectiveCamera; +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.VertexAttribute; +import com.badlogic.gdx.graphics.VertexAttributes; +import com.badlogic.gdx.graphics.VertexAttributes.Usage; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; +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 NxtARCore core; + + // Background related fields. + private float u_scaling[]; + protected Sprite background; + private Texture backgroundTexture; + private ShaderProgram backgroundShader; + + // 3D rendering fields. + private FrameBuffer frameBuffer; + private Sprite frameBufferSprite; + private Matrix4 normalMatrix; + + // Cameras. + private OrthographicCamera camera; + private OrthographicCamera pixelPerfectCamera; + private PerspectiveCamera camera3D; + + // 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; + + private MeshBuilder builder; + private Mesh mesh; + private ShaderProgram meshShader; + + // 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. + 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; + + // 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; + } + + 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 3D rendering. + frameBuffer = null; + camera3D = null; + frameBufferSprite = null; + + 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, 0.0f, 1.0f); + builder.sphere(1.0f, 1.0f, 1.0f, 10, 10); + }mesh = builder.end(); + + meshShader = new ShaderProgram(Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_vert.glsl"), Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_frag.glsl")); + if(!meshShader.isCompiled()){ + Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + meshShader.getLog()); + Gdx.app.exit(); + } + ShaderProgram.pedantic = false; + + normalMatrix = new Matrix4(); + } + + @Override + public void render(float delta){ + byte[] frame; + byte[] prevFrame = null; + Size dimensions = null; + CVMarkerData data; + TextureRegion region; + + // 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(); + + if(camera3D == null && frameBuffer == null){ + int w, h; + + w = frameMonitor.getFrameDimensions().getWidth(); + h = frameMonitor.getFrameDimensions().getHeight(); + + frameBuffer = new FrameBuffer(Format.RGBA4444, w, h, true); + frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); + + camera3D = new PerspectiveCamera(67, w, h); + camera3D.translate(0.0f, 0.0f, 2.0f); + camera3D.near = 0.01f; + camera3D.far = 100.0f; + camera3D.lookAt(0.0f, 0.0f, 0.0f); + camera3D.update(); + } + + // Apply the undistortion method if the camera has been calibrated already. + if(core.cvProc.cameraIsCalibrated()){ + 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 && !Arrays.equals(frame, prevFrame)){ + // Decode the video 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(); + + // Convert the decoded frame into a renderable texture. + region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight()); + if(renderableVideoFrame == null) + renderableVideoFrame = new Sprite(region); + else + renderableVideoFrame.setRegion(region); + renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); + renderableVideoFrame.setPosition(0, 0); + + frameBuffer.begin();{ + Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); + Gdx.gl.glClearColor(1, 1, 1, 0); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); + + // TODO: Render something. + meshShader.begin();{ + normalMatrix.set(camera3D.combined); + meshShader.setUniformMatrix("u_projTrans", camera3D.combined); + meshShader.setUniformMatrix("u_normalMat", normalMatrix.tra().inv()); + meshShader.setUniform4fv("u_lightPos", new float[] {2.0f, 2.0f, 4.0f, 0.0f}, 0, 4); + meshShader.setUniform4fv("u_lightDiffuse", new float[] {0.0f, 0.5f, 1.0f, 1.0f}, 0, 4); + meshShader.setUniform4fv("u_ambient", new float[] {0.0f, 0.1f, 0.2f, 1.0f}, 0, 4); + meshShader.setUniform1fv("u_shiny", new float[] {2.0f}, 0, 1); + meshShader.setUniformf("u_cameraPos", camera3D.position); + mesh.render(meshShader, GL20.GL_TRIANGLES); + }meshShader.end(); + + 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(true, 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() * (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); + + 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(camera.combined); + }else{ + core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + } + + // Render the video frame and the frame buffer. + core.batch.enableBlending(); + core.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); + 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(pixelPerfectCamera.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(); + } + + // 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(); + + if(buttonTexture != null) + buttonTexture.dispose(); + + if(buttonTexture2 != null) + buttonTexture2.dispose(); + + backgroundTexture.dispose(); + + if(backgroundShader != null) + backgroundShader.dispose(); + + if(frameBuffer != null) + frameBuffer.dispose(); + + if(meshShader != null) + meshShader.dispose(); + + if(mesh != null) + mesh.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; + } +} From e82d49f1f173e1755501b577afe006c0dca94cba Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 May 2014 10:46:47 -0430 Subject: [PATCH 12/19] Testing the shader. --- .../ciens/ccg/nxtar/states/InGameState.java | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index ec61303..f67487a 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -15,8 +15,6 @@ */ 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; @@ -25,8 +23,8 @@ import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor.CVMarkerData; 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.artemis.World; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.controllers.Controller; @@ -48,7 +46,6 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; 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; @@ -68,7 +65,9 @@ public class InGameState extends BaseState{ // 3D rendering fields. private FrameBuffer frameBuffer; private Sprite frameBufferSprite; - private Matrix4 normalMatrix; + + // Game objects. + private World gameWorld; // Cameras. private OrthographicCamera camera; @@ -176,7 +175,7 @@ public class InGameState extends BaseState{ 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, 0.0f, 1.0f); + builder.setColor(1.0f, 1.0f, 1.0f, 1.0f); builder.sphere(1.0f, 1.0f, 1.0f, 10, 10); }mesh = builder.end(); @@ -185,19 +184,25 @@ public class InGameState extends BaseState{ Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + meshShader.getLog()); Gdx.app.exit(); } + // TODO: Move this line to core. ShaderProgram.pedantic = false; - normalMatrix = new Matrix4(); + // Set up Artemis. + gameWorld = new World(); + // TODO: Create entities and systems. } @Override public void render(float delta){ + int w, h; byte[] frame; - byte[] prevFrame = null; - Size dimensions = null; CVMarkerData data; TextureRegion region; + // Update the game state. + gameWorld.setDelta(Gdx.graphics.getDeltaTime() * 1000); + gameWorld.process(); + // Clear the screen. Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); @@ -215,13 +220,11 @@ public class InGameState extends BaseState{ // 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(camera3D == null && frameBuffer == null){ - int w, h; - - w = frameMonitor.getFrameDimensions().getWidth(); - h = frameMonitor.getFrameDimensions().getHeight(); - frameBuffer = new FrameBuffer(Format.RGBA4444, w, h, true); frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); @@ -242,16 +245,15 @@ public class InGameState extends BaseState{ data = core.cvProc.findMarkersInFrame(frame); // If a valid frame was fetched. - if(data != null && data.outFrame != null && !Arrays.equals(frame, prevFrame)){ + if(data != null && data.outFrame != null){ // Decode the video frame. - dimensions = frameMonitor.getFrameDimensions(); - videoFrame = new Pixmap(data.outFrame, 0, dimensions.getWidth() * dimensions.getHeight()); + 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, dimensions.getWidth(), dimensions.getHeight()); + region = new TextureRegion(videoFrameTexture, 0, 0, w, h); if(renderableVideoFrame == null) renderableVideoFrame = new Sprite(region); else @@ -264,15 +266,14 @@ public class InGameState extends BaseState{ Gdx.gl.glClearColor(1, 1, 1, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); - // TODO: Render something. + // TODO: Call rendering system. + // TODO: Move hardcoded uniforms to objects. meshShader.begin();{ - normalMatrix.set(camera3D.combined); meshShader.setUniformMatrix("u_projTrans", camera3D.combined); - meshShader.setUniformMatrix("u_normalMat", normalMatrix.tra().inv()); meshShader.setUniform4fv("u_lightPos", new float[] {2.0f, 2.0f, 4.0f, 0.0f}, 0, 4); - meshShader.setUniform4fv("u_lightDiffuse", new float[] {0.0f, 0.5f, 1.0f, 1.0f}, 0, 4); + meshShader.setUniform4fv("u_lightDiffuse", new float[] {1.0f, 1.0f, 1.0f, 1.0f}, 0, 4); meshShader.setUniform4fv("u_ambient", new float[] {0.0f, 0.1f, 0.2f, 1.0f}, 0, 4); - meshShader.setUniform1fv("u_shiny", new float[] {2.0f}, 0, 1); + meshShader.setUniform1fv("u_shiny", new float[] {50.0f}, 0, 1); meshShader.setUniformf("u_cameraPos", camera3D.position); mesh.render(meshShader, GL20.GL_TRIANGLES); }meshShader.end(); @@ -300,7 +301,7 @@ public class InGameState extends BaseState{ frameBufferSprite.rotate90(true); frameBufferSprite.translate(-frameBufferSprite.getWidth() / 2, 0.5f - frameBufferSprite.getHeight()); }else{ - float xSize = Gdx.graphics.getHeight() * (dimensions.getWidth() / dimensions.getHeight()); + 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); @@ -318,6 +319,7 @@ public class InGameState extends BaseState{ } // Render the video frame and the frame buffer. + // TODO: Enable blending only once in core. core.batch.enableBlending(); core.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); core.batch.begin();{ @@ -342,9 +344,6 @@ public class InGameState extends BaseState{ headC.draw(core.batch); }core.batch.end(); } - - // Save this frame as previous to avoid processing the same frame twice when network latency is high. - prevFrame = frame; } @Override From 167b5d644b6d77369193cfe87dec7c92db5b9565 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 May 2014 11:30:45 -0430 Subject: [PATCH 13/19] Some refactorings and touch ups. --- src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java | 13 ++++- .../ciens/ccg/nxtar/states/InGameState.java | 47 ++++++++++++------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 7be016d..3af4f70 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -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.

@@ -156,13 +158,17 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ 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; @@ -317,6 +323,9 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } } + // TODO: Disable start game button until camera has been sucessfully calibrated. + // TODO: Add calibration listener callback. + @Override public synchronized void networkStreamConnected(String streamName){ Gdx.app.log(TAG, CLASS_NAME + ".networkStreamConnected() :: Stream " + streamName + " connected."); diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index f67487a..f763661 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -57,7 +57,7 @@ public class InGameState extends BaseState{ private NxtARCore core; // Background related fields. - private float u_scaling[]; + private float uScaling[]; protected Sprite background; private Texture backgroundTexture; private ShaderProgram backgroundShader; @@ -164,9 +164,9 @@ public class InGameState extends BaseState{ 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; + 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. frameBuffer = null; @@ -184,8 +184,6 @@ public class InGameState extends BaseState{ Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + meshShader.getLog()); Gdx.app.exit(); } - // TODO: Move this line to core. - ShaderProgram.pedantic = false; // Set up Artemis. gameWorld = new World(); @@ -212,7 +210,7 @@ public class InGameState extends BaseState{ core.batch.begin();{ if(backgroundShader != null){ core.batch.setShader(backgroundShader); - backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2); + backgroundShader.setUniform2fv("u_scaling", uScaling, 0, 2); } background.draw(core.batch); if(backgroundShader != null) core.batch.setShader(null); @@ -319,9 +317,6 @@ public class InGameState extends BaseState{ } // Render the video frame and the frame buffer. - // TODO: Enable blending only once in core. - core.batch.enableBlending(); - core.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); core.batch.begin();{ renderableVideoFrame.draw(core.batch); frameBufferSprite.draw(core.batch); @@ -540,9 +535,14 @@ public class InGameState extends BaseState{ event.setPower((byte)0x00); queue.addEvent(event); } + }else{ + // TODO: Send input to the input handler system. } + + return true; } - return true; + + return false; } @Override @@ -646,9 +646,14 @@ public class InGameState extends BaseState{ motorButtonsPointers[6] = -1; motorButtonsTouched[6] = false; + }else{ + // TODO: Pass input to the input handler system. } + + return true; } - return true; + + return false; } @Override @@ -749,18 +754,23 @@ public class InGameState extends BaseState{ motorButtonsPointers[6] = -1; motorButtonsTouched[6] = false; + }else{ + // TODO: Pass input to the input handler system. } + + return true; } - return true; + + return false; } @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; } @@ -772,7 +782,7 @@ public class InGameState extends BaseState{ public boolean buttonDown(Controller controller, int buttonCode){ MotorEvent event; - if(stateActive /*&& Ouya.runningOnOuya*/){ + if(stateActive){ Gdx.app.log(TAG, CLASS_NAME + ".buttonDown() :: " + controller.getName() + " :: " + Integer.toString(buttonCode)); if(buttonCode == Ouya.BUTTON_L1){ @@ -842,6 +852,8 @@ public class InGameState extends BaseState{ event.setMotor(motor_t.RECENTER); event.setPower((byte)0x00); queue.addEvent(event); + }else{ + // TODO: Pass input to the input handler system. } return true; @@ -854,7 +866,7 @@ public class InGameState extends BaseState{ public boolean buttonUp(Controller controller, int buttonCode){ MotorEvent event; - if(stateActive /*&& Ouya.runningOnOuya*/){ + if(stateActive){ Gdx.app.log(TAG, CLASS_NAME + ".buttonDown() :: " + controller.getName() + " :: " + Integer.toString(buttonCode)); if(buttonCode == Ouya.BUTTON_L1){ @@ -917,6 +929,8 @@ public class InGameState extends BaseState{ }else if(buttonCode == Ouya.BUTTON_Y){ motorGamepadButtonPressed[6] = false; + }else{ + // TODO: Pass input to the input handler system. } return true; @@ -927,6 +941,7 @@ public class InGameState extends BaseState{ @Override public boolean axisMoved(Controller controller, int axisCode, float value){ + // TODO: Pass input to the input handler system. return false; } } From e6ea6ab4a115c0635943972d14f9b70fddf293d8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 May 2014 17:00:21 -0430 Subject: [PATCH 14/19] Added comments. --- src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java | 165 ++++++++- .../ciens/ccg/nxtar/graphics/LightSource.java | 110 ++++++ ...er.java => ApplicationEventsListener.java} | 2 +- .../ccg/nxtar/network/RobotControlThread.java | 6 +- .../ccg/nxtar/network/SensorReportThread.java | 6 +- .../nxtar/network/VideoStreamingThread.java | 6 +- .../ucv/ciens/ccg/nxtar/states/BaseState.java | 316 +++++++++--------- .../ciens/ccg/nxtar/states/InGameState.java | 34 +- 8 files changed, 445 insertions(+), 200 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java rename src/ve/ucv/ciens/ccg/nxtar/interfaces/{NetworkConnectionListener.java => ApplicationEventsListener.java} (94%) diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 3af4f70..1fa7fe5 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -16,7 +16,7 @@ package ve.ucv.ciens.ccg.nxtar; import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor; -import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener; +import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener; import ve.ucv.ciens.ccg.nxtar.interfaces.OSFunctionalityProvider; import ve.ucv.ciens.ccg.nxtar.network.RobotControlThread; import ve.ucv.ciens.ccg.nxtar.network.SensorReportThread; @@ -57,10 +57,16 @@ import com.badlogic.gdx.graphics.glutils.ShaderProgram; *
  • 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(); /** @@ -96,30 +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; + + /** + *

    The OpenCV wrapper.

    + */ public CVProcessor cvProc; + + /** + *

    Wrapper around the Operating System methods.

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

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

    + */ private int connections; + + /** + *

    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; /** @@ -127,7 +201,10 @@ 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.osFunction = (OSFunctionalityProvider)concreteApp; }catch(ClassCastException cc){ @@ -143,6 +220,14 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } } + /*;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; 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[game_states_t.getNumStates()]; @@ -154,6 +239,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ 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); } @@ -169,8 +255,8 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ // Set up the overlay font. if(ProjectConstants.DEBUG){ - 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); @@ -190,6 +276,7 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ robotThread = RobotControlThread.getInstance(); sensorThread = SensorReportThread.getInstance(); + // Launch networking threads. serviceDiscoveryThread.start(); videoThread.start(); @@ -208,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(); @@ -233,6 +320,10 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } } + /** + *

    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(); @@ -241,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); @@ -264,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();{ @@ -283,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(); @@ -323,9 +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."); @@ -340,6 +463,16 @@ public class NxtARCore extends Game implements NetworkConnectionListener{ } } + /*;;;;;;;;;;;;;;;;;; + ; 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(osFunction != null){ if(longToast) osFunction.showLongToast(msg); 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..5eb5521 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java @@ -0,0 +1,110 @@ +/* + * 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 point or directional light source.

    + */ +public class LightSource{ + private Vector3 position; + private Color ambientColor; + private Color diffuseColor; + private Color specularColor; + private float shinyness; + + 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); + ambientColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + shinyness = 10.0f; + } + + public LightSource(Vector3 position){ + 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); + ambientColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + shinyness = 10.0f; + } + + public LightSource(Vector3 position, Color ambientColor, Color diffuseColor, Color specularColor, float shinyness){ + this.position.set(position); + this.ambientColor.set(ambientColor); + this.diffuseColor.set(diffuseColor); + this.specularColor.set(specularColor); + this.shinyness = 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){ + 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/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/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..629ad22 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; } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java index 3886705..b0c2be1 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/BaseState.java @@ -1,151 +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.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 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(); - - /* 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; - }; -} +/* + * 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/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index f763661..a731ca3 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -54,8 +54,6 @@ public class InGameState extends BaseState{ private static final String CLASS_NAME = InGameState.class.getSimpleName(); private static final String BACKGROUND_SHADER_PATH = "shaders/bckg/bckg"; - private NxtARCore core; - // Background related fields. private float uScaling[]; protected Sprite background; @@ -188,8 +186,13 @@ public class InGameState extends BaseState{ // Set up Artemis. gameWorld = new World(); // TODO: Create entities and systems. + gameWorld.initialize(); } + /*;;;;;;;;;;;;;;;;;;;;;; + ; BASE STATE METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;*/ + @Override public void render(float delta){ int w, h; @@ -341,21 +344,6 @@ public class InGameState extends BaseState{ } } - @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) @@ -441,9 +429,9 @@ public class InGameState extends BaseState{ headC.setPosition(-(headC.getWidth() / 2), headA.getY() - headA.getHeight() - 10); } - /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; BEGIN INPUT PROCESSOR METHODS ; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + /*;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; INPUT PROCESSOR METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ @Override public boolean touchDown(int screenX, int screenY, int pointer, int button){ @@ -774,9 +762,9 @@ public class InGameState extends BaseState{ return false; } - /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; BEGIN CONTROLLER LISTENER METHODS ; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ + /*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; CONTROLLER LISTENER METHODS ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/ @Override public boolean buttonDown(Controller controller, int buttonCode){ From b7367427f630a2a0db76285d77d05755b223bee0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 May 2014 11:37:58 -0430 Subject: [PATCH 15/19] Successfully incorporated Artemis. --- .../ccg/nxtar/components/ModelComponent.java | 27 ++++++ .../nxtar/components/PositionComponent.java | 32 +++++++ .../ccg/nxtar/components/ShaderComponent.java | 31 +++++++ .../ShaderFailedToLoadException.java | 24 ++++++ .../ciens/ccg/nxtar/graphics/LightSource.java | 58 ++++++++++++- .../ccg/nxtar/graphics/RenderParameters.java | 75 ++++++++++++++++ .../graphics/shaders/CustomShaderBase.java | 32 +++++++ .../shaders/SingleLightPhongShader.java | 58 +++++++++++++ .../ciens/ccg/nxtar/states/InGameState.java | 51 ++++++----- .../ciens/ccg/nxtar/systems/RenderSystem.java | 86 +++++++++++++++++++ 10 files changed, 448 insertions(+), 26 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/components/ModelComponent.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/components/ShaderComponent.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/exceptions/ShaderFailedToLoadException.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/graphics/RenderParameters.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/CustomShaderBase.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPhongShader.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.java diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/ModelComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/ModelComponent.java new file mode 100644 index 0000000..e3e6208 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/ModelComponent.java @@ -0,0 +1,27 @@ +/* + * 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.graphics.Mesh; + +public class ModelComponent extends Component { + public Mesh model; + + public ModelComponent(Mesh model){ + this.model = model; + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.java new file mode 100644 index 0000000..3283512 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.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.components; + +import com.artemis.Component; +import com.badlogic.gdx.math.Vector3; + +public class PositionComponent extends Component { + public Vector3 position; + + public PositionComponent(){ + this.position = new Vector3(); + } + + public PositionComponent(Vector3 position){ + this.position = new Vector3(); + this.position.set(position); + } +} 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/exceptions/ShaderFailedToLoadException.java b/src/ve/ucv/ciens/ccg/nxtar/exceptions/ShaderFailedToLoadException.java new file mode 100644 index 0000000..c8ca5f3 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/exceptions/ShaderFailedToLoadException.java @@ -0,0 +1,24 @@ +/* + * 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.exceptions; + +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/LightSource.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java index 5eb5521..d7dab46 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/LightSource.java @@ -19,7 +19,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector3; /** - *

    A 3D point or directional light source.

    + *

    A 3D light source.

    */ public class LightSource{ private Vector3 position; @@ -28,23 +28,54 @@ public class LightSource{ 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; } - public LightSource(Vector3 position, Color ambientColor, Color diffuseColor, Color specularColor, float shinyness){ + /** + *

    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); @@ -52,6 +83,24 @@ public class LightSource{ 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); } @@ -84,7 +133,10 @@ public class LightSource{ this.specularColor.set(specularColor); } - public void setShinyness(float shinyness){ + 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; } 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/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index a731ca3..0b6f3fc 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -19,11 +19,18 @@ 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.components.ModelComponent; +import ve.ucv.ciens.ccg.nxtar.components.PositionComponent; +import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; +import ve.ucv.ciens.ccg.nxtar.exceptions.ShaderFailedToLoadException; +import ve.ucv.ciens.ccg.nxtar.graphics.shaders.SingleLightPhongShader; import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor.CVMarkerData; 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.RenderSystem; import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; +import com.artemis.Entity; import com.artemis.World; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; @@ -90,7 +97,6 @@ public class InGameState extends BaseState{ private MeshBuilder builder; private Mesh mesh; - private ShaderProgram meshShader; // Button touch helper fields. private boolean[] motorButtonsTouched; @@ -177,22 +183,30 @@ public class InGameState extends BaseState{ builder.sphere(1.0f, 1.0f, 1.0f, 10, 10); }mesh = builder.end(); - meshShader = new ShaderProgram(Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_vert.glsl"), Gdx.files.internal("shaders/singleDiffuseLight/singleDiffuseLight_frag.glsl")); - if(!meshShader.isCompiled()){ - Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + meshShader.getLog()); - Gdx.app.exit(); - } - // Set up Artemis. gameWorld = new World(); - // TODO: Create entities and systems. + + // TODO: Separate entity creation from the state class. + Entity e = gameWorld.createEntity(); + e.addComponent(new PositionComponent(new Vector3(0.5f, 0.5f, 0.0f))); + e.addComponent(new ModelComponent(mesh)); + try{ + e.addComponent(new ShaderComponent(new SingleLightPhongShader().loadShader())); + }catch(ShaderFailedToLoadException se){ + Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + se.getMessage()); + Gdx.app.exit(); + } + e.addToWorld(); + + gameWorld.setSystem(new RenderSystem(), true); + gameWorld.initialize(); } /*;;;;;;;;;;;;;;;;;;;;;; ; BASE STATE METHODS ; ;;;;;;;;;;;;;;;;;;;;;;*/ - + @Override public void render(float delta){ int w, h; @@ -235,6 +249,8 @@ public class InGameState extends BaseState{ camera3D.far = 100.0f; camera3D.lookAt(0.0f, 0.0f, 0.0f); camera3D.update(); + + gameWorld.getSystem(RenderSystem.class).setCamera(camera3D); } // Apply the undistortion method if the camera has been calibrated already. @@ -262,22 +278,14 @@ public class InGameState extends BaseState{ renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2); renderableVideoFrame.setPosition(0, 0); + // Set the 3D frame buffer for rendering. frameBuffer.begin();{ Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); Gdx.gl.glClearColor(1, 1, 1, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); - // TODO: Call rendering system. - // TODO: Move hardcoded uniforms to objects. - meshShader.begin();{ - meshShader.setUniformMatrix("u_projTrans", camera3D.combined); - meshShader.setUniform4fv("u_lightPos", new float[] {2.0f, 2.0f, 4.0f, 0.0f}, 0, 4); - meshShader.setUniform4fv("u_lightDiffuse", new float[] {1.0f, 1.0f, 1.0f, 1.0f}, 0, 4); - meshShader.setUniform4fv("u_ambient", new float[] {0.0f, 0.1f, 0.2f, 1.0f}, 0, 4); - meshShader.setUniform1fv("u_shiny", new float[] {50.0f}, 0, 1); - meshShader.setUniformf("u_cameraPos", camera3D.position); - mesh.render(meshShader, GL20.GL_TRIANGLES); - }meshShader.end(); + // Render the current state of the game. + gameWorld.getSystem(RenderSystem.class).process(); Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); }frameBuffer.end(); @@ -363,9 +371,6 @@ public class InGameState extends BaseState{ if(frameBuffer != null) frameBuffer.dispose(); - if(meshShader != null) - meshShader.dispose(); - if(mesh != null) mesh.dispose(); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.java new file mode 100644 index 0000000..6b14287 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.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.systems; + +import ve.ucv.ciens.ccg.nxtar.components.ModelComponent; +import ve.ucv.ciens.ccg.nxtar.components.PositionComponent; +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.graphics.PerspectiveCamera; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector3; + +public class RenderSystem extends EntityProcessingSystem { + @Mapper ComponentMapper positionMapper; + @Mapper ComponentMapper shaderMapper; + @Mapper ComponentMapper modelMapper; + + private PerspectiveCamera camera; + private Matrix4 translationMatrix; + + @SuppressWarnings("unchecked") + public RenderSystem() { + super(Aspect.getAspectForAll(PositionComponent.class, ShaderComponent.class, ModelComponent.class)); + + camera = null; + RenderParameters.setLightSource1(new LightSource(new Vector3(2.0f, 2.0f, 4.0f), new Color(0.0f, 0.1f, 0.2f, 1.0f), new Color(1.0f, 1.0f, 1.0f, 1.0f), new Color(1.0f, 0.8f, 0.0f, 1.0f), 50.0f)); + } + + public void setCamera(PerspectiveCamera camera) throws IllegalArgumentException { + if(camera == null) + throw new IllegalArgumentException("Camera should not be null."); + + this.camera = camera; + translationMatrix = new Matrix4().setToTranslation(0.0f, 0.0f, 0.0f); + } + + @Override + protected void process(Entity e) { + PositionComponent positionComponent; + ShaderComponent shaderComponent; + ModelComponent modelComponent; + + // If no camera has been assigned then skip this frame. + if(camera == null) + return; + + // Get the necesary components. + positionComponent = positionMapper.get(e); + modelComponent = modelMapper.get(e); + shaderComponent = shaderMapper.get(e); + + // Set up the global rendering parameters for this frame. + translationMatrix.setToTranslation(positionComponent.position); + RenderParameters.setTransformationMatrix(translationMatrix); + RenderParameters.setModelViewProjectionMatrix(camera.combined); + RenderParameters.setEyePosition(camera.position); + + // Render this entity. + shaderComponent.shader.getShaderProgram().begin();{ + shaderComponent.shader.setUniforms(); + modelComponent.model.render(shaderComponent.shader.getShaderProgram(), GL20.GL_TRIANGLES); + }shaderComponent.shader.getShaderProgram().end(); + } +} From 82e95ed0f7583bf02c8b72927d0254e1a8db11f5 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 12 May 2014 14:30:24 -0430 Subject: [PATCH 16/19] Added aditional geometric transformation info to rendering. Added entity creator. --- .../nxtar/components/GeometryComponent.java | 50 +++++++ .../EntityCreatorBase.java} | 23 +-- .../nxtar/entities/TestGameEntityCreator.java | 131 ++++++++++++++++++ .../ciens/ccg/nxtar/states/InGameState.java | 57 +++----- ...RenderSystem.java => RenderingSystem.java} | 46 +++--- 5 files changed, 230 insertions(+), 77 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java rename src/ve/ucv/ciens/ccg/nxtar/{components/PositionComponent.java => entities/EntityCreatorBase.java} (61%) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java rename src/ve/ucv/ciens/ccg/nxtar/systems/{RenderSystem.java => RenderingSystem.java} (67%) 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..1ca65a1 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java @@ -0,0 +1,50 @@ +/* + * 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.Quaternion; +import com.badlogic.gdx.math.Vector3; + +public class GeometryComponent extends Component { + public Vector3 position; + public Quaternion rotation; + public Vector3 scaling; + + public GeometryComponent(){ + this.position = new Vector3(); + this.rotation = new Quaternion(new Vector3(1.0f, 0.0f, 0.0f), 0.0f); + this.scaling = new Vector3(1.0f, 1.0f, 1.0f); + } + + public GeometryComponent(Vector3 position){ + this.position = new Vector3(position); + this.rotation = new Quaternion(new Vector3(1.0f, 0.0f, 0.0f), 0.0f); + this.scaling = new Vector3(1.0f, 1.0f, 1.0f); + } + + public GeometryComponent(Quaternion rotation){ + this.position = new Vector3(); + this.rotation = new Quaternion(rotation); + this.scaling = new Vector3(1.0f, 1.0f, 1.0f); + } + + public GeometryComponent(Vector3 position, Quaternion rotation, Vector3 scaling){ + this.position = new Vector3(position); + this.rotation = new Quaternion(rotation); + this.scaling = new Vector3(scaling); + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.java b/src/ve/ucv/ciens/ccg/nxtar/entities/EntityCreatorBase.java similarity index 61% rename from src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.java rename to src/ve/ucv/ciens/ccg/nxtar/entities/EntityCreatorBase.java index 3283512..a5a8fa0 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/components/PositionComponent.java +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/EntityCreatorBase.java @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ve.ucv.ciens.ccg.nxtar.components; +package ve.ucv.ciens.ccg.nxtar.entities; -import com.artemis.Component; -import com.badlogic.gdx.math.Vector3; +import com.artemis.World; -public class PositionComponent extends Component { - public Vector3 position; +public abstract class EntityCreatorBase { + protected World world; - public PositionComponent(){ - this.position = new Vector3(); + public void setWorld(World world) throws IllegalArgumentException{ + if(world == null) + throw new IllegalArgumentException("World cannot be null."); + + this.world = world; } - public PositionComponent(Vector3 position){ - this.position = new Vector3(); - this.position.set(position); - } + public abstract void createAllEntities(); + + public abstract void 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..7a593f7 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java @@ -0,0 +1,131 @@ +/* + * 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.ModelComponent; +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; +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.Quaternion; +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() { + Entity sphere; + Entity cube; + Entity capsule1; + Entity capsule2; + + Gdx.app.log(TAG, CLASS_NAME + ".createAllEntities(): Started."); + + // 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))); + sphere.addComponent(new ModelComponent(sphereMesh)); + sphere.addComponent(new ShaderComponent(singleLightPhongShader)); + + cube = world.createEntity(); + cube.addComponent(new GeometryComponent(new Vector3(-0.5f, -0.5f, 0.0f), new Quaternion(new Vector3(1.0f, 1.0f, 0.0f), 0.0f), new Vector3(1.0f, 1.0f, 1.0f))); + cube.addComponent(new ModelComponent(cubeMesh)); + cube.addComponent(new ShaderComponent(singleLightPhongShader)); + + capsule1 = world.createEntity(); + capsule1.addComponent(new GeometryComponent(new Vector3(-0.5f, 0.5f, 0.0f), new Quaternion(new Vector3(1.0f, 0.0f, 0.0f), 0.0f), new Vector3(1.5f, 1.0f, 1.0f))); + capsule1.addComponent(new ModelComponent(capsuleMesh)); + capsule1.addComponent(new ShaderComponent(singleLightPhongShader)); + + capsule2 = world.createEntity(); + capsule2.addComponent(new GeometryComponent(new Vector3(0.5f, -0.5f, 0.0f), new Quaternion(new Vector3(0.0f, 1.0f, 0.0f), 0.0f), new Vector3(1.0f, 1.5f, 1.0f))); + capsule2.addComponent(new ModelComponent(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/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 0b6f3fc..0017dff 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -19,25 +19,21 @@ 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.components.ModelComponent; -import ve.ucv.ciens.ccg.nxtar.components.PositionComponent; -import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; -import ve.ucv.ciens.ccg.nxtar.exceptions.ShaderFailedToLoadException; -import ve.ucv.ciens.ccg.nxtar.graphics.shaders.SingleLightPhongShader; +import ve.ucv.ciens.ccg.nxtar.entities.EntityCreatorBase; +import ve.ucv.ciens.ccg.nxtar.entities.TestGameEntityCreator; +import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor.CVMarkerData; 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.RenderSystem; +import ve.ucv.ciens.ccg.nxtar.systems.RenderingSystem; import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants; -import com.artemis.Entity; 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.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.Pixmap; @@ -45,12 +41,8 @@ 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.VertexAttribute; -import com.badlogic.gdx.graphics.VertexAttributes; -import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.math.Vector2; @@ -73,6 +65,7 @@ public class InGameState extends BaseState{ // Game objects. private World gameWorld; + private EntityCreatorBase entityCreator; // Cameras. private OrthographicCamera camera; @@ -95,9 +88,6 @@ public class InGameState extends BaseState{ private Sprite headB; private Sprite headC; - private MeshBuilder builder; - private Mesh mesh; - // Button touch helper fields. private boolean[] motorButtonsTouched; private int[] motorButtonsPointers; @@ -177,28 +167,13 @@ public class InGameState extends BaseState{ camera3D = null; frameBufferSprite = null; - 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); - }mesh = builder.end(); - - // Set up Artemis. + // Set up the game world. gameWorld = new World(); + entityCreator = new TestGameEntityCreator(); + entityCreator.setWorld(gameWorld); - // TODO: Separate entity creation from the state class. - Entity e = gameWorld.createEntity(); - e.addComponent(new PositionComponent(new Vector3(0.5f, 0.5f, 0.0f))); - e.addComponent(new ModelComponent(mesh)); - try{ - e.addComponent(new ShaderComponent(new SingleLightPhongShader().loadShader())); - }catch(ShaderFailedToLoadException se){ - Gdx.app.error(TAG, CLASS_NAME + ".InGameState(): " + se.getMessage()); - Gdx.app.exit(); - } - e.addToWorld(); - - gameWorld.setSystem(new RenderSystem(), true); + entityCreator.createAllEntities(); + gameWorld.setSystem(new RenderingSystem(), true); gameWorld.initialize(); } @@ -249,8 +224,6 @@ public class InGameState extends BaseState{ camera3D.far = 100.0f; camera3D.lookAt(0.0f, 0.0f, 0.0f); camera3D.update(); - - gameWorld.getSystem(RenderSystem.class).setCamera(camera3D); } // Apply the undistortion method if the camera has been calibrated already. @@ -285,7 +258,9 @@ public class InGameState extends BaseState{ Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); // Render the current state of the game. - gameWorld.getSystem(RenderSystem.class).process(); + RenderParameters.setModelViewProjectionMatrix(camera3D.combined); + RenderParameters.setEyePosition(camera3D.position); + gameWorld.getSystem(RenderingSystem.class).process(); Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); }frameBuffer.end(); @@ -354,6 +329,9 @@ public class InGameState extends BaseState{ @Override public void dispose(){ + if(entityCreator != null) + entityCreator.dispose(); + if(videoFrameTexture != null) videoFrameTexture.dispose(); @@ -370,9 +348,6 @@ public class InGameState extends BaseState{ if(frameBuffer != null) frameBuffer.dispose(); - - if(mesh != null) - mesh.dispose(); } /*;;;;;;;;;;;;;;;;;; diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/RenderingSystem.java similarity index 67% rename from src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.java rename to src/ve/ucv/ciens/ccg/nxtar/systems/RenderingSystem.java index 6b14287..28b48ff 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/RenderSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/RenderingSystem.java @@ -15,8 +15,8 @@ */ package ve.ucv.ciens.ccg.nxtar.systems; +import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; import ve.ucv.ciens.ccg.nxtar.components.ModelComponent; -import ve.ucv.ciens.ccg.nxtar.components.PositionComponent; import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent; import ve.ucv.ciens.ccg.nxtar.graphics.LightSource; import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; @@ -28,54 +28,50 @@ 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.graphics.PerspectiveCamera; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; -public class RenderSystem extends EntityProcessingSystem { - @Mapper ComponentMapper positionMapper; +public class RenderingSystem extends EntityProcessingSystem { + @Mapper ComponentMapper geometryMapper; @Mapper ComponentMapper shaderMapper; @Mapper ComponentMapper modelMapper; - private PerspectiveCamera camera; private Matrix4 translationMatrix; + private Matrix4 rotationMatrix; + private Matrix4 scalingMatrix; + private Matrix4 combinedTransformationMatrix; @SuppressWarnings("unchecked") - public RenderSystem() { - super(Aspect.getAspectForAll(PositionComponent.class, ShaderComponent.class, ModelComponent.class)); + public RenderingSystem() { + super(Aspect.getAspectForAll(GeometryComponent.class, ShaderComponent.class, ModelComponent.class)); - camera = null; RenderParameters.setLightSource1(new LightSource(new Vector3(2.0f, 2.0f, 4.0f), new Color(0.0f, 0.1f, 0.2f, 1.0f), new Color(1.0f, 1.0f, 1.0f, 1.0f), new Color(1.0f, 0.8f, 0.0f, 1.0f), 50.0f)); - } - public void setCamera(PerspectiveCamera camera) throws IllegalArgumentException { - if(camera == null) - throw new IllegalArgumentException("Camera should not be null."); - - this.camera = camera; translationMatrix = new Matrix4().setToTranslation(0.0f, 0.0f, 0.0f); + rotationMatrix = new Matrix4().setToRotation(1.0f, 0.0f, 0.0f, 0.0f); + scalingMatrix = new Matrix4().setToScaling(0.0f, 0.0f, 0.0f); + combinedTransformationMatrix = new Matrix4(); } @Override protected void process(Entity e) { - PositionComponent positionComponent; + GeometryComponent geometryComponent; ShaderComponent shaderComponent; ModelComponent modelComponent; - // If no camera has been assigned then skip this frame. - if(camera == null) - return; - - // Get the necesary components. - positionComponent = positionMapper.get(e); + // Get the necessary components. + geometryComponent = geometryMapper.get(e); modelComponent = modelMapper.get(e); shaderComponent = shaderMapper.get(e); + // Calculate the geometric transformation for this entity. + translationMatrix.setToTranslation(geometryComponent.position); + rotationMatrix.rotate(geometryComponent.rotation); + scalingMatrix.setToScaling(geometryComponent.scaling); + combinedTransformationMatrix.idt().mul(scalingMatrix).mul(rotationMatrix).mul(translationMatrix); + // Set up the global rendering parameters for this frame. - translationMatrix.setToTranslation(positionComponent.position); - RenderParameters.setTransformationMatrix(translationMatrix); - RenderParameters.setModelViewProjectionMatrix(camera.combined); - RenderParameters.setEyePosition(camera.position); + RenderParameters.setTransformationMatrix(combinedTransformationMatrix); // Render this entity. shaderComponent.shader.getShaderProgram().begin();{ From fbb25ead08132f8168da645804bd028dde1c5d1f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 13 May 2014 18:29:25 -0430 Subject: [PATCH 17/19] Added marker positioning and rendering. Not tested yet. --- src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java | 12 +- .../nxtar/components/GeometryComponent.java | 22 +--- .../nxtar/components/MarkerCodeComponent.java | 28 +++++ ...ModelComponent.java => MeshComponent.java} | 4 +- .../nxtar/entities/BombGameEntityCreator.java | 32 ++++++ .../nxtar/entities/TestGameEntityCreator.java | 23 ++-- ....java => AndroidFunctionalityWrapper.java} | 2 +- .../{CVProcessor.java => ImageProcessor.java} | 18 +-- .../nxtar/states/CameraCalibrationState.java | 10 +- .../ciens/ccg/nxtar/states/InGameState.java | 29 +++-- .../systems/MarkerPositioningSystem.java | 77 +++++++++++++ .../nxtar/systems/MarkerRenderingSystem.java | 108 ++++++++++++++++++ ...System.java => ObjectRenderingSystem.java} | 54 +++++++-- .../ccg/nxtar/utils/ProjectConstants.java | 1 + 14 files changed, 351 insertions(+), 69 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/components/MarkerCodeComponent.java rename src/ve/ucv/ciens/ccg/nxtar/components/{ModelComponent.java => MeshComponent.java} (90%) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/entities/BombGameEntityCreator.java rename src/ve/ucv/ciens/ccg/nxtar/interfaces/{OSFunctionalityProvider.java => AndroidFunctionalityWrapper.java} (94%) rename src/ve/ucv/ciens/ccg/nxtar/interfaces/{CVProcessor.java => ImageProcessor.java} (69%) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java create mode 100644 src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java rename src/ve/ucv/ciens/ccg/nxtar/systems/{RenderingSystem.java => ObjectRenderingSystem.java} (59%) diff --git a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java index 1fa7fe5..62ec6ce 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java +++ b/src/ve/ucv/ciens/ccg/nxtar/NxtARCore.java @@ -15,9 +15,9 @@ */ package ve.ucv.ciens.ccg.nxtar; -import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor; +import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor; import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener; -import ve.ucv.ciens.ccg.nxtar.interfaces.OSFunctionalityProvider; +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; @@ -116,12 +116,12 @@ public class NxtARCore extends Game implements ApplicationEventsListener{ /** *

    The OpenCV wrapper.

    */ - public CVProcessor cvProc; + public ImageProcessor cvProc; /** *

    Wrapper around the Operating System methods.

    */ - private OSFunctionalityProvider osFunction; + private AndroidFunctionalityWrapper osFunction; // Networking related fields. /** @@ -206,14 +206,14 @@ public class NxtARCore extends Game implements ApplicationEventsListener{ // Check if the concrete application implements all required interfaces. try{ - this.osFunction = (OSFunctionalityProvider)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.osFunction = null; } 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(); diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java index 1ca65a1..674386e 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java +++ b/src/ve/ucv/ciens/ccg/nxtar/components/GeometryComponent.java @@ -16,35 +16,23 @@ package ve.ucv.ciens.ccg.nxtar.components; import com.artemis.Component; -import com.badlogic.gdx.math.Quaternion; +import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Vector3; public class GeometryComponent extends Component { public Vector3 position; - public Quaternion rotation; + public Matrix3 rotation; public Vector3 scaling; public GeometryComponent(){ this.position = new Vector3(); - this.rotation = new Quaternion(new Vector3(1.0f, 0.0f, 0.0f), 0.0f); + this.rotation = new Matrix3(); this.scaling = new Vector3(1.0f, 1.0f, 1.0f); } - public GeometryComponent(Vector3 position){ + public GeometryComponent(Vector3 position, Matrix3 rotation, Vector3 scaling){ this.position = new Vector3(position); - this.rotation = new Quaternion(new Vector3(1.0f, 0.0f, 0.0f), 0.0f); - this.scaling = new Vector3(1.0f, 1.0f, 1.0f); - } - - public GeometryComponent(Quaternion rotation){ - this.position = new Vector3(); - this.rotation = new Quaternion(rotation); - this.scaling = new Vector3(1.0f, 1.0f, 1.0f); - } - - public GeometryComponent(Vector3 position, Quaternion rotation, Vector3 scaling){ - this.position = new Vector3(position); - this.rotation = new Quaternion(rotation); + 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/components/ModelComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/MeshComponent.java similarity index 90% rename from src/ve/ucv/ciens/ccg/nxtar/components/ModelComponent.java rename to src/ve/ucv/ciens/ccg/nxtar/components/MeshComponent.java index e3e6208..b96db52 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/components/ModelComponent.java +++ b/src/ve/ucv/ciens/ccg/nxtar/components/MeshComponent.java @@ -18,10 +18,10 @@ package ve.ucv.ciens.ccg.nxtar.components; import com.artemis.Component; import com.badlogic.gdx.graphics.Mesh; -public class ModelComponent extends Component { +public class MeshComponent extends Component { public Mesh model; - public ModelComponent(Mesh model){ + public MeshComponent(Mesh model){ this.model = model; } } 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/TestGameEntityCreator.java b/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java index 7a593f7..9b069a4 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java +++ b/src/ve/ucv/ciens/ccg/nxtar/entities/TestGameEntityCreator.java @@ -15,8 +15,8 @@ */ package ve.ucv.ciens.ccg.nxtar.entities; -import ve.ucv.ciens.ccg.nxtar.components.ModelComponent; 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; @@ -30,7 +30,7 @@ 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.Quaternion; +import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Vector3; public class TestGameEntityCreator extends EntityCreatorBase { @@ -45,6 +45,7 @@ public class TestGameEntityCreator extends EntityCreatorBase { @Override public void createAllEntities() { + Matrix3 identity = new Matrix3(); Entity sphere; Entity cube; Entity capsule1; @@ -52,6 +53,8 @@ public class TestGameEntityCreator extends EntityCreatorBase { 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(); @@ -84,23 +87,23 @@ public class TestGameEntityCreator extends EntityCreatorBase { // 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))); - sphere.addComponent(new ModelComponent(sphereMesh)); + 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), new Quaternion(new Vector3(1.0f, 1.0f, 0.0f), 0.0f), new Vector3(1.0f, 1.0f, 1.0f))); - cube.addComponent(new ModelComponent(cubeMesh)); + 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), new Quaternion(new Vector3(1.0f, 0.0f, 0.0f), 0.0f), new Vector3(1.5f, 1.0f, 1.0f))); - capsule1.addComponent(new ModelComponent(capsuleMesh)); + 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), new Quaternion(new Vector3(0.0f, 1.0f, 0.0f), 0.0f), new Vector3(1.0f, 1.5f, 1.0f))); - capsule2.addComponent(new ModelComponent(capsuleMesh)); + 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. diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/OSFunctionalityProvider.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/AndroidFunctionalityWrapper.java similarity index 94% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/OSFunctionalityProvider.java rename to src/ve/ucv/ciens/ccg/nxtar/interfaces/AndroidFunctionalityWrapper.java index 76cd6aa..d233374 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/OSFunctionalityProvider.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/AndroidFunctionalityWrapper.java @@ -15,7 +15,7 @@ */ package ve.ucv.ciens.ccg.nxtar.interfaces; -public interface OSFunctionalityProvider{ +public interface AndroidFunctionalityWrapper{ public void showShortToast(String msg); public void showLongToast(String msg); public void enableMulticast(); diff --git a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java similarity index 69% rename from src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java rename to src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java index e3b6c54..9d75780 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/CVProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java @@ -15,21 +15,25 @@ */ package ve.ucv.ciens.ccg.nxtar.interfaces; -public interface CVProcessor{ - public class CVMarkerData{ +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector3; + +public interface ImageProcessor{ + public class MarkerData{ public byte[] outFrame; public int[] markerCodes; - // TODO: Add marker location data. + public Vector3[] translationVectors; + public Matrix3[] rotationMatrices; } - public class CVCalibrationData{ + public class CalibrationData{ public byte[] outFrame; public float[] calibrationPoints; } - public CVMarkerData findMarkersInFrame(byte[] frame); - public CVCalibrationData findCalibrationPattern(byte[] frame); + public MarkerData findMarkersInFrame(byte[] frame); + public CalibrationData findCalibrationPattern(byte[] frame); public void calibrateCamera(float[][] calibrationSamples, byte[] frame); public byte[] undistortFrame(byte[] frame); - public boolean cameraIsCalibrated(); + public boolean isCameraCalibrated(); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index 8927df6..24a2327 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -19,7 +19,7 @@ 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.CVProcessor.CVCalibrationData; +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; @@ -210,22 +210,22 @@ public class CameraCalibrationState extends BaseState{ frame = frameMonitor.getCurrentFrame(); // Apply the undistortion method if the camera has been calibrated already. - if(core.cvProc.cameraIsCalibrated()){ + if(core.cvProc.isCameraCalibrated()){ frame = core.cvProc.undistortFrame(frame); } // Find the calibration points in the video frame. - CVCalibrationData data = core.cvProc.findCalibrationPattern(frame); + CalibrationData data = core.cvProc.findCalibrationPattern(frame); // Disable the sampling button if the calibration pattern was not found. - if(data.calibrationPoints != null && !core.cvProc.cameraIsCalibrated()){ + 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.cameraIsCalibrated() && data.calibrationPoints != null){ + if(takeSample && !core.cvProc.isCameraCalibrated() && data.calibrationPoints != null){ // Disable sample taking. takeSample = false; Gdx.app.log(TAG, CLASS_NAME + ".render(): Sample taken."); diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 0017dff..286469c 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -22,10 +22,12 @@ 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.TestGameEntityCreator; import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; -import ve.ucv.ciens.ccg.nxtar.interfaces.CVProcessor.CVMarkerData; +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.RenderingSystem; +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; @@ -173,7 +175,9 @@ public class InGameState extends BaseState{ entityCreator.setWorld(gameWorld); entityCreator.createAllEntities(); - gameWorld.setSystem(new RenderingSystem(), true); + gameWorld.setSystem(new MarkerPositioningSystem()); + gameWorld.setSystem(new MarkerRenderingSystem(), true); + gameWorld.setSystem(new ObjectRenderingSystem(), true); gameWorld.initialize(); } @@ -186,13 +190,9 @@ public class InGameState extends BaseState{ public void render(float delta){ int w, h; byte[] frame; - CVMarkerData data; + MarkerData data; TextureRegion region; - // Update the game state. - gameWorld.setDelta(Gdx.graphics.getDeltaTime() * 1000); - gameWorld.process(); - // Clear the screen. Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); @@ -227,7 +227,7 @@ public class InGameState extends BaseState{ } // Apply the undistortion method if the camera has been calibrated already. - if(core.cvProc.cameraIsCalibrated()){ + if(core.cvProc.isCameraCalibrated()){ frame = core.cvProc.undistortFrame(frame); } @@ -236,6 +236,11 @@ public class InGameState extends BaseState{ // 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); @@ -260,7 +265,9 @@ public class InGameState extends BaseState{ // Render the current state of the game. RenderParameters.setModelViewProjectionMatrix(camera3D.combined); RenderParameters.setEyePosition(camera3D.position); - gameWorld.getSystem(RenderingSystem.class).process(); + 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(); @@ -325,6 +332,8 @@ public class InGameState extends BaseState{ headC.draw(core.batch); }core.batch.end(); } + + data = null; } @Override 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..3f8a561 --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java @@ -0,0 +1,77 @@ +/* + * 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]); + } + }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..a16880d --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java @@ -0,0 +1,108 @@ +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.set(geometry.rotation); + scalingMatrix.setToScaling(geometry.scaling); + combinedTransformationMatrix.idt().mul(scalingMatrix).mul(rotationMatrix).mul(translationMatrix); + 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(); + } + }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/RenderingSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java similarity index 59% rename from src/ve/ucv/ciens/ccg/nxtar/systems/RenderingSystem.java rename to src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java index 28b48ff..8c631b8 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/RenderingSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java @@ -16,7 +16,8 @@ package ve.ucv.ciens.ccg.nxtar.systems; import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent; -import ve.ucv.ciens.ccg.nxtar.components.ModelComponent; +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; @@ -31,42 +32,73 @@ import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; -public class RenderingSystem extends EntityProcessingSystem { +/** + *

    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; + @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 RenderingSystem() { - super(Aspect.getAspectForAll(GeometryComponent.class, ShaderComponent.class, ModelComponent.class)); + public ObjectRenderingSystem() { + super(Aspect.getAspectForAll(GeometryComponent.class, ShaderComponent.class, MeshComponent.class).exclude(MarkerCodeComponent.class)); - RenderParameters.setLightSource1(new LightSource(new Vector3(2.0f, 2.0f, 4.0f), new Color(0.0f, 0.1f, 0.2f, 1.0f), new Color(1.0f, 1.0f, 1.0f, 1.0f), new Color(1.0f, 0.8f, 0.0f, 1.0f), 50.0f)); + 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().setToRotation(1.0f, 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; - ModelComponent modelComponent; + MeshComponent meshComponent; // Get the necessary components. geometryComponent = geometryMapper.get(e); - modelComponent = modelMapper.get(e); + meshComponent = modelMapper.get(e); shaderComponent = shaderMapper.get(e); // Calculate the geometric transformation for this entity. translationMatrix.setToTranslation(geometryComponent.position); - rotationMatrix.rotate(geometryComponent.rotation); + rotationMatrix.set(geometryComponent.rotation); scalingMatrix.setToScaling(geometryComponent.scaling); combinedTransformationMatrix.idt().mul(scalingMatrix).mul(rotationMatrix).mul(translationMatrix); @@ -76,7 +108,7 @@ public class RenderingSystem extends EntityProcessingSystem { // Render this entity. shaderComponent.shader.getShaderProgram().begin();{ shaderComponent.shader.setUniforms(); - modelComponent.model.render(shaderComponent.shader.getShaderProgram(), GL20.GL_TRIANGLES); + 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 ed0090a..8d3c2c6 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java +++ b/src/ve/ucv/ciens/ccg/nxtar/utils/ProjectConstants.java @@ -36,6 +36,7 @@ public abstract class ProjectConstants{ public static final int MENU_BUTTON_FONT_SIZE; 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; From a9fa76cb680d7d7acf64e39c73cbabc6fc0762e0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 May 2014 16:56:31 -0430 Subject: [PATCH 18/19] Markers rendered almost sucessfully. --- .../entities/MarkerTestEntityCreator.java | 93 +++++++++++++++++++ .../nxtar/network/VideoStreamingThread.java | 15 ++- .../nxtar/states/CameraCalibrationState.java | 7 +- .../ciens/ccg/nxtar/states/InGameState.java | 17 ++-- .../nxtar/systems/MarkerRenderingSystem.java | 45 +++++++-- .../nxtar/systems/ObjectRenderingSystem.java | 2 +- 6 files changed, 149 insertions(+), 30 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/entities/MarkerTestEntityCreator.java 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/network/VideoStreamingThread.java b/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java index 629ad22..ac2eb60 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java +++ b/src/ve/ucv/ciens/ccg/nxtar/network/VideoStreamingThread.java @@ -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/CameraCalibrationState.java b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java index 24a2327..b27b0f8 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/CameraCalibrationState.java @@ -210,9 +210,9 @@ public class CameraCalibrationState extends BaseState{ frame = frameMonitor.getCurrentFrame(); // Apply the undistortion method if the camera has been calibrated already. - if(core.cvProc.isCameraCalibrated()){ + /*if(core.cvProc.isCameraCalibrated()){ frame = core.cvProc.undistortFrame(frame); - } + }*/ // Find the calibration points in the video frame. CalibrationData data = core.cvProc.findCalibrationPattern(frame); @@ -248,8 +248,9 @@ public class CameraCalibrationState extends BaseState{ if(lastSampleTaken == ProjectConstants.CALIBRATION_SAMPLES){ Gdx.app.log(TAG, CLASS_NAME + "render(): Last sample taken."); - core.toast("Calibrating camera", false); core.cvProc.calibrateCamera(calibrationSamples, frame); + msg = "Camera successfully calibrated"; + core.toast(msg, true); } } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 286469c..9ed814a 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -20,7 +20,7 @@ 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.TestGameEntityCreator; +import ve.ucv.ciens.ccg.nxtar.entities.MarkerTestEntityCreator; 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; @@ -171,9 +171,8 @@ public class InGameState extends BaseState{ // Set up the game world. gameWorld = new World(); - entityCreator = new TestGameEntityCreator(); + entityCreator = new MarkerTestEntityCreator(); entityCreator.setWorld(gameWorld); - entityCreator.createAllEntities(); gameWorld.setSystem(new MarkerPositioningSystem()); gameWorld.setSystem(new MarkerRenderingSystem(), true); @@ -215,21 +214,21 @@ public class InGameState extends BaseState{ // Create the 3D perspective camera and the frame buffer object if they don't exist. if(camera3D == null && frameBuffer == null){ - frameBuffer = new FrameBuffer(Format.RGBA4444, w, h, true); + frameBuffer = new FrameBuffer(Format.RGBA8888, w, h, true); frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); camera3D = new PerspectiveCamera(67, w, h); - camera3D.translate(0.0f, 0.0f, 2.0f); + camera3D.translate(0.0f, 0.0f, 0.0f); camera3D.near = 0.01f; camera3D.far = 100.0f; - camera3D.lookAt(0.0f, 0.0f, 0.0f); + camera3D.lookAt(0.0f, 0.0f, -1.0f); camera3D.update(); } // Apply the undistortion method if the camera has been calibrated already. - if(core.cvProc.isCameraCalibrated()){ + /*if(core.cvProc.isCameraCalibrated()){ frame = core.cvProc.undistortFrame(frame); - } + }*/ // Attempt to find the markers in the current video frame. data = core.cvProc.findMarkersInFrame(frame); @@ -258,11 +257,11 @@ public class InGameState extends BaseState{ // Set the 3D frame buffer for rendering. frameBuffer.begin();{ + Gdx.gl.glDisable(GL20.GL_CULL_FACE); Gdx.gl.glEnable(GL20.GL_DEPTH_TEST); Gdx.gl.glClearColor(1, 1, 1, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); - // Render the current state of the game. RenderParameters.setModelViewProjectionMatrix(camera3D.combined); RenderParameters.setEyePosition(camera3D.position); gameWorld.getSystem(MarkerRenderingSystem.class).setMarkerData(data); diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java index a16880d..2bcf671 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java @@ -66,18 +66,18 @@ public class MarkerRenderingSystem extends EntityProcessingSystem { @Override protected void process(Entity e) { MarkerCodeComponent marker; - GeometryComponent geometry; - ShaderComponent shaderComp; - MeshComponent meshComp; + 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); + marker = markerMapper.get(e); + geometry = geometryMapper.get(e); shaderComp = shaderMapper.get(e); - meshComp = meshMapper.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++){ @@ -86,9 +86,36 @@ public class MarkerRenderingSystem extends EntityProcessingSystem { Gdx.app.log(TAG, CLASS_NAME + ".process(): Rendering marker code " + Integer.toString(markers.markerCodes[i]) + "."); // Set the geometric transformations. translationMatrix.setToTranslation(geometry.position); - rotationMatrix.set(geometry.rotation); + + Gdx.app.log(TAG, CLASS_NAME + ".process(): TRANSLATION:"); + Gdx.app.log(TAG, CLASS_NAME + ".process(): (" + Float.toString(geometry.position.x) + ", " + Float.toString(geometry.position.y) + ", " + Float.toString(geometry.position.z) + ")"); + + 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; + //rotationMatrix.idt(); + + Gdx.app.log(TAG, CLASS_NAME + ".process(): ROTATION:"); + Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[0]) + ", " + Float.toString(rotationMatrix.val[4]) + ", " + Float.toString(rotationMatrix.val[8]) + ", " + Float.toString(rotationMatrix.val[12]) + "|"); + Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[1]) + ", " + Float.toString(rotationMatrix.val[5]) + ", " + Float.toString(rotationMatrix.val[9]) + ", " + Float.toString(rotationMatrix.val[13]) + "|"); + Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[2]) + ", " + Float.toString(rotationMatrix.val[6]) + ", " + Float.toString(rotationMatrix.val[10]) + ", " + Float.toString(rotationMatrix.val[14]) + "|"); + Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[3]) + ", " + Float.toString(rotationMatrix.val[7]) + ", " + Float.toString(rotationMatrix.val[11]) + ", " + Float.toString(rotationMatrix.val[15]) + "|"); + scalingMatrix.setToScaling(geometry.scaling); - combinedTransformationMatrix.idt().mul(scalingMatrix).mul(rotationMatrix).mul(translationMatrix); + combinedTransformationMatrix.idt().mul(translationMatrix).mul(rotationMatrix).mul(scalingMatrix); RenderParameters.setTransformationMatrix(combinedTransformationMatrix); // Render the marker; @@ -101,7 +128,7 @@ public class MarkerRenderingSystem extends EntityProcessingSystem { 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 index 8c631b8..6d0b9d3 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/ObjectRenderingSystem.java @@ -100,7 +100,7 @@ public class ObjectRenderingSystem extends EntityProcessingSystem { translationMatrix.setToTranslation(geometryComponent.position); rotationMatrix.set(geometryComponent.rotation); scalingMatrix.setToScaling(geometryComponent.scaling); - combinedTransformationMatrix.idt().mul(scalingMatrix).mul(rotationMatrix).mul(translationMatrix); + combinedTransformationMatrix.idt().mul(translationMatrix).mul(rotationMatrix).mul(scalingMatrix); // Set up the global rendering parameters for this frame. RenderParameters.setTransformationMatrix(combinedTransformationMatrix); From 87295031dc8c973906964aec12bb9485d51654c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 May 2014 12:10:14 -0430 Subject: [PATCH 19/19] Rendering of objects on top of markers is complete. --- .../graphics/CustomPerspectiveCamera.java | 48 ++++++ .../ccg/nxtar/interfaces/ImageProcessor.java | 47 ++++++ .../ciens/ccg/nxtar/states/InGameState.java | 144 +++++++++++------- .../systems/MarkerPositioningSystem.java | 1 + .../nxtar/systems/MarkerRenderingSystem.java | 12 +- 5 files changed, 189 insertions(+), 63 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/graphics/CustomPerspectiveCamera.java 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/interfaces/ImageProcessor.java b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java index 9d75780..a2effea 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java +++ b/src/ve/ucv/ciens/ccg/nxtar/interfaces/ImageProcessor.java @@ -15,6 +15,8 @@ */ 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; @@ -31,9 +33,54 @@ public interface ImageProcessor{ 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/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index 9ed814a..81a0073 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -21,6 +21,7 @@ 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; @@ -37,7 +38,6 @@ 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.PerspectiveCamera; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; @@ -47,57 +47,63 @@ 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 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; + private float uScaling[]; + protected Sprite background; + private Texture backgroundTexture; + private ShaderProgram backgroundShader; // 3D rendering fields. - private FrameBuffer frameBuffer; - private Sprite frameBufferSprite; + private Matrix4 projectionMatrix; + private FrameBuffer frameBuffer; + private Sprite frameBufferSprite; // Game objects. - private World gameWorld; - private EntityCreatorBase entityCreator; + private World gameWorld; + private EntityCreatorBase entityCreator; // Cameras. - private OrthographicCamera camera; - private OrthographicCamera pixelPerfectCamera; - private PerspectiveCamera camera3D; + private OrthographicCamera unitaryOrthoCamera; + private OrthographicCamera pixelPerfectOrthoCamera; + private CustomPerspectiveCamera perspectiveCamera; // Video stream graphics. - private Texture videoFrameTexture; - private Sprite renderableVideoFrame; - private Pixmap videoFrame; + 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; + 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; + private boolean[] motorButtonsTouched; + private int[] motorButtonsPointers; + private boolean[] motorGamepadButtonPressed; // Monitors. - private VideoFrameMonitor frameMonitor; - private MotorEventQueue queue; + private VideoFrameMonitor frameMonitor; + private MotorEventQueue queue; public InGameState(final NxtARCore core){ this.core = core; @@ -108,8 +114,8 @@ public class InGameState extends BaseState{ 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()); + pixelPerfectOrthoCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + unitaryOrthoCamera = new OrthographicCamera(1.0f, Gdx.graphics.getHeight() / Gdx.graphics.getWidth()); if(!Ouya.runningOnOuya) setUpButtons(); @@ -165,8 +171,9 @@ public class InGameState extends BaseState{ uScaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f; // Set up the 3D rendering. + projectionMatrix = new Matrix4().idt(); frameBuffer = null; - camera3D = null; + perspectiveCamera = null; frameBufferSprite = null; // Set up the game world. @@ -177,7 +184,6 @@ public class InGameState extends BaseState{ gameWorld.setSystem(new MarkerPositioningSystem()); gameWorld.setSystem(new MarkerRenderingSystem(), true); gameWorld.setSystem(new ObjectRenderingSystem(), true); - gameWorld.initialize(); } @@ -191,13 +197,14 @@ public class InGameState extends BaseState{ 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(pixelPerfectCamera.combined); + core.batch.setProjectionMatrix(pixelPerfectOrthoCamera.combined); core.batch.begin();{ if(backgroundShader != null){ core.batch.setShader(backgroundShader); @@ -213,16 +220,16 @@ public class InGameState extends BaseState{ h = frameMonitor.getFrameDimensions().getHeight(); // Create the 3D perspective camera and the frame buffer object if they don't exist. - if(camera3D == null && frameBuffer == null){ + if(perspectiveCamera == null && frameBuffer == null){ frameBuffer = new FrameBuffer(Format.RGBA8888, w, h, true); frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); - camera3D = new PerspectiveCamera(67, w, h); - camera3D.translate(0.0f, 0.0f, 0.0f); - camera3D.near = 0.01f; - camera3D.far = 100.0f; - camera3D.lookAt(0.0f, 0.0f, -1.0f); - camera3D.update(); + 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. @@ -257,13 +264,44 @@ public class InGameState extends BaseState{ // 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(1, 1, 1, 0); + Gdx.gl.glClearColor(0, 0, 0, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); - RenderParameters.setModelViewProjectionMatrix(camera3D.combined); - RenderParameters.setEyePosition(camera3D.position); + // 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(); @@ -273,7 +311,7 @@ public class InGameState extends BaseState{ // Set the frame buffer object texture to a renderable sprite. region = new TextureRegion(frameBuffer.getColorBufferTexture(), 0, 0, frameBuffer.getWidth(), frameBuffer.getHeight()); - region.flip(true, true); + region.flip(false, true); if(frameBufferSprite == null) frameBufferSprite = new Sprite(region); else @@ -303,9 +341,9 @@ public class InGameState extends BaseState{ // Set the correct camera for the device. if(!Ouya.runningOnOuya){ - core.batch.setProjectionMatrix(camera.combined); + core.batch.setProjectionMatrix(unitaryOrthoCamera.combined); }else{ - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.setProjectionMatrix(pixelPerfectOrthoCamera.combined); } // Render the video frame and the frame buffer. @@ -320,7 +358,7 @@ public class InGameState extends BaseState{ // Render the interface buttons. if(!Ouya.runningOnOuya){ - core.batch.setProjectionMatrix(pixelPerfectCamera.combined); + core.batch.setProjectionMatrix(pixelPerfectOrthoCamera.combined); core.batch.begin();{ motorA.draw(core.batch); motorB.draw(core.batch); @@ -427,7 +465,7 @@ public class InGameState extends BaseState{ if(!Ouya.runningOnOuya){ win2world.set(screenX, screenY, 0.0f); - camera.unproject(win2world); + 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)); @@ -527,7 +565,7 @@ public class InGameState extends BaseState{ if(!Ouya.runningOnOuya){ win2world.set(screenX, screenY, 0.0f); - camera.unproject(win2world); + 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)); @@ -638,7 +676,7 @@ public class InGameState extends BaseState{ if(!Ouya.runningOnOuya){ win2world.set(screenX, screenY, 0.0f); - camera.unproject(win2world); + unitaryOrthoCamera.unproject(win2world); touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight()); if(pointer == motorButtonsPointers[0] && !motorA.getBoundingRectangle().contains(touchPointWorldCoords)){ diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java index 3f8a561..f544007 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerPositioningSystem.java @@ -66,6 +66,7 @@ public class MarkerPositioningSystem extends EntityProcessingSystem { 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) + "."); diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java index 2bcf671..2f72ac8 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/MarkerRenderingSystem.java @@ -87,9 +87,6 @@ public class MarkerRenderingSystem extends EntityProcessingSystem { // Set the geometric transformations. translationMatrix.setToTranslation(geometry.position); - Gdx.app.log(TAG, CLASS_NAME + ".process(): TRANSLATION:"); - Gdx.app.log(TAG, CLASS_NAME + ".process(): (" + Float.toString(geometry.position.x) + ", " + Float.toString(geometry.position.y) + ", " + Float.toString(geometry.position.z) + ")"); - rotationMatrix.val[0] = geometry.rotation.val[0]; rotationMatrix.val[1] = geometry.rotation.val[1]; rotationMatrix.val[2] = geometry.rotation.val[2]; @@ -106,13 +103,6 @@ public class MarkerRenderingSystem extends EntityProcessingSystem { rotationMatrix.val[13] = 0; rotationMatrix.val[14] = 0; rotationMatrix.val[15] = 1; - //rotationMatrix.idt(); - - Gdx.app.log(TAG, CLASS_NAME + ".process(): ROTATION:"); - Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[0]) + ", " + Float.toString(rotationMatrix.val[4]) + ", " + Float.toString(rotationMatrix.val[8]) + ", " + Float.toString(rotationMatrix.val[12]) + "|"); - Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[1]) + ", " + Float.toString(rotationMatrix.val[5]) + ", " + Float.toString(rotationMatrix.val[9]) + ", " + Float.toString(rotationMatrix.val[13]) + "|"); - Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[2]) + ", " + Float.toString(rotationMatrix.val[6]) + ", " + Float.toString(rotationMatrix.val[10]) + ", " + Float.toString(rotationMatrix.val[14]) + "|"); - Gdx.app.log(TAG, CLASS_NAME + ".process(): |" + Float.toString(rotationMatrix.val[3]) + ", " + Float.toString(rotationMatrix.val[7]) + ", " + Float.toString(rotationMatrix.val[11]) + ", " + Float.toString(rotationMatrix.val[15]) + "|"); scalingMatrix.setToScaling(geometry.scaling); combinedTransformationMatrix.idt().mul(translationMatrix).mul(rotationMatrix).mul(scalingMatrix); @@ -123,6 +113,8 @@ public class MarkerRenderingSystem extends EntityProcessingSystem { 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) + ".");