/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine is distributed in the hope that it will *
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.game;
import totalcross.io.IOException;
import totalcross.ui.*;
import totalcross.ui.event.*;
import totalcross.ui.font.Font;
import totalcross.ui.gfx.GfxSurface;
import totalcross.ui.gfx.Graphics;
import totalcross.ui.image.Image;
import totalcross.ui.image.ImageException;
/**
* Game MainWindow provided by the GameEngine. Note: you can't access this class
* directly. You must use the methods provided by the GameEngine instead.
*
* @author Frank Diebolt
* @author Guilherme Campos Hazan
* @version 1.1
*/
class GameEngineMainWindow extends MainWindow
{
/**
* TotalCross game API version.
*/
private static GameEngine engine;
private Options options;
private HighScores hscores;
private boolean isRunning;
private Graphics graf;
private TimerEvent gameTimer;
private boolean flicker;
private Control gameTimerControl = new Control()
{
public final void onEvent(Event e)
{
if (isRunning)
refresh();
if (!isRunning)
{
removeTimer(gameTimer);
gameTimer = null;
_doPaint();
// Notifies the game run mode quit by calling onGameStop().
engine.onGameStop();
Window.isHighlighting = true; // guich@550_30: support pen less devices
}
}
};
/** Do nothing. All attributes must be set by the Game implementor */
protected GameEngineMainWindow()
{
paintBackground = false;
}
/** Called just after the GameEngine is constructed */
protected void setGameEngine(GameEngine engine)
{
GameEngineMainWindow.engine = engine;
}
/**
* Returns a Graphics instance for the drawing surface. A new instance is
* always returned
*/
static final Graphics getEngineGraphics()
{
if (engine == null)
throw new GameEngineException("GameEngine not initialized");
return engine.getGraphics();
}
/** Returns the drawing surface */
static final GfxSurface getSurface()
{
if (engine == null)
throw new GameEngineException("GameEngine not initialized");
return (GfxSurface) engine;
}
/**
* Replace initUI() handling to initialize the engine.<br>
* <B>Could not be overloaded.</B> Notifies onGameInit().<br>
*/
public final void initUI()
{
transparentBackground = true; // guich@tc122_54
flicker = engine.gameDoClearScreen;
if (!engine.gameHasUI) // can greately improve drawing performance?
graf = getGraphics();
engine.gameIsRunning = isRunning = false;
engine.onGameInit();
}
/**
* Replace onExit() handling to shutdown the engine.<br>
* <B>Could not be overloaded.</B> Notifies onGameExit().
*/
public final void onExit()
{
engine.onGameExit();
shutdown();
}
/**
* Get a new instance of the game highscores.
*
* @return HighScores.
*/
HighScores getHighScores()
{
if (hscores != null)
return hscores;
if (engine.gameHighscoresSize <= 0)
return null;
try
{
return hscores = new HighScores(engine);
}
catch (IOException e)
{
// e.printStackTrace();
}
return null;
}
/**
* Get a new instance of the game options.
*
* @return Options.
*/
Options getOptions()
{
return options != null ? options : (options = new Options(engine));
}
/**
* Create a new TextRenderer. A TextRenderer performs a fast String display
* with an optional integer value.
*
* @param font
* to display with.
* @param foreColor
* text color, may be null.
* @param text
* to render.
* @param maxDigits
* digits to display.
* @return a new TextRenderer.
* @throws ImageException
* @see TextRenderer TextRenderer for more information
*/
TextRenderer createTextRenderer(Font font, int foreColor, String text, int maxDigits) throws ImageException
{
return new TextRenderer(font, foreColor, backColor, text, maxDigits);
}
/**
* Create a new TextRenderer. A TextRenderer performs a fast String display with an optional integer value.
*
* @param font
* to display with.
* @param foreColor
* text color, may be null.
* @param text
* to render.
* @param maxDigits
* digits to display.
* @param zeroPadding
* pad with leading zeros.
* @return a new TextRenderer.
* @throws ImageException
* @see TextRenderer TextRenderer for more information
*/
TextRenderer createTextRenderer(Font font, int foreColor, String text, int maxDigits, boolean zeroPadding) throws ImageException //fdie@420_27
{
return new TextRenderer(font, foreColor, backColor, text, maxDigits, zeroPadding);
}
/*
* Shutdown the GameEngine and releases its resources.
*/
private final void shutdown()
{
engine.gameIsRunning = isRunning = false;
try
{
if (hscores != null)
hscores.close();
if (options != null)
options.close();
if (gameTimer != null)
removeTimer(gameTimer);
}
catch (totalcross.io.IOException e)
{
}
}
/*
* Stops the game. <br> Arms a timer, because onGameStop() events that may
* start a UI we have to be in the event handling.<br> The game will be
* interrupted at next timer event.
*/
void stop()
{
engine.gameIsRunning = isRunning = false;
if (engine.gameRefreshPeriod <= 0)
gameTimer = super.addTimer(gameTimerControl, 10);
}
/**
* Start the game mainloop. <br>
* NOTE: If the game is time based (arcade game), this function arms the
* mainloop timer which causes scheduled onPaint() calls to let the game
* redraw a new frame.<br>
* For non time based games, you have to call explicitly the refresh()
* function to redraw a frame (on pen events for instance or any other kind
* of events...)
*
* @see #stop
*/
void start()
{
// first let's clean the screen, maybe we can also set the background color
//refresh();
engine.onGameStart();
Window.isHighlighting = false; // guich@550_30: support pen less devices
engine.gameIsRunning = isRunning = true;
if (engine.gameRefreshPeriod > 0)
gameTimer = super.addTimer(gameTimerControl, engine.gameRefreshPeriod);
// start first game display
refresh();
}
/**
* Use an image as background. <br>
* The provided image is scaled if required to the screen size and displayed at each frame refresh. NOTE: the
* "gameHasUI" also have to be set to false to support this feature
*
* @throws ImageException
*/
public Image useBackground(Image bg) throws ImageException //fdie@420_26
{
if (bg != null && (bg.getHeight() != height || bg.getWidth() != width))
bg = bg.getScaledInstance(width, height);
bgSurface = bg;
paintBackground = (bg != null);
return bg;
}
protected Image bgSurface;
private boolean paintBackground;
/**
* Refreshes the screen. If there are UI elements on the screen
* (GameEngine.hasUI = true) calls the slower _doPaint. Otherwise, just
* prepares the buffer and repaint it.
*/
void refresh()
{
if (!engine.gameHasUI)
{
if (flicker && bgSurface == null)
{
graf.backColor = backColor;
graf.fillRect(0, 0, totalcross.sys.Settings.screenWidth, totalcross.sys.Settings.screenHeight);
}
else
if (paintBackground)
{
graf.drawImage(bgSurface, 0, 0); // tc: replaced copyScreen
paintBackground = flicker; // continue background display if "clearscreen" is enabled
}
engine.onPaint(graf);
updateScreen(); // tc100 g0.copyScreen(isurf, 0,0,this.height);
}
else
_doPaint();
}
/**
* Replace onEvent handling to identify and notify some usefull game
* events.<br>
* <B>Could not be overloaded.</B>
*
* @param evt
* event that occurs.
*/
public final void onEvent(Event evt)
{
switch (evt.type)
{
case TimerEvent.TRIGGERED:
engine.onTimer((TimerEvent) evt);
break;
case KeyEvent.KEY_PRESS:
case KeyEvent.SPECIAL_KEY_PRESS:
engine.onKey((KeyEvent) evt);
break;
case PenEvent.PEN_DOWN:
engine.onPenDown((PenEvent) evt);
break;
case PenEvent.PEN_DRAG:
engine.onPenDrag((PenEvent) evt);
break;
case PenEvent.PEN_UP:
engine.onPenUp((PenEvent) evt);
break;
default:
engine.onOtherEvent(evt);
}
}
}