// Copyright 2008 Google Inc. // // 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 com.google.android.stardroid.renderer; import com.google.android.stardroid.renderer.util.UpdateClosure; import com.google.android.stardroid.source.ImageSource; import com.google.android.stardroid.source.LineSource; import com.google.android.stardroid.source.PointSource; import com.google.android.stardroid.source.TextSource; import com.google.android.stardroid.units.GeocentricCoordinates; import android.os.ConditionVariable; import android.util.Log; import java.util.EnumSet; import java.util.List; public abstract class RendererControllerBase { /** * Base class for all renderer managers. */ public static abstract class RenderManager<E> { protected RendererObjectManager mManager; private RenderManager(RendererObjectManager mgr) { mManager = mgr; } public void queueEnabled(final boolean enable, RendererControllerBase controller) { final String msg = (enable ? "Enabling" : "Disabling") + " manager " + mManager; controller.queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mManager.enable(enable); }}); } public void queueMaxFieldOfView(final float fov, RendererControllerBase controller) { final String msg = "Setting manager max field of view: " + fov; controller.queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mManager.setMaxRadiusOfView(fov); }}); } public abstract void queueObjects( final List<E> objects, final EnumSet<RendererObjectManager.UpdateType> updateType, RendererControllerBase controller); } // TODO(brent): collapse these into a single class? /** * Class for managing a set of point objects. */ public static class PointManager extends RenderManager<PointSource> { private PointManager(PointObjectManager manager) { super(manager); } @Override public void queueObjects(final List<PointSource> points, final EnumSet<RendererObjectManager.UpdateType> updateType, RendererControllerBase controller) { String msg = "Setting point objects"; controller.queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { ((PointObjectManager) mManager).updateObjects(points, updateType); }}); } } /** * Class for managing a set of polyline objects. */ public static class LineManager extends RenderManager<LineSource> { private LineManager(PolyLineObjectManager manager) { super(manager); } @Override public void queueObjects(final List<LineSource> lines, final EnumSet<RendererObjectManager.UpdateType> updateType, RendererControllerBase controller) { String msg = "Setting line objects"; controller.queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { ((PolyLineObjectManager) mManager).updateObjects(lines, updateType); }}); } } /** * Class for managing a set of text label objects. */ public static class LabelManager extends RenderManager<TextSource> { private LabelManager(LabelObjectManager manager) { super(manager); } @Override public void queueObjects(final List<TextSource> labels, final EnumSet<RendererObjectManager.UpdateType> updateType, RendererControllerBase controller) { String msg = "Setting label objects"; controller.queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { ((LabelObjectManager) mManager).updateObjects(labels, updateType); }}); } } /** * Class for managing a set of image objects. */ public static class ImageManager extends RenderManager<ImageSource> { private ImageManager(ImageObjectManager manager) { super(manager); } @Override public void queueObjects(final List<ImageSource> images, final EnumSet<RendererObjectManager.UpdateType> updateType, RendererControllerBase controller) { String msg = "Setting image objects"; controller.queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { ((ImageObjectManager) mManager).updateObjects(images, updateType); }}); } } protected static interface EventQueuer { void queueEvent(Runnable r); } public RendererControllerBase(SkyRenderer renderer) { mRenderer = renderer; } // Used only to allow logging different types of events. The distinction // can be somewhat ambiguous at times, so when in doubt, I tend to use // "view" for those things that change all the time (like the direction // the user is looking) and "data" for those that change less often // (like whether a layer is visible or not). protected enum CommandType { View, // The command only changes the user's view. Data, // The command changes what is actually rendered. Synchronization // The command relates to synchronization. } private static final boolean SHOULD_LOG_QUEUE = false; private static final boolean SHOULD_LOG_RUN = false; private static final boolean SHOULD_LOG_FINISH = false; protected final SkyRenderer mRenderer; public PointManager createPointManager(int layer) { PointManager manager = new PointManager(mRenderer.createPointManager(layer)); queueAddManager(manager); return manager; } public LineManager createLineManager(int layer) { LineManager manager = new LineManager(mRenderer.createPolyLineManager(layer)); queueAddManager(manager); return manager; } public LabelManager createLabelManager(int layer) { LabelManager manager = new LabelManager(mRenderer.createLabelManager(layer)); queueAddManager(manager); return manager; } public ImageManager createImageManager(int layer) { ImageManager manager = new ImageManager(mRenderer.createImageManager(layer)); queueAddManager(manager); return manager; } public void queueNightVisionMode(final boolean enable) { final String msg = "Setting night vision mode: " + enable; queueRunnable(msg, CommandType.View, new Runnable() { public void run() { mRenderer.setNightVisionMode(enable); }}); } public void queueFieldOfView(final float fov) { final String msg = "Setting fov: " + fov; queueRunnable(msg, CommandType.View, new Runnable() { public void run() { mRenderer.setRadiusOfView(fov); }}); } public void queueTextAngle(final float angleInRadians) { final String msg = "Setting text angle: " + angleInRadians; queueRunnable(msg, CommandType.View, new Runnable() { public void run() { mRenderer.setTextAngle(angleInRadians); }}); } public void queueViewerUpDirection(final GeocentricCoordinates up) { final String msg = "Setting up direction: " + up; queueRunnable(msg, CommandType.View, new Runnable() { public void run() { mRenderer.setViewerUpDirection(up); }}); } public void queueSetViewOrientation(final float dirX, final float dirY, final float dirZ, final float upX, final float upY, final float upZ) { final String msg = "Setting view orientation"; queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mRenderer.setViewOrientation(dirX, dirY, dirZ, upX, upY, upZ); }}); } public void queueEnableSkyGradient(final GeocentricCoordinates sunPosition) { final String msg = "Enabling sky gradient at: " + sunPosition; queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mRenderer.enableSkyGradient(sunPosition); }}); } public void queueDisableSkyGradient() { final String msg = "Disabling sky gradient"; queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mRenderer.disableSkyGradient(); }}); } public void queueEnableSearchOverlay(final GeocentricCoordinates target, final String targetName) { final String msg = "Enabling search overlay"; queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mRenderer.enableSearchOverlay(target, targetName); }}); } public void queueDisableSearchOverlay() { final String msg = "Disabling search overlay"; queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mRenderer.disableSearchOverlay(); }}); } public void addUpdateClosure(final UpdateClosure runnable) { final String msg = "Setting update callback"; queueRunnable(msg, CommandType.Data, new Runnable() { @Override public void run() { mRenderer.addUpdateClosure(runnable); } }); } public void removeUpdateCallback(final UpdateClosure update) { final String msg = "Removing update callback"; queueRunnable(msg, CommandType.Data, new Runnable() { @Override public void run() { mRenderer.removeUpdateCallback(update); } }); } /** * Must be called once to register an object manager to the renderer. * @param rom */ public<E> void queueAddManager(final RenderManager<E> rom) { String msg = "Adding manager: " + rom; queueRunnable(msg, CommandType.Data, new Runnable() { public void run() { mRenderer.addObjectManager(rom.mManager); }}); } public void waitUntilFinished() { final ConditionVariable cv = new ConditionVariable(); String msg = "Waiting until operations have finished"; queueRunnable(msg, CommandType.Synchronization, new Runnable() { public void run() { cv.open(); }}); cv.block(); } abstract protected EventQueuer getQueuer(); protected void queueRunnable(String msg, final CommandType type, final Runnable r) { EventQueuer queuer = getQueuer(); String fullMessage = toString() + " - " + msg; RendererControllerBase.queueRunnable(queuer, fullMessage, type, r); } protected static void queueRunnable(EventQueuer queuer, final String msg, final CommandType type, final Runnable r) { // If we're supposed to log something, then wrap the runnable with the // appropriate logging statements. Otherwise, just queue it. if (SHOULD_LOG_QUEUE || SHOULD_LOG_RUN || SHOULD_LOG_FINISH) { logQueue(msg, type); queuer.queueEvent(new Runnable() { public void run() { logRun(msg, type); r.run(); logFinish(msg, type); }}); } else { queuer.queueEvent(r); } } protected static void logQueue(String description, CommandType type) { if (SHOULD_LOG_QUEUE) { Log.d("RendererController-" + type.toString(), "Queuing: " + description); } } protected static void logRun(String description, CommandType type) { if (SHOULD_LOG_RUN) { Log.d("RendererController-" + type.toString(), "Running: " + description); } } protected static void logFinish(String description, CommandType type) { if (SHOULD_LOG_FINISH) { Log.d("RendererController-" + type.toString(), "Finished: " + description); } } }