Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

image_viewer.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program 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.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *
 */

// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL

#include "common/scummsys.h"
#include "common/str.h"
#include "common/stream.h"
#include "common/archive.h"
#include "common/events.h"
#include "common/ptr.h"
#include "gui/message.h"
#include "engines/engine.h"
#include "backends/platform/psp/input.h"
#include "backends/platform/psp/display_manager.h"
#include "backends/platform/psp/display_client.h"
#include "backends/platform/psp/image_viewer.h" 
#include "backends/platform/psp/png_loader.h" 
#include "backends/platform/psp/thread.h"

static const char *imageName = "psp_image";
#define PSP_SCREEN_HEIGHT 272
#define PSP_SCREEN_WIDTH 480
 
bool ImageViewer::load(int imageNum) {
      if (_init)
            unload();
            
      // build string
      char number[8];
      sprintf(number, "%d", imageNum);
      Common::String imageNameStr(imageName);   
      Common::String specificImageName = imageNameStr + Common::String(number) + Common::String(".png");
      
      // search for image file
      if (!SearchMan.hasFile(specificImageName)) {
            PSP_ERROR("file %s not found\n", specificImageName.c_str());
            return false;
      }
      
      Common::ScopedPtr<Common::SeekableReadStream> file(SearchMan.createReadStreamForMember(specificImageName));
      
      _buffer = new Buffer();
      _palette = new Palette();
      _renderer = new GuRenderer();
      
      assert(_buffer);
      assert(_palette);
      assert(_renderer);
      
      // Load a PNG into our buffer and palette. Size it by the actual size of the image
      PngLoader image(file, *_buffer, *_palette, Buffer::kSizeBySourceSize);
      
      PngLoader::Status status = image.allocate();    // allocate the buffers for the file
      
      char error[100];
      if (status == PngLoader::BAD_FILE) {
            sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str());
            GUI::TimedMessageDialog dialog(error, 4000);
            dialog.runModal();
            return false;
      } else if (status == PngLoader::OUT_OF_MEMORY) {
            sprintf(error, "Out of memory loading %s. Try making the image smaller", specificImageName.c_str());
            GUI::TimedMessageDialog dialog(error, 4000);
            dialog.runModal();
            return false;
      }
      // try to load the image file
      if (!image.load()) {
            sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str());
            GUI::TimedMessageDialog dialog(error, 4000);
            dialog.runModal();      
            return false;
      }
      
      setConstantRendererOptions();
      setFullScreenImageParams();         // prepare renderer for full screen view
      
      _imageNum = imageNum;               // now we can say we displayed this image
      _init = true;
      
      return true;
}

void ImageViewer::setConstantRendererOptions() {
      _renderer->setBuffer(_buffer);
      _renderer->setPalette(_palette);
      
      _renderer->setAlphaBlending(false);
      _renderer->setColorTest(false);
      _renderer->setUseGlobalScaler(false);
      _renderer->setStretch(true);
      _renderer->setOffsetInBuffer(0, 0);
      _renderer->setDrawWholeBuffer();    
}

void ImageViewer::unload() {
      _init = false;
      delete _buffer;
      delete _palette;
      delete _renderer;
      _buffer = 0;
      _palette = 0;
      _renderer = 0;
}

void ImageViewer::resetOnEngineDone() {
      _imageNum = 0;
}

void ImageViewer::setVisible(bool visible) {
      DEBUG_ENTER_FUNC();
      
      if (_visible == visible)
            return;
                  
      // from here on, we're making the loader visible
      if (visible && g_engine) {    // we can only run the image viewer when there's an engine
            g_engine->pauseEngine(true);
            
            load(_imageNum ? _imageNum : 1);    // load the 1st image or the current
      }

      if (visible && _init) { // we managed to load
            _visible = true;
            setViewerButtons(true);
            
            { // so dialog goes out of scope, destroying all allocations
                  GUI::TimedMessageDialog dialog("Image Viewer", 1000);
                  dialog.runModal();
            }
            
            runLoop();  // only listen to viewer events
      } else {    // we were asked to make invisible or failed to load
            _visible = false;
            unload();
            setViewerButtons(false);
            
            if (g_engine && g_engine->isPaused())
                  g_engine->pauseEngine(false);
      }
      setDirty();
}

// This is the only way we can truly pause the games
// Sad but true.
void ImageViewer::runLoop() {
      while (_visible) {
            Common::Event event;
            PspThread::delayMillis(30);
            _inputHandler->getAllInputs(event);
            _displayManager->renderAll();
      }
}

void ImageViewer::setViewerButtons(bool active) {
      _inputHandler->setImageViewerMode(active);
}     

void ImageViewer::loadNextImage() {
      if (!load(_imageNum+1)) {           // try to load the next image
            if (!load(_imageNum))         // we failed, so reload the current image
                  setVisible(false);            // just hide
      }
      setDirty();
}

void ImageViewer::loadLastImage() {
      if (_imageNum - 1 > 0) {
            if (!load(_imageNum-1))
                  if (!load(_imageNum))
                        setVisible(false);      // we can't even show the old image so hide
      }           
      setDirty();
}

void ImageViewer::setFullScreenImageParams() {
      // we try to fit the image fullscreen at least in one dimension
      uint32 width = _buffer->getSourceWidth();
      uint32 height = _buffer->getSourceHeight();     

      _centerX = PSP_SCREEN_WIDTH / 2.0f;
      _centerY = PSP_SCREEN_HEIGHT / 2.0f;
      
      // see if we fit width wise
      if (PSP_SCREEN_HEIGHT >= (int)((height * PSP_SCREEN_WIDTH) / (float)width)) {
            setZoom(PSP_SCREEN_WIDTH / (float)width); 
      } else {
            setZoom(PSP_SCREEN_HEIGHT / (float)height);
      }
}

void ImageViewer::render() {
      if (_init) {
            assert(_buffer);
            assert(_renderer);

            // move the image slightly. Note that we count on the renderer's timing
            switch (_movement) {
            case EVENT_MOVE_LEFT:
                  moveImageX(-_visibleWidth / 100.0f);
                  break;
            case EVENT_MOVE_UP:
                  moveImageY(-_visibleHeight / 100.0f);
                  break;
            case EVENT_MOVE_RIGHT:
                  moveImageX(_visibleWidth / 100.0f);
                  break;
            case EVENT_MOVE_DOWN:
                  moveImageY(_visibleHeight / 100.0f);
                  break;
            default:
                  break;
            }
            _renderer->render();
      }     
}

void ImageViewer::modifyZoom(bool up) {
      float factor = _zoomFactor;
      if (up) 
            factor += 0.1f;
      else // down
            factor -= 0.1f;
      
      setZoom(factor);  
}

void ImageViewer::setZoom(float value) { 
      if (value <= 0.0f)            // don't want 0 or negative zoom
            return;

      _zoomFactor = value;
      _renderer->setStretchXY(value, value); 
      setOffsetParams();
}

void ImageViewer::moveImageX(float val) {
      float newVal = _centerX + val;
      
      if (newVal - (_visibleWidth / 2) > PSP_SCREEN_WIDTH - 4 || newVal + (_visibleWidth / 2) < 4)  
            return;
      _centerX = newVal;
      setOffsetParams();
}

void ImageViewer::moveImageY(float val) {
      float newVal = _centerY + val;
      
      if (newVal - (_visibleHeight / 2) > PSP_SCREEN_HEIGHT - 4 || newVal + (_visibleHeight / 2) < 4)  
            return;
      _centerY = newVal;
      setOffsetParams();
}

//    Set the renderer with the proper offset on the screen 
//
void ImageViewer::setOffsetParams() {
      _visibleWidth = _zoomFactor * _buffer->getSourceWidth();
      _visibleHeight = _zoomFactor * _buffer->getSourceHeight();        
      
      int offsetX = _centerX - (int)(_visibleWidth * 0.5f);
      int offsetY = _centerY - (int)(_visibleHeight * 0.5f);
      
      _renderer->setOffsetOnScreen(offsetX, offsetY);
      setDirty();
}

//    Handler events coming in from the inputHandler
//
void ImageViewer::handleEvent(uint32 event) {
      DEBUG_ENTER_FUNC();
      
      switch (event) {  
      case EVENT_HIDE:
            setVisible(false);
            break;
      case EVENT_SHOW:
            setVisible(true);
            break;
      case EVENT_ZOOM_IN:
            modifyZoom(true);
            break;
      case EVENT_ZOOM_OUT:
            modifyZoom(false);
            break;
      case EVENT_MOVE_LEFT:
      case EVENT_MOVE_UP:
      case EVENT_MOVE_RIGHT:
      case EVENT_MOVE_DOWN:
      case EVENT_MOVE_STOP:
            _movement = (Event)event;
            break;
      case EVENT_NEXT_IMAGE:
            loadNextImage();
            break;
      case EVENT_LAST_IMAGE:
            loadLastImage();
            break;
      default:
            PSP_ERROR("Unknown event %d\n", event);
            break;
      }
}

Generated by  Doxygen 1.6.0   Back to index