Code Search for Developers
 
 
  

DynamicGraphic.cpp from FreeOrion at Krugle


Show DynamicGraphic.cpp syntax highlighted

/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003 T. Zachary Laine

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1
   of the License, or (at your option) any later version.
   
   This library 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
   Lesser General Public License for more details.
    
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.
    
   Zach Laine
   whatwasthataddress@hotmail.com */

/* This class is based on earlier work with GG by Tony Casale.  Thanks, Tony.*/

#include <GG/DynamicGraphic.h>

#include <GG/GUI.h>
#include <GG/DrawUtil.h>
#include <GG/Texture.h>
#include <GG/WndEditor.h>

#include <boost/assign/list_of.hpp>

#include <cmath>


using namespace GG;

namespace {
    const double DEFAULT_FPS = 15.0;
}

DynamicGraphic::DynamicGraphic() :
    Control(),
    m_margin(0),
    m_frame_width(0),
    m_frame_height(0),
    m_FPS(DEFAULT_FPS),
    m_playing(true),
    m_looping(true),
    m_curr_texture(0),
    m_curr_subtexture(0),
    m_frames(0),
    m_curr_frame(0),
    m_first_frame_time(-1),
    m_last_frame_time(-1),
    m_first_frame_idx(0),
    m_style(GRAPHIC_NONE)
{
}

DynamicGraphic::DynamicGraphic(int x, int y, int w, int h, bool loop, int frame_width, int frame_height, int margin, 
                               const std::vector<boost::shared_ptr<Texture> >& textures, Flags<GraphicStyle> style/* = GRAPHIC_NONE*/, int frames/* = -1*/, 
                               Flags<WndFlag> flags/* = Flags<WndFlags>()*/) :
    Control(x, y, w, h, flags),
    m_margin(margin),
    m_frame_width(frame_width),
    m_frame_height(frame_height),
    m_FPS(DEFAULT_FPS),
    m_playing(true),
    m_looping(loop),
    m_curr_texture(0),
    m_curr_subtexture(0),
    m_frames(0),
    m_curr_frame(0),
    m_first_frame_time(-1),
    m_last_frame_time(-1),
    m_first_frame_idx(0),
    m_style(style)
{
    ValidateStyle();
    SetColor(CLR_WHITE);
    AddFrames(textures, frames);
    m_last_frame_idx = m_frames - 1;
}

int DynamicGraphic::Frames() const       
{
    return m_frames;
}

bool DynamicGraphic::Playing() const
{
    return m_playing;
}

bool DynamicGraphic::Looping() const
{
    return m_looping;
}

double DynamicGraphic::FPS() const
{
    return m_FPS;
}

int DynamicGraphic::FrameIndex() const
{
    return m_curr_frame;
}

int DynamicGraphic::TimeIndex() const
{
    return m_last_frame_time;
}

int DynamicGraphic::StartFrame() const
{
    return m_first_frame_idx;
}

int DynamicGraphic::EndFrame() const
{
    return m_last_frame_idx;
}

int DynamicGraphic::Margin() const
{
    return m_margin;
}

int DynamicGraphic::FrameWidth() const
{
    return m_frame_width;
}

int DynamicGraphic::FrameHeight() const
{
    return m_frame_height;
}

Flags<GraphicStyle> DynamicGraphic::Style() const
{
    return m_style;
}

void DynamicGraphic::Render()
{
    if (0 <= m_curr_texture && m_curr_texture < static_cast<int>(m_textures.size()) &&
        0 <= m_curr_subtexture && m_curr_subtexture < m_textures[m_curr_texture].frames) {
        bool send_stopped_signal = false;
        bool send_end_frame_signal = false;

        // advance frames
        int initial_frame_idx = (0.0 <= m_FPS ? m_first_frame_idx : m_last_frame_idx);
        int final_frame_idx =   (0.0 <= m_FPS ? m_last_frame_idx : m_first_frame_idx);
        if (m_playing) {
            if (m_first_frame_time == -1) {
                m_last_frame_time = m_first_frame_time = GUI::GetGUI()->Ticks();
                if (0.0 != m_FPS) // needed if a start index was set
                    m_first_frame_time = static_cast<int>(m_first_frame_time - 1000.0 / m_FPS * m_curr_frame);
            } else {
                int old_frame = m_curr_frame;
                int curr_time = GUI::GetGUI()->Ticks();
                SetFrameIndex(initial_frame_idx + static_cast<int>((curr_time - m_first_frame_time) / 1000.0 * m_FPS) % (m_last_frame_idx - m_first_frame_idx + 1));

                // determine whether the final frame was passed
                int frames_passed = static_cast<int>((curr_time - m_last_frame_time) / 1000.0 * m_FPS);
                if (m_frames <= frames_passed || (0.0 <= m_FPS ? m_curr_frame < old_frame : m_curr_frame > old_frame)) { // if we passed the final frame
                    send_end_frame_signal = true;
                    if (!m_looping) { // if looping isn't allowed, stop at the last frame
                        m_playing = false;
                        m_first_frame_time = -1;
                        SetFrameIndex(final_frame_idx);
                        send_stopped_signal = true;
                    }
                }
                m_last_frame_time = curr_time;
            }
        }

        // render current frame
        Clr color_to_use = Disabled() ? DisabledColor(Color()) : Color();
        glColor(color_to_use);

        int cols = m_textures[m_curr_texture].texture->DefaultWidth() / (m_frame_width + m_margin);
        int x = (m_curr_subtexture % cols) * (m_frame_width + m_margin) + m_margin;
        int y = (m_curr_subtexture / cols) * (m_frame_height + m_margin) + m_margin;
        SubTexture st(m_textures[m_curr_texture].texture, x, y, x + m_frame_width, y + m_frame_height);

        Pt ul = UpperLeft(), lr = LowerRight();
        Pt window_sz(lr - ul);
        Pt graphic_sz(m_frame_width, m_frame_height);
        Pt pt1, pt2(graphic_sz); // (unscaled) default graphic size
        if (m_style & GRAPHIC_FITGRAPHIC) {
            if (m_style & GRAPHIC_PROPSCALE) {
                double scale_x = window_sz.x / double(graphic_sz.x),
                    scale_y = window_sz.y / double(graphic_sz.y);
                double scale = (scale_x < scale_y) ? scale_x : scale_y;
                pt2.x = int(graphic_sz.x * scale);
                pt2.y = int(graphic_sz.y * scale);
            } else {
                pt2 = window_sz;
            }
        } else if (m_style & GRAPHIC_SHRINKFIT) {
            if (m_style & GRAPHIC_PROPSCALE) {
                double scale_x = (graphic_sz.x > window_sz.x) ? window_sz.x / double(graphic_sz.x) : 1.0,
                    scale_y = (graphic_sz.y > window_sz.y) ? window_sz.y / double(graphic_sz.y) : 1.0;
                double scale = (scale_x < scale_y) ? scale_x : scale_y;
                pt2.x = int(graphic_sz.x * scale);
                pt2.y = int(graphic_sz.y * scale);
            } else {
                pt2 = window_sz;
            }
        }

        int shift = 0;
        if (m_style & GRAPHIC_LEFT) {
            shift = ul.x;
        } else if (m_style & GRAPHIC_CENTER) {
            shift = ul.x + (window_sz.x - (pt2.x - pt1.x)) / 2;
        } else { // m_style & GRAPHIC_RIGHT
            shift = lr.x - (pt2.x - pt1.x);
        }
        pt1.x += shift;
        pt2.x += shift;

        if (m_style & GRAPHIC_TOP) {
            shift = ul.y;
        } else if (m_style & GRAPHIC_VCENTER) {
            shift = ul.y + (window_sz.y - (pt2.y - pt1.y)) / 2;
        } else { // m_style & GRAPHIC_BOTTOM
            shift = lr.y - (pt2.y - pt1.y);
        }
        pt1.y += shift;
        pt2.y += shift;

        st.OrthoBlit(pt1, pt2);

        if (send_end_frame_signal)
            EndFrameSignal(final_frame_idx);
        if (send_stopped_signal)
            StoppedSignal(m_curr_frame);
    }
}

void DynamicGraphic::AddFrames(const Texture* texture, int frames/* = -1*/)
{
    int frames_in_texture = FramesInTexture(texture);
    if (!frames_in_texture)
        throw CannotAddFrame("DynamicGraphic::AddFrames : attempted to add frames from a Texture too small for even one frame");

    FrameSet fs;
    fs.texture.reset(texture);
    fs.frames = frames < 0 ? frames_in_texture : std::min(frames_in_texture, std::max(frames, 1));
    m_textures.push_back(fs);
    m_frames += fs.frames;
}

void DynamicGraphic::AddFrames(const boost::shared_ptr<Texture>& texture, int frames/* = -1*/)
{
    int frames_in_texture = FramesInTexture(texture.get());
    if (!frames_in_texture)
        throw CannotAddFrame("DynamicGraphic::AddFrames : attempted to add frames from a Texture too small for even one frame");

    FrameSet fs;
    fs.texture = texture;
    fs.frames = frames < 0 ? frames_in_texture : std::min(frames_in_texture, std::max(frames, 1));
    m_textures.push_back(fs);
    m_frames += fs.frames;
}

void DynamicGraphic::AddFrames(const std::vector<boost::shared_ptr<Texture> >& textures, int frames/* = -1*/)
{
    if (!textures.empty()) {
        int old_frames = m_frames;
        for (unsigned int i = 0; i < textures.size() - 1; ++i)
            AddFrames(textures[i], -1);
        AddFrames(textures.back(), m_frames - old_frames);
    }
}

void DynamicGraphic::Play()
{
    // if we're at the end of a previous playback and looping is disabled, reset the frame index to the initial frame
    if (!m_playing && !m_looping && m_curr_frame == (0.0 <= m_FPS ? m_last_frame_idx : m_first_frame_idx))
        SetFrameIndex(0.0 <= m_FPS ? m_first_frame_idx : m_last_frame_idx);
    m_playing = true;
    if (m_FPS == 0.0)
        m_FPS = DEFAULT_FPS;
}

void DynamicGraphic::Pause()
{
    m_playing = false;
}

void DynamicGraphic::NextFrame()
{
    if (0 <= m_curr_texture && 0 <= m_curr_subtexture && m_textures.size()) { // if these are reasonable values
        m_playing = false;
        if (m_curr_frame == m_last_frame_idx) { // if this is the very last frame
            if (m_looping) // only wrap around if looping is turned on
                SetFrameIndex(m_first_frame_idx);
        } else if (m_curr_subtexture == m_textures[m_curr_texture].frames - 1) {
            ++m_curr_texture;
            m_curr_subtexture = 0;
            ++m_curr_frame;
        } else {
            ++m_curr_subtexture;
            ++m_curr_frame;
        }
    }
}

void DynamicGraphic::PrevFrame()
{
    if (0 <= m_curr_texture && 0 <= m_curr_subtexture && m_textures.size()) { // if these are reasonable values
        m_playing = false;
        if (m_curr_frame == m_first_frame_idx) { // if this is the very first frame
            if (m_looping) // only wrap around if looping is turned on
                SetFrameIndex(m_last_frame_idx);
        } else if (!m_curr_subtexture) { // if this is the first frame in its texture
            --m_curr_texture;
            m_curr_subtexture = m_textures[m_curr_texture].frames - 1;
            --m_curr_frame;
        } else { // if this is some frame in the middle of its texture
            --m_curr_subtexture;
            --m_curr_frame;
        }
    }
}

void DynamicGraphic::Stop()
{
    m_playing = false;
    SetFrameIndex(0.0 <= m_FPS ? m_first_frame_idx : m_last_frame_idx);
}

void DynamicGraphic::Loop(bool b/* = true*/)
{
    m_looping = b;
}

void DynamicGraphic::SetFPS(double fps)
{
    m_FPS = fps;
}

void DynamicGraphic::SetFrameIndex(int idx)
{
    if (m_textures.empty()) { // if there are no valid texture data
        m_curr_texture = -1;
        m_curr_subtexture = -1;
        m_curr_frame = -1;
    } else if (idx < 0) { // if idx is too low
        m_curr_texture = 0;
        m_curr_subtexture = 0;
        m_curr_frame = 0;
    } else if (m_frames <= idx) { // if idx is too high
        m_curr_texture = static_cast<int>(m_textures.size()) - 1;
        m_curr_subtexture = m_textures[m_curr_texture].frames - 1;
        m_curr_frame = m_frames - 1;
    } else {
        // try to use O(1) Prev- and NextFrame() if we can
        if (idx == m_curr_frame + 1 && m_curr_frame < m_last_frame_idx) {
            NextFrame();
            m_playing = true;
        } else if (idx == m_curr_frame - 1 && m_first_frame_idx < m_curr_frame) {
            PrevFrame();
            m_playing = true;
        } else { // use O(n) linear search if necessary
            m_curr_frame = idx;
            if (idx == 0) {
                m_curr_texture = 0;
                m_curr_subtexture = 0;
            } else {
                m_curr_texture = 0;
                for (unsigned int i = 0; i < m_textures.size(); ++i) {
                    if (0 <= idx - m_textures[i].frames) {
                        idx -= m_textures[i].frames;
                        m_curr_texture++;
                    } else {
                        m_curr_subtexture = idx;
                        break;
                    }
                }
            }
        }
    }
}

void DynamicGraphic::SetTimeIndex(int idx)
{
    int initial_frame_idx = 0.0 <= m_FPS ? m_first_frame_idx : m_last_frame_idx;
    int final_frame_idx = 0.0 <= m_FPS ? m_last_frame_idx : m_first_frame_idx;
    int frames_in_sequence = (m_last_frame_idx - m_first_frame_idx + 1);
    if (idx < 0)
        SetFrameIndex(initial_frame_idx);
    else if (frames_in_sequence * m_FPS <= idx && !m_looping)
        SetFrameIndex(final_frame_idx);
    else
        SetFrameIndex(initial_frame_idx + static_cast<int>(idx / 1000.0 * m_FPS) % frames_in_sequence);
}

void DynamicGraphic::SetStartFrame(int idx)
{
    if (idx < 0)
        m_first_frame_idx = 0;
    else if (m_frames <= idx)
        m_first_frame_idx = m_frames - 1;
    else
        m_first_frame_idx = idx;

    if (m_curr_frame < m_first_frame_idx)
        SetFrameIndex(m_first_frame_idx);
}

void DynamicGraphic::SetEndFrame(int idx)
{
    if (idx < 0)
        m_last_frame_idx = 0;
    else if (m_frames <= idx)
        m_last_frame_idx = m_frames - 1;
    else
        m_last_frame_idx = idx;

    if (m_last_frame_idx < m_curr_frame)
        SetFrameIndex(m_last_frame_idx);
}

void DynamicGraphic::SetStyle(Flags<GraphicStyle> style)
{
    m_style = style;
    ValidateStyle();
}

void DynamicGraphic::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    Control::DefineAttributes(editor);
    editor->Label("DynamicGraphic");
    editor->Attribute("Frame Margin", const_cast<int&>(m_margin));
    editor->Attribute("Frame Width", const_cast<int&>(m_frame_width));
    editor->Attribute("Frame Height", const_cast<int&>(m_frame_height));
    // TODO: handle setting frame(s)
    editor->Attribute("Frames Per Second", m_FPS);
    editor->Attribute("Playing", m_playing);
    editor->Attribute("Looping", m_looping);
    editor->BeginFlags(m_style);
    typedef std::vector<GraphicStyle> FlagVec;
    using boost::assign::list_of;
    editor->FlagGroup("V. Alignment", FlagVec() = list_of(GRAPHIC_TOP)(GRAPHIC_VCENTER)(GRAPHIC_BOTTOM));
    editor->FlagGroup("H. Alignment", FlagVec() = list_of(GRAPHIC_LEFT)(GRAPHIC_CENTER)(GRAPHIC_RIGHT));
    editor->Flag("Fit Graphic to Size", GRAPHIC_FITGRAPHIC);
    editor->Flag("Shrink-to-Fit", GRAPHIC_SHRINKFIT);
    editor->Flag("Proportional Scaling", GRAPHIC_PROPSCALE);
    editor->EndFlags();
}

int DynamicGraphic::FramesInTexture(const Texture* t) const
{
    int cols = t->DefaultWidth() / (m_frame_width + m_margin);
    int rows = t->DefaultHeight() / (m_frame_height + m_margin);
    return cols * rows;
}

const std::vector<DynamicGraphic::FrameSet>& DynamicGraphic::Textures() const
{
    return m_textures;
}

int DynamicGraphic::CurrentTexture() const
{
    return m_curr_texture;
}

int DynamicGraphic::CurrentSubTexture() const
{
    return m_curr_texture;
}

int DynamicGraphic::FirstFrameTime() const
{
    return m_first_frame_time;
}

int DynamicGraphic::LastFrameTime() const
{
    return m_last_frame_time;
}

void DynamicGraphic::ValidateStyle()
{
    int dup_ct = 0;   // duplication count
    if (m_style & GRAPHIC_LEFT) ++dup_ct;
    if (m_style & GRAPHIC_RIGHT) ++dup_ct;
    if (m_style & GRAPHIC_CENTER) ++dup_ct;
    if (dup_ct != 1) {   // exactly one must be picked; when none or multiples are picked, use GRAPHIC_CENTER by default
        m_style &= ~(GRAPHIC_RIGHT | GRAPHIC_LEFT);
        m_style |= GRAPHIC_CENTER;
    }
    dup_ct = 0;
    if (m_style & GRAPHIC_TOP) ++dup_ct;
    if (m_style & GRAPHIC_BOTTOM) ++dup_ct;
    if (m_style & GRAPHIC_VCENTER) ++dup_ct;
    if (dup_ct != 1) {   // exactly one must be picked; when none or multiples are picked, use GRAPHIC_VCENTER by default
        m_style &= ~(GRAPHIC_TOP | GRAPHIC_BOTTOM);
        m_style |= GRAPHIC_VCENTER;
    }
    dup_ct = 0;
    if (m_style & GRAPHIC_FITGRAPHIC) ++dup_ct;
    if (m_style & GRAPHIC_SHRINKFIT) ++dup_ct;
    if (dup_ct > 1) {   // mo more than one may be picked; when both are picked, use GRAPHIC_SHRINKFIT by default
        m_style &= ~GRAPHIC_FITGRAPHIC;
        m_style |= GRAPHIC_SHRINKFIT;
    }
}




See more files for this project here

FreeOrion

FreeOrion brings nation building to a galactic scale with its full-featured grand campaign and in-game racial histories, in addition to the classic 4X model of galactic conquest and tactical combat.

Project homepage: http://sourceforge.net/projects/freeorion
Programming language(s): C,C++
License: other

  Ogre/
    Plugins/
      OISInput.cfg
      OISInput.cpp
      OISInput.h
      OgreGUIInputPlugin.cpp
      OgreGUIInputPlugin.h
      SConscript
    OgreGUI.cpp
    SConscript
  SDL/
    SConscript
    SDLGUI.cpp
  dialogs/
    ColorDlg.cpp
    FileDlg.cpp
    SConscript
    ThreeButtonDlg.cpp
  AlignmentFlags.cpp
  Base.cpp
  BrowseInfoWnd.cpp
  Button.cpp
  Clr.cpp
  Control.cpp
  Cursor.cpp
  DrawUtil.cpp
  DropDownList.cpp
  DynamicGraphic.cpp
  Edit.cpp
  EventPump.cpp
  Font.cpp
  GUI.cpp
  Layout.cpp
  ListBox.cpp
  Menu.cpp
  MultiEdit.cpp
  Plugin.cpp
  PluginInterface.cpp
  PtRect.cpp
  SConscript
  Scroll.cpp
  Slider.cpp
  StaticGraphic.cpp
  StyleFactory.cpp
  TabWnd.cpp
  TextControl.cpp
  Texture.cpp
  Timer.cpp
  Wnd.cpp
  WndEditor.cpp
  WndEvent.cpp
  ZList.cpp
  _vsnprintf.c