Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
82 KB
Referenced Files
None
Subscribers
None
diff --git a/editor/ImageEditor.cpp b/editor/ImageEditor.cpp
new file mode 100644
index 0000000..987fd55
--- /dev/null
+++ b/editor/ImageEditor.cpp
@@ -0,0 +1,393 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#include <qpen.h>
+#include <qpainter.h>
+#include "ImageEditor.h"
+
+#define SIZERW 7
+#define SIZERW2 3
+ImageData::ImageData()
+{
+ head.resize(4); body.resize(4); legs.resize(6); hit.resize(4); isExtrapolated = true;
+
+ head.setPoint( 0, 100, 100 );
+ head.setPoint( 1, 150, 100 );
+ head.setPoint( 2, 150, 150 );
+ head.setPoint( 3, 100, 150 );
+
+ body.setPoint( 0, 100, 160 );
+ body.setPoint( 1, 100, 250 );
+ body.setPoint( 2, 150, 250 );
+ body.setPoint( 3, 150, 160 );
+
+ legs.setPoint( 0, 150, 260 );
+ legs.setPoint( 1, 180, 300 );
+ legs.setPoint( 2, 190, 400 );
+ legs.setPoint( 3, 60, 400 );
+ legs.setPoint( 4, 70, 300 );
+ legs.setPoint( 5, 100, 260 );
+
+ hit.setPoint( 0, 10, 10 );
+ hit.setPoint( 1, 20, 10 );
+ hit.setPoint( 2, 20, 20 );
+ hit.setPoint( 3, 10, 20 );
+}
+
+ImageData& ImageData::operator=( const ImageData& d )
+{
+ int i;
+ for ( i=0; i<4; ++i )
+ {
+ head[i] = d.head[i];
+ body[i] = d.body[i];
+ hit[i] = d.hit[i];
+ }
+
+ for ( i=0; i<6; ++i )
+ {
+ legs[i] = d.legs[i];
+ }
+ imageOffset = d.imageOffset;
+ imageSize = d.imageSize;
+ isExtrapolated = d.isExtrapolated;
+
+ return *this;
+}
+
+enum
+{
+ CANVASSIZER_RTTI = 759238,
+ DRAGGABLEPOLYGON_RTTI = 25039,
+ DRAGGABLESPRITE_RTTI = 592783,
+};
+
+#define POSITION(A) (A->rtti() == CANVASSIZER_RTTI) ? ((CanvasSizer*)A)->position() : \
+(A->rtti() == DRAGGABLEPOLYGON_RTTI) ? ((DraggablePolygon*)A)->position() : \
+((DraggableSprite*)A)->position()
+
+#define MOVETO(A,B) (A->rtti() == CANVASSIZER_RTTI) ? ((CanvasSizer*)A)->moveTo(B) : \
+(A->rtti() == DRAGGABLEPOLYGON_RTTI) ? ((DraggablePolygon*)A)->moveTo(B) : \
+((DraggableSprite*)A)->moveTo(B);
+
+/*
+class CanvasDraggable
+{
+public:
+ virtual QPoint position() { return QPoint(0,0); }
+ virtual void reread() {}
+ virtual void moveTo( const QPoint& pos ) { debug( "CanvasDraggable::moveTo(%d,%d)", pos.x(), pos.y() ); }
+};
+*/
+
+class DraggableSprite: public QCanvasSprite
+{
+public:
+ DraggableSprite( QCanvasPixmapArray * a, QCanvas* canvas, QPoint* _point )
+ : QCanvasSprite( a, canvas )
+ {
+ point = _point;
+ reread();
+ }
+
+ virtual QPoint position() { return *point ; }
+ virtual void reread() { setX( point->x() ); setY( point->y() ); }
+ virtual void moveTo( const QPoint& pos ) { *point = pos; }
+ virtual int rtti() const
+ {
+ return DRAGGABLESPRITE_RTTI;
+ }
+protected:
+ QPoint* point;
+};
+
+class DraggablePolygon: public QCanvasPolygon
+{
+public:
+ DraggablePolygon( QCanvas* canvas, QPointArray* _array ) :
+ QCanvasPolygon( canvas )
+ {
+ array = _array;
+ setPoints( *array );
+ }
+
+ virtual QPoint position() { return (*array)[0]; }
+ virtual void reread() { setPoints( *array ); }
+ virtual void moveTo( const QPoint& pos )
+ {
+ QPoint _delta = pos - position();
+ if ( _delta.manhattanLength() == 0 )
+ {
+ // Not moved.
+ return;
+ }
+ for ( uint i=0; i<array->count(); ++i )
+ {
+ array->at(i) += _delta;
+ //(*array)[i] += _delta;
+ //(*array)[i] = (*array)[i] + _delta;
+ }
+ }
+ virtual int rtti() const
+ {
+ return DRAGGABLEPOLYGON_RTTI;
+ }
+protected:
+ QPointArray *array;
+};
+
+class CanvasSizer : public QCanvasRectangle
+{
+public:
+
+ CanvasSizer( QCanvas* canvas,
+ QCanvasPolygon* _polygon, QPointArray* _array, int _polyIndex, int _index )
+ : QCanvasRectangle( canvas )
+ {
+ array = _array;
+ index = _index;
+ polygon = _polygon;
+ setSize( SIZERW, SIZERW );
+ reread();
+ setPen( black );
+
+ switch ( _polyIndex )
+ {
+ case 0: setBrush( red); break;
+ case 1: setBrush( green ); break;
+ case 2: setBrush( blue ); break;
+ case 3: setBrush( yellow); break;
+ }
+ setZ( 20 );
+ show();
+ }
+
+ virtual QPoint position()
+ {
+ return (*array)[index];
+ }
+
+ virtual void reread()
+ {
+ setX( (*array)[index].x() - SIZERW2 );
+ setY( (*array)[index].y() - SIZERW2 );
+ polygon->setPoints( *array );
+ }
+
+ virtual void moveTo( const QPoint& p )
+ {
+ (*array)[index] = p;
+ reread();
+ }
+
+ virtual int rtti() const
+ {
+ return CANVASSIZER_RTTI;
+ }
+
+protected:
+ QPointArray* array;
+ int index;
+ QCanvasPolygon* polygon;
+};
+
+struct ImageEditor_P
+{
+ ImageEditor* This;
+
+ ImageData data;
+ QImage image;
+ QCanvasPixmapArray pixmapArray;
+ DraggablePolygon *head, *body, *legs, *hit;
+ DraggableSprite *background;
+
+ CanvasSizer* headSizer[4];
+ CanvasSizer* bodySizer[4];
+ CanvasSizer* legsSizer[6];
+ CanvasSizer* hitSizer[4];
+
+ bool dragging;
+ QPoint dragOrigin;
+ QPoint dragOffset;
+ QCanvasItem* draggable;
+
+ ImageEditor_P()
+ {
+ head = body = legs = hit = NULL;
+ background = NULL;
+
+ dragging = false;
+ draggable = NULL;
+ }
+
+ void data2Canvas()
+ {
+ int i;
+ This->canvas()->setBackgroundColor( QColor( 64,64,64 ) );
+
+ if ( !head )
+ {
+ head = new DraggablePolygon( This->canvas(), & data.head );
+ head->setBrush( QBrush( Qt::red, Qt::DiagCrossPattern ) );
+ head->setZ( 10 );
+ body = new DraggablePolygon( This->canvas(), & data.body );
+ body->setBrush( QBrush( Qt::green, Qt::DiagCrossPattern ) );
+ body->setZ( 8 );
+ legs = new DraggablePolygon( This->canvas(), & data.legs );
+ legs->setBrush( QBrush( Qt::blue, Qt::DiagCrossPattern ) );
+ legs->setZ( 6 );
+ hit = new DraggablePolygon( This->canvas(), & data.hit );
+ hit->setBrush( QBrush( Qt::yellow, Qt::DiagCrossPattern ) );
+ hit->setZ( 6 );
+
+ for ( i=0; i<4; ++i )
+ headSizer[i] = new CanvasSizer( This->canvas(),
+ head, & data.head, 0, i );
+ for ( i=0; i<4; ++i )
+ bodySizer[i] = new CanvasSizer( This->canvas(),
+ body, & data.body, 1, i );
+ for ( i=0; i<6; ++i )
+ legsSizer[i] = new CanvasSizer( This->canvas(),
+ legs, & data.legs, 2, i );
+ for ( i=0; i<4; ++i )
+ hitSizer[i] = new CanvasSizer( This->canvas(),
+ hit, & data.hit, 3, i );
+ }
+
+ head->setPoints( data.head );
+ head->show();
+ body->setPoints( data.body );
+ body->show();
+ legs->setPoints( data.legs );
+ legs->show();
+ hit->setPoints( data.hit );
+ hit->show();
+
+ for ( i=0; i<4; ++i ) headSizer[i]->reread();
+ for ( i=0; i<4; ++i ) bodySizer[i]->reread();
+ for ( i=0; i<6; ++i ) legsSizer[i]->reread();
+ for ( i=0; i<4; ++i ) hitSizer[i]->reread();
+
+ rereadImage();
+ This->canvas()->setAllChanged();
+ This->canvas()->update();
+ }
+
+ void setImage( const QImage& newimage )
+ {
+ if ( image == newimage )
+ return;
+
+ image = newimage;
+ pixmapArray.setImage( 0, new QCanvasPixmap( image ) );
+
+ if ( ! background )
+ {
+ background = new DraggableSprite( &pixmapArray, This->canvas(), & data.imageOffset );
+ background->show();
+ }
+ else
+ {
+ background->setSequence( &pixmapArray );
+ }
+ rereadImage();
+ //
+ //This->canvas()->update();
+ }
+
+ void rereadImage()
+ {
+ background->setX( data.imageOffset.x() );
+ background->setY( data.imageOffset.y() );
+ }
+};
+
+ImageEditor::ImageEditor( QWidget * parent, const char * name, WFlags f )
+ : QCanvasView( parent, name, f )
+{
+ p = new ImageEditor_P;
+ p->This = this;
+}
+
+ImageEditor::~ImageEditor()
+{
+ delete( p );
+ p = NULL;
+}
+
+void ImageEditor::setImage( const QImage& image )
+{
+ QImage img = image;
+ p->setImage( image );
+}
+
+ImageData ImageEditor::getData()
+{
+ return p->data;
+}
+
+void ImageEditor::setData( ImageData data )
+{
+ p->data = data;
+ p->data2Canvas();
+ emit extrapolated( data.isExtrapolated );
+
+ QPoint focalPoint = data.imageOffset;
+ focalPoint += QPoint( p->image.width() / 2, p->image.height() / 2 );
+ focalPoint = worldMatrix() * focalPoint;
+ center( focalPoint.x(), focalPoint.y(), 0.5, 0.5 );
+}
+
+void ImageEditor::contentsMousePressEvent ( QMouseEvent * e )
+{
+ if ( p->dragging )
+ {
+ MOVETO( p->draggable, p->dragOrigin );
+ p->dragging = false;
+ p->data2Canvas();
+ return;
+ }
+
+ QPoint src = inverseWorldMatrix().map(e->pos());
+
+ // Find which canvas widget is there...
+
+ QCanvasItemList items = canvas()->collisions ( src );
+ if ( items.count() == 0 )
+ return; // Nothing is there
+
+ QCanvasItem* item = items.first();
+
+ p->draggable = item;
+ p->dragging = true;
+ p->dragOrigin = POSITION(item);
+ p->dragOffset = src - p->dragOrigin;
+
+}
+
+void ImageEditor::contentsMouseMoveEvent ( QMouseEvent * e )
+{
+ if ( !p->dragging )
+ return;
+ QPoint src = inverseWorldMatrix().map(e->pos());
+ src -= p->dragOffset;
+
+ MOVETO(p->draggable, src);
+ p->data2Canvas();
+}
+
+void ImageEditor::contentsMouseReleaseEvent( QMouseEvent * e )
+{
+ contentsMouseMoveEvent( e );
+ if (!p->dragging)
+ return;
+ p->dragging = false;
+ p->draggable = false;
+ p->data.isExtrapolated = false;
+ emit extrapolated(false);
+}
+
diff --git a/editor/ImageEditor.h b/editor/ImageEditor.h
new file mode 100644
index 0000000..bfc25c7
--- /dev/null
+++ b/editor/ImageEditor.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#ifndef IMAGEEDITOR_H
+#define IMAGEEDITOR_H
+
+#ifndef QIMAGE_H
+#include <qimage.h>
+#endif
+#ifndef QCANVASVIEW_H
+#include <qcanvas.h>
+#endif
+#ifndef QPOINTARRAY_H
+#include <qpointarray.h>
+#endif
+
+struct ImageData
+{
+ QPointArray head;
+ QPointArray body;
+ QPointArray legs;
+ QPointArray hit;
+ QPoint imageOffset;
+ QSize imageSize;
+ bool isExtrapolated;
+
+ ImageData();
+ ImageData& operator=( const ImageData& );
+};
+
+struct ImageEditor_P;
+class QImage;
+
+class ImageEditor: public QCanvasView
+{
+ Q_OBJECT
+public:
+ ImageEditor( QWidget * parent = 0, const char * name = 0, WFlags f = 0 );
+ ~ImageEditor();
+
+ virtual void setImage( const QImage& image );
+ virtual ImageData getData();
+ virtual void setData( ImageData data );
+
+signals:
+ void extrapolated( bool );
+
+protected:
+ virtual void contentsMousePressEvent ( QMouseEvent * e );
+ virtual void contentsMouseMoveEvent ( QMouseEvent * e );
+ virtual void contentsMouseReleaseEvent( QMouseEvent * e );
+
+private:
+ ImageEditor_P * p;
+};
+
+#endif
diff --git a/editor/ImageStorage.cpp b/editor/ImageStorage.cpp
new file mode 100644
index 0000000..c98a8b0
--- /dev/null
+++ b/editor/ImageStorage.cpp
@@ -0,0 +1,245 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#include <qvaluevector.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qvaluelist.h>
+
+#include "ImageStorage.h"
+#include "OutlineDetector.h"
+#include "RlePack.h"
+
+ImageStorage ImageStorage::singleton;
+
+struct ImageStorage_P
+{
+ QValueVector<ImageData> dataVector;
+ int m_iHeadW;
+ int m_iHeadH;
+ int m_iBodyW;
+ double m_dBodyP;
+};
+
+ImageStorage& ImageStorage::instance()
+{
+ return singleton;
+}
+
+ImageStorage::ImageStorage()
+{
+ d = new ImageStorage_P;
+ d->m_iHeadW = 35;
+ d->m_iHeadH = 45;
+ d->m_iBodyW = 55;
+ d->m_dBodyP = 0.5;
+}
+
+void ImageStorage::load( const QString& filename )
+{
+ QFile f( filename );
+ if ( !f.open( IO_ReadOnly | IO_Translate ) )
+ {
+ return;
+ }
+
+ QTextStream s( &f );
+ QString line;
+ QStringList sl;
+ QRegExp separator( "[^0-9]+" );
+ QValueList<ImageData> images;
+
+ while (!f.atEnd() )
+ {
+ line = s.readLine();
+ sl = sl.split( separator, line, false );
+ if ( sl.count() < 4 )
+ continue;
+
+ ImageData data;
+ data.isExtrapolated = true;
+
+ data.imageOffset.setX( sl[0].toInt() );
+ data.imageOffset.setY( sl[1].toInt() );
+ data.imageSize.setWidth( sl[2].toInt() );
+ data.imageSize.setHeight( sl[3].toInt() );
+
+ debug( "Found data: %d %d %d %d", data.imageSize.width(), data.imageSize.height(),
+ data.imageOffset.x(), data.imageOffset.y() );
+
+ if ( sl.count() < 31 )
+ {
+ images.push_back( data );
+ continue;
+ }
+
+ int j = 4;
+ int i;
+ for ( i=0; i<4; ++i )
+ {
+ data.head[i].setX( sl[j++].toInt() );
+ data.head[i].setY( sl[j++].toInt() );
+ }
+ for ( i=0; i<4; ++i )
+ {
+ data.body[i].setX( sl[j++].toInt() );
+ data.body[i].setY( sl[j++].toInt() );
+ }
+ for ( i=0; i<6; ++i )
+ {
+ data.legs[i].setX( sl[j++].toInt() );
+ data.legs[i].setY( sl[j++].toInt() );
+ }
+ data.isExtrapolated = sl[j++].toInt();
+
+ if ( sl.count() > 36 )
+ {
+ for ( i=0; i<4; ++i )
+ {
+ data.hit[i].setX( sl[j++].toInt() );
+ data.hit[i].setY( sl[j++].toInt() );
+ }
+ }
+
+ images.push_back( data );
+ }
+
+ d->dataVector.resize( images.count() );
+ for ( uint i=0; i<images.count(); ++i )
+ {
+ d->dataVector[i] = images[i];
+ }
+}
+
+
+QString array2String( const QPointArray& a )
+{
+ QString s = "[";
+ QString s1;
+ for ( uint i=0; i<a.count(); ++i )
+ {
+ s1.sprintf( "%3d,%3d,", a.at(i).x(), a.at(i).y() );
+ s += s1;
+ }
+ s += "]";
+ return s;
+}
+
+void ImageStorage::save( const QString& filename, RlePack* images )
+{
+ QFile f( filename );
+ if (! f.open ( IO_WriteOnly ) )
+ {
+ return;
+ }
+ QTextStream out( &f );
+
+ QString s, s1;
+
+ for ( uint i=0; i<count(); ++i )
+ {
+ ImageData d = getImageData(i, images);
+ s.sprintf( "'x'=>%3d, 'y'=>%3d, 'w'=>%3d, 'h'=>%3d, 'head'=>%s, 'body'=>%s, 'legs'=>%s, 'ex'=>%d",
+ d.imageOffset.x(), d.imageOffset.y(),
+ d.imageSize.width(), d.imageSize.height(),
+ array2String( d.head ).latin1(),
+ array2String( d.body ).latin1(),
+ array2String( d.legs ).latin1(),
+ d.isExtrapolated );
+ if ( d.hit[0].x() != 10 )
+ {
+ s += ", 'hit'=>" + array2String( d.hit );
+ }
+ out << "{ "<< s << " },\n";
+ }
+ f.close();
+}
+
+uint ImageStorage::count()
+{
+ return d->dataVector.size();
+}
+
+ImageData ImageStorage::getImageData( int index, RlePack* images )
+{
+ ImageData data = d->dataVector[index];
+// debug( "ImageStorage::getImageData( %d, extrapolated %d )", index, data.isExtrapolated );
+
+ if ( data.isExtrapolated )
+ {
+ QImage image( images->getSize( index ), 8 );
+ image.fill(0);
+ images->draw( image, index, 0, 0 );
+ OutlineDetector::doDetection( d->m_iHeadW, d->m_iHeadH, d->m_iBodyW, d->m_dBodyP,
+ image, data );
+ }
+ /*
+ if ( data.isExtrapolated )
+ {
+ debug( "Extrapolating image %d", index );
+ // Extrapolate data
+ if ( index == 0 )
+ return data;
+
+ // Find the non-extrapolated image before index
+
+ int before, after;
+ for ( before=index-1; before>=0; --before )
+ if ( ! d->dataVector[before].isExtrapolated )
+ break;
+ if ( before < 0 )
+ return data;
+
+ // Find the non-extrapolated image after index
+
+ for ( after = index+1; after<count(); ++after )
+ if ( ! d->dataVector[after].isExtrapolated )
+ break;
+ if ( after >= count() )
+ return data;
+
+ // Found before and after, now all we have to do is
+ // extrapolate...
+ debug( "Before = %d, after = %d", before, after );
+
+ double wbefore = ((double)after-index) / ((double)after-before);
+ double wafter = ((double)index-before) / ((double)after-before);
+ ImageData dbefore = d->dataVector[before];
+ ImageData dafter = d->dataVector[after];
+ int i;
+
+ for ( i=0; i<4; ++i )
+ {
+ data.head[i].setX( int ( dbefore.head[i].x()*wbefore + dafter.head[i].x()*wafter ) );
+ data.head[i].setY( int ( dbefore.head[i].y()*wbefore + dafter.head[i].y()*wafter ) );
+ data.body[i].setX( int ( dbefore.body[i].x()*wbefore + dafter.body[i].x()*wafter ) );
+ data.body[i].setY( int ( dbefore.body[i].y()*wbefore + dafter.body[i].y()*wafter ) );
+ }
+ for ( i=0; i<6; ++i )
+ {
+ data.legs[i].setX( int ( dbefore.legs[i].x()*wbefore + dafter.legs[i].x()*wafter ) );
+ data.legs[i].setY( int ( dbefore.legs[i].y()*wbefore + dafter.legs[i].y()*wafter ) );
+ }
+ }
+ */
+ return data;
+}
+
+void ImageStorage::setImageData( int index, const ImageData& data )
+{
+// debug( "ImageStorage::setImageData( %d, extrapolated %d )", index, data.isExtrapolated );
+ d->dataVector[index] = data;
+}
+
+void ImageStorage::setDetectionParams( int a_iHeadW, int a_iHeadH, int a_iBodyW, double a_dBodyP )
+{
+ d->m_iHeadW = a_iHeadW;
+ d->m_iHeadH = a_iHeadH;
+ d->m_iBodyW = a_iBodyW;
+ d->m_dBodyP = a_dBodyP;
+}
diff --git a/editor/ImageStorage.h b/editor/ImageStorage.h
new file mode 100644
index 0000000..f4151d3
--- /dev/null
+++ b/editor/ImageStorage.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#ifndef _IMAGEDATA_H
+#define _IMAGEDATA_H
+
+#include "ImageEditor.h"
+
+struct ImageStorage_P;
+class RlePack;
+
+class ImageStorage
+{
+public:
+ static ImageStorage& instance();
+
+ void load( const QString& filename );
+ void save( const QString& filename, RlePack* images );
+
+ uint count();
+ ImageData getImageData( int index, RlePack* images );
+ void setImageData( int index, const ImageData& data );
+ void setDetectionParams( int a_iHeadW, int a_iHeadH, int a_iBodyW, double a_dBodyP );
+
+protected:
+ ImageStorage();
+
+protected:
+ static ImageStorage singleton;
+ ImageStorage_P* d;
+};
+
+#endif
diff --git a/editor/MortalEditor.pro b/editor/MortalEditor.pro
new file mode 100644
index 0000000..8410705
--- /dev/null
+++ b/editor/MortalEditor.pro
@@ -0,0 +1,31 @@
+SOURCES += RlePack.cpp \
+ main.cpp \
+ ImageEditor.cpp \
+ ImageStorage.cpp \
+ OutlineDetector.cpp
+HEADERS += RlePack.h \
+ ImageEditor.h \
+ ImageStorage.h \
+ OutlineDetector.h
+unix {
+ UI_DIR = .ui
+ MOC_DIR = .moc
+ OBJECTS_DIR = .obj
+}
+FORMS = mortaleditor.ui
+IMAGES = images/filenew \
+ images/fileopen \
+ images/filesave \
+ images/print \
+ images/undo \
+ images/redo \
+ images/editcut \
+ images/editcopy \
+ images/editpaste \
+ images/searchfind \
+ images/zoomin.png \
+ images/zoomout.png \
+ images/xrefresh.png
+TEMPLATE =app
+CONFIG += qt warn_on thread debug
+LANGUAGE = C++
diff --git a/editor/OutlineDetector.cpp b/editor/OutlineDetector.cpp
new file mode 100644
index 0000000..05e72c6
--- /dev/null
+++ b/editor/OutlineDetector.cpp
@@ -0,0 +1,228 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#include <qimage.h>
+#include <qwmatrix.h>
+#include "ImageEditor.h"
+#include "OutlineDetector.h"
+
+
+
+ImageData OutlineDetector::doDetection( int _headW, int _headH, int _bodyW,
+ double _bodyPercent, QImage& _image, ImageData& _data )
+{
+ OutlineDetector o( _headW, _headH, _bodyW, _bodyPercent, _image );
+
+ QPoint _imageOffset = _data.imageOffset;
+ o.data.imageOffset = _imageOffset;
+ o.data.imageSize = _data.imageSize;
+ o.data.head.translate( _imageOffset.x(), _imageOffset.y() );
+ o.data.body.translate( _imageOffset.x(), _imageOffset.y() );
+ o.data.legs.translate( _imageOffset.x(), _imageOffset.y() );
+
+ _image = o.image;
+ _data = o.data;
+ return o.data;
+}
+
+
+
+void OutlineDetector::findScanline( int _y, int& _outFrom, int& _outWidth )
+{
+ int _maxfrom = -1, _maxwidth = 0;
+ int _from = 0, _width = 0;
+ bool _inside = false;
+ int _pixel;
+
+ for ( int x=0; x<imageW; ++x )
+ {
+ _pixel = image.pixelIndex( x, _y );
+ if ( _pixel == 0 )
+ {
+ if ( _inside )
+ {
+ // We have reached the end of this round.
+ if ( _width > _maxwidth )
+ {
+ _maxfrom = _from; _maxwidth = _width;
+ }
+ //debug( "Reached the end of the run at %d, %d", x, _y );
+ }
+ _inside = false;
+ continue;
+ }
+
+ if ( !_inside )
+ {
+ //debug( "Reached the start of the run at %d, %d", x, _y );
+ _from = x;
+ _width = 0;
+ _inside = true;
+ }
+ ++_width;
+ }
+
+ if ( _inside && _width > _maxwidth )
+ {
+ _maxwidth = _width; _maxfrom = _from;
+ }
+
+ _outFrom = _maxfrom;
+ _outWidth = _maxwidth;
+}
+
+
+void OutlineDetector::findMinMax( int y1, int y2, int& _min, int& _max )
+{
+ _min = _max = -1;
+ int _pixel;
+
+ for ( int y=y1; y<=y2; ++y )
+ {
+ for ( int x=0; x<imageW; ++x )
+ {
+ _pixel = image.pixelIndex( x, y );
+ if ( _pixel == 0 )
+ {
+ continue;
+ }
+
+ if ( (_min < 0) || (_min > x) )
+ _min = x;
+ if ( (_max < x ) )
+ _max = x;
+ }
+ }
+
+}
+
+
+void OutlineDetector::findAverage( int y1, int y2, int& from, int& width )
+{
+ if ( y1>y2 )
+ {
+ from = width = -1;
+ return;
+ }
+
+ int totX = 0, totW = 0;
+
+ for ( int y=y1; y<y2; ++y )
+ {
+ int _from, _width;
+ findScanline( y, _from, _width );
+ totX += _from;
+ totW += _width;
+ //image.setPixel( scanX[0], y, 5 );
+ }
+
+ from = totX / (y2-y1+1);
+ width = totW / (y2-y1 + 1 );
+}
+
+
+
+OutlineDetector::OutlineDetector( int __headW, int __headH, int __bodyW, double __bodyPercent, QImage& __image )
+{
+ headW = __headW;
+ headH = __headH;
+ bodyW = __bodyW;
+ bodyPercent = __bodyPercent;
+ image = __image;
+
+ imageW = image.width();
+ imageH = image.height();
+
+ if ( imageH < headH *1.25 )
+ {
+ // Image is too small for detection
+ data.head.setPoint( 0, 0, 0 );
+ data.head.setPoint( 1, imageW, 0 );
+ data.head.setPoint( 2, imageW, imageH );
+ data.head.setPoint( 3, 0, imageH );
+
+ data.body.setPoint( 0, 0, 0 );
+ data.body.setPoint( 1, imageW, 0 );
+ data.body.setPoint( 2, imageW, imageH );
+ data.body.setPoint( 3, 0, imageH );
+
+ data.legs.setPoint( 0, 0, 0 );
+ data.legs.setPoint( 1, imageW/2, 0 );
+ data.legs.setPoint( 2, imageW, 0 );
+ data.legs.setPoint( 3, imageW, imageH );
+ data.legs.setPoint( 4, imageW/2, imageH );
+ data.legs.setPoint( 5, 0, imageH );
+ return;
+ }
+
+ bool bRotated = false;
+
+ if ( imageH < 150 && imageW > 200 )
+ {
+ // laying position. Change strategy.
+ QWMatrix oMatrix;
+ oMatrix.rotate( -90.0 );
+ image = image.xForm( oMatrix );
+
+ imageW = image.width();
+ imageH = image.height();
+ bRotated = true;
+ }
+
+ int _headX, _headW, _bodyX, _bodyW;
+ int _bodyY = int( (imageH - headH) * bodyPercent + headH );
+ int _legX1, _legX2;
+
+ findAverage( 0, headH, _headX, _headW );
+ findAverage( headH, _bodyY, _bodyX, _bodyW );
+
+ int _legH = imageH - _bodyY + 1;
+ findMinMax( _bodyY + _legH/2, imageH-1, _legX1, _legX2 );
+
+// debug( "Head X: %d, head W: %d", _headX, _headW );
+// debug( "Body X: %d, body W: %d", _bodyX, _bodyW );
+
+ if ( bRotated )
+ {
+ data.head.setPoint( 0, 0, imageW-_headX-_headW );
+ data.head.setPoint( 1, headH, imageW-_headX-_headW );
+ data.head.setPoint( 2, headH, imageW-_headX );
+ data.head.setPoint( 3, 0, imageW-_headX );
+
+ data.body.setPoint( 0, headH, imageW-_bodyX-bodyW );
+ data.body.setPoint( 1, _bodyY+5, imageW-_bodyX-bodyW );
+ data.body.setPoint( 2, _bodyY+5, imageW-_bodyX );
+ data.body.setPoint( 3, headH, imageW-_bodyX );
+
+ data.legs.setPoint( 0, _bodyY-5, imageW-_bodyX-bodyW );
+ data.legs.setPoint( 1, _bodyY-5, imageW-_bodyX-bodyW-5 );
+ data.legs.setPoint( 2, imageH, imageW-_legX2 );
+ data.legs.setPoint( 3, imageH, imageW-_legX1 );
+ data.legs.setPoint( 4, _bodyY-5, imageW );
+ data.legs.setPoint( 5, _bodyY-5, imageW-5 );
+ return;
+ }
+
+ data.head.setPoint( 0, _headX, 0 );
+ data.head.setPoint( 1, _headX + _headW, 0 );
+ data.head.setPoint( 2, _headX + _headW, headH+5 );
+ data.head.setPoint( 3, _headX, headH+5 );
+
+ data.body.setPoint( 0, _bodyX, headH );
+ data.body.setPoint( 1, _bodyX + bodyW, headH );
+ data.body.setPoint( 2, _bodyX + bodyW, _bodyY+5 );
+ data.body.setPoint( 3, _bodyX, _bodyY+5 );
+
+ data.legs.setPoint( 0, _bodyX, _bodyY-5 );
+ data.legs.setPoint( 1, _bodyX + 5, _bodyY-5 );
+ data.legs.setPoint( 2, _bodyX + bodyW - 5, _bodyY-5 );
+ data.legs.setPoint( 3, _bodyX + bodyW, _bodyY-5 );
+ data.legs.setPoint( 4, _legX2, imageH );
+ data.legs.setPoint( 5, _legX1, imageH );
+}
+
+
diff --git a/editor/OutlineDetector.h b/editor/OutlineDetector.h
new file mode 100644
index 0000000..b5de680
--- /dev/null
+++ b/editor/OutlineDetector.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#ifndef OUTLINEDETECTOR_H
+#define OUTLINEDETECTOR_H
+
+class OutlineDetector
+{
+public:
+ static ImageData doDetection( int _headW, int _headH, int _bodyW, double _bodyPercent,
+ QImage& _image, ImageData& _data );
+
+protected:
+
+ OutlineDetector( int _headW, int _headH, int _bodyW, double _bodyPercent, QImage& _image );
+
+ void findScanline( int _y, int& _from, int& width );
+ void findMinMax( int y1, int y2, int& _min, int& _max );
+ void findAverage( int y1, int y2, int& from, int& width );
+
+protected:
+ int headW;
+ int headH;
+ int bodyW;
+ double bodyPercent;
+
+ QImage image;
+ int imageW;
+ int imageH;
+ ImageData data;
+};
+
+#endif
diff --git a/editor/RlePack.cpp b/editor/RlePack.cpp
new file mode 100644
index 0000000..fef3d8d
--- /dev/null
+++ b/editor/RlePack.cpp
@@ -0,0 +1,407 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <qimage.h>
+
+#include "RlePack.h"
+
+typedef unsigned char Uint8;
+
+typedef struct {
+ Uint8 r;
+ Uint8 g;
+ Uint8 b;
+ Uint8 unused;
+} SDL_Color;
+
+
+typedef struct RLE_SPRITE /* a RLE compressed sprite */
+{
+ int w, h; /* width and height in pixels */
+ int color_depth; /* color depth of the image */
+ int size; /* size of sprite data in bytes */
+ signed char dat[0];
+} RLE_SPRITE;
+
+
+struct RlePack_P
+{
+ SDL_Color palette[256];
+ int count, arraysize;
+ RLE_SPRITE** sprites;
+};
+
+RlePack::RlePack( const char* filename )
+{
+ p = new RlePack_P;
+ p->count = p->arraysize = 0;
+ p->sprites = NULL;
+
+ //@ Load file and stuff
+ FILE* f;
+
+ f = fopen( filename, "rb" );
+ if (f==NULL)
+ {
+ debug( "Can't open file '%s'.\n", filename );
+ return;
+ }
+
+ int datacount;
+
+#define READDW(I) { \
+ unsigned char data[4]; \
+ fread( data, 4, 1, f ); \
+ (I) = (data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]; }
+#define READW(I) { \
+unsigned char data[2]; \
+ fread( data, 2, 1, f ); \
+ (I) = (data[0]<<8) + data[1]; }
+#define READCH(S,C) { \
+fread( S, C, 1, f ); S[C] = 0; }
+
+ fseek( f, 8, SEEK_SET ); // Skip header
+ READDW( datacount );
+
+ debug( "File '%s' contains %d entries.\n", filename, datacount );
+ if (datacount>500) datacount = 500; // Sanity
+
+ p->arraysize = datacount;
+ p->sprites = new RLE_SPRITE*[ datacount ];
+
+ while( (!feof(f)) && (!ferror(f)) && (datacount>0) )
+ {
+ char s[10];
+ READCH( s, 4 );
+ if ( !strcmp( s, "prop" )) // Found a property
+ {
+ fseek( f, 4, SEEK_CUR );
+ unsigned int propsize;
+ READDW( propsize );
+ fseek( f, propsize, SEEK_CUR );
+ }
+ else if (!strcmp( s, "RLE " )) // Found an RLE_SPRITE
+ {
+ datacount--;
+
+ unsigned int length, bpp, width, height, size;
+
+ READDW( length );
+ READDW( length );
+ READW( bpp );
+ READW( width );
+ READW( height );
+ READDW( size );
+
+ RLE_SPRITE* sprite = (RLE_SPRITE*) malloc( sizeof(RLE_SPRITE) + size );
+ p->sprites[ p->count ] = sprite;
+ (p->count)++;
+ sprite->w = width;
+ sprite->h = height;
+ sprite->color_depth = bpp;
+ sprite->size = size;
+ fread( sprite->dat, 1, size, f );
+ }
+ else if (!strcmp( s, "PAL ")) // Found a palette
+ {
+ datacount--;
+
+ unsigned int length, pallength;
+ READDW( length );
+ READDW( length );
+ pallength = length>1024 ? 1024 : length;
+ pallength /= 4;
+
+ for (uint i=0; i< pallength; i++)
+ {
+ char c[4];
+ fread( c, 4, 1, f );
+ p->palette[i].r = c[0]*4;
+ p->palette[i].g = c[1]*4;
+ p->palette[i].b = c[2]*4;
+ p->palette[i].unused = 0;
+ }
+
+ fseek( f, length - pallength*4, SEEK_CUR );
+ }
+ else // Found something else
+ {
+ debug( "Unknown: %s.", s );
+ datacount--;
+
+ unsigned int length;
+ READDW( length );
+ READDW( length );
+ fseek( f, length, SEEK_CUR );
+ }
+ }
+
+ fclose( f );
+}
+
+RlePack::~RlePack()
+{
+ if (!p)
+ return;
+
+ if (p->sprites)
+ {
+ for ( int i=0; i<p->count; ++i )
+ {
+ delete p->sprites[i];
+ p->sprites[i] = NULL;
+ }
+ delete[] p->sprites;
+ p->sprites = NULL;
+ }
+
+ delete( p );
+ p = NULL;
+}
+
+/*
+void OffsetRLESprite( RLE_SPRITE* spr, int offset )
+{
+ if (!spr || !offset) return;
+
+ signed char *s = spr->dat;
+ signed char c;
+ int y;
+
+ for (y=0; y<spr->h; y++)
+ {
+ c = *s++;
+
+ while (c)
+ {
+ // For positive c: solid pixels.
+ for ( ; c>0; c-- )
+ {
+ *s = (*s) + offset;
+ s++;
+ }
+ c = *s++;
+ }
+ }
+}
+
+
+void RlePack::offsetSprites( int offset )
+{
+ if ( (offset<=0) || (offset>255) )
+ return;
+
+ int i;
+
+ // Offset every RLE_SPRITE
+
+ for ( i=0; i<p->count; ++i )
+ {
+ OffsetRLESprite( p->sprites[i], offset );
+ }
+}
+*/
+
+/*
+SDL_Color* RlePack::getPalette()
+{
+ return p->palette;
+}
+*/
+
+
+void draw_rle_sprite( QImage& target, RLE_SPRITE* src, int dx, int dy )
+{
+#define RLE_PTR signed char*
+#define RLE_IS_EOL(c) ((c) == 0)
+#define PIXEL_PTR unsigned char*
+#define OFFSET_PIXEL_PTR(p,x) ((PIXEL_PTR) (p) + (x))
+#define INC_PIXEL_PTR(p) ((p)++)
+#define DEC_PIXEL_PTR(p) ((p)--)
+#define PUT_PIXEL(p,c) (*((unsigned char *)(p)) = (c))
+
+ int x, y, w, h; // width and height of visible area
+ int dxbeg, dybeg; // beginning in destination
+ int sxbeg, sybeg; // beginning in source
+ RLE_PTR s;
+
+ // Clip to dst->clip_rect
+ int dst_cl = 0;
+ int dst_cr = target.width();
+ int dst_ct = 0;
+ int dst_cb = target.height();
+
+// if (dst->clip)
+ if (1)
+ {
+
+ int tmp;
+
+ tmp = dst_cl - dx;
+ sxbeg = ((tmp < 0) ? 0 : tmp);
+ dxbeg = sxbeg + dx;
+
+ tmp = dst_cr - dx;
+ w = ((tmp > src->w) ? src->w : tmp) - sxbeg;
+ if ( w<=0 ) return;
+
+ tmp = dst_ct - dy;
+ sybeg = ((tmp < 0) ? 0 : tmp);
+ dybeg = sybeg + dy;
+
+ tmp = dst_cb - dy;
+ h = ((tmp > src->h) ? src->h : tmp) - sybeg;
+ if ( h<=0 ) return;
+ }
+ else {
+ w = src->w;
+ h = src->h;
+ sxbeg = 0;
+ sybeg = 0;
+ dxbeg = dx;
+ dybeg = dy;
+ }
+
+ s = (RLE_PTR) (src->dat);
+
+ /* Clip top. */
+ for (y = sybeg - 1; y >= 0; y--) {
+ long c = *s++;
+
+ while (!RLE_IS_EOL(c)) {
+ if (c > 0)
+ s += c;
+ c = *s++;
+ }
+ }
+
+ // Visible part.
+ for (y = 0; y < h; y++)
+ {
+ //@@@ PIXEL_PTR d = OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y), dxbeg);
+ PIXEL_PTR d = target.scanLine(dybeg + y) + dxbeg;
+ if ( !d) break;
+ //PIXEL_PTR d = (PIXEL_PTR) dst->pixels;
+ //d += (dybeg+y)*dst->pitch;
+ //d = OFFSET_PIXEL_PTR( d, dxbeg );
+ long c = *s++;
+
+ // Clip left.
+ for (x = sxbeg; x > 0; ) {
+ if (RLE_IS_EOL(c))
+ goto next_line;
+ else if (c > 0) {
+ /* Run of solid pixels. */
+ if ((x - c) >= 0) {
+ /* Fully clipped. */
+ x -= c;
+ s += c;
+ }
+ else {
+ /* Visible on the right. */
+ c -= x;
+ s += x;
+ break;
+ }
+ }
+ else {
+ /* Run of transparent pixels. */
+ if ((x + c) >= 0) {
+ /* Fully clipped. */
+ x += c;
+ }
+ else {
+ /* Visible on the right. */
+ c += x;
+ break;
+ }
+ }
+
+ c = *s++;
+ }
+
+ /* Visible part. */
+ for (x = w; x > 0; ) {
+ if (RLE_IS_EOL(c))
+ goto next_line;
+ else if (c > 0) {
+ /* Run of solid pixels. */
+ if ((x - c) >= 0) {
+ /* Fully visible. */
+ x -= c;
+ for (c--; c >= 0; s++, INC_PIXEL_PTR(d), c--) {
+ unsigned long col = *s;
+ PUT_PIXEL(d, col);
+ }
+ }
+ else {
+ /* Clipped on the right. */
+ c -= x;
+ for (x--; x >= 0; s++, INC_PIXEL_PTR(d), x--) {
+ unsigned long col = *s;
+ PUT_PIXEL(d, col);
+ }
+ break;
+ }
+ }
+ else {
+ /* Run of transparent pixels. */
+ x += c;
+ d = OFFSET_PIXEL_PTR(d, -c);
+ }
+
+ c = *s++;
+ }
+
+ /* Clip right. */
+ while (!RLE_IS_EOL(c)) {
+ if (c > 0)
+ s += c;
+ c = *s++;
+ }
+
+ next_line: ;
+ }
+
+}
+
+int RlePack::count()
+{
+ return p->count;
+}
+
+void RlePack::draw( QImage& target, int index, int x, int y )
+{
+ if ( (index<0) || (index>=p->count) )
+ return;
+
+ RLE_SPRITE* sprite = p->sprites[index];
+ if (!sprite)
+ return;
+
+ draw_rle_sprite( target, sprite, x, y );
+}
+
+QSize RlePack::getSize( int index )
+{
+ if ( (index<0) || (index>=p->count) )
+ return QSize();
+
+ RLE_SPRITE* sprite = p->sprites[index];
+ return QSize( sprite->w, sprite->h );
+}
+
+void RlePack::transferPalette( QImage& target )
+{
+ for ( int i=0; i<256; ++i )
+ {
+ target.setColor( i, qRgb( p->palette[i].r, p->palette[i].g, p->palette[i].b ) );
+ }
+}
diff --git a/editor/RlePack.h b/editor/RlePack.h
new file mode 100644
index 0000000..23eafd3
--- /dev/null
+++ b/editor/RlePack.h
@@ -0,0 +1,30 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#ifndef __RLEPACK_H
+#define __RLEPACK_H
+
+struct RlePack_P;
+
+class RlePack
+{
+public:
+ RlePack( const char* filename );
+ ~RlePack();
+
+// void offsetSprites( int offset );
+// SDL_Color* getPalette();
+ int count();
+ void draw( QImage& target, int index, int x, int y );
+ void transferPalette( QImage& target );
+ QSize getSize( int index );
+
+private:
+ RlePack_P* p;
+};
+
+#endif
diff --git a/editor/gif2dat.pl b/editor/gif2dat.pl
new file mode 100755
index 0000000..4a67153
--- /dev/null
+++ b/editor/gif2dat.pl
@@ -0,0 +1,119 @@
+#!/usr/bin/perl -w
+
+#
+# gif2dat.pl
+# For OpenMortal http://openmortal.sf.net
+#
+# The purpose of this script is converting an animated gif file
+# (usually, a character) into a dat and dat.txt files, usable by OpenMortal.
+# THIS PROGRAM COMES WITH NO WARRANTY OR SUPPORT OF ANY KIND.
+# It is intended to be an internal tool. If it works for you, lovely.
+#
+# The conversion requires:
+# libungif-progs package (Mandrake naming)
+# allegro (/usr/bin/dat tool required)
+#
+# The "magic number" is the transparent color in the gif (this will be
+# color 0 in the output file).
+#
+
+if (!$ARGV[0])
+{
+ print "Usage: $0 gifname [datname] [magiccolor]
+If datname is not supplied, gif2dat.dat and gif2dat.txt are written.
+The default magic color is 63\n";
+ die;
+}
+
+`rm _GIF* FRAME* PALETTE.PCX`;
+
+$gifname = $ARGV[0];
+$datname = $ARGV[1];
+$txtname = $datname ? "$datname.txt" : 'gif2dat.txt';
+$datname = 'gif2dat.dat' unless $datname;
+$trcolor = (defined $ARGV[2]) ? $ARGV[2] : 63;
+
+# Left = 273, Top = 149, Width = 133, Height = 300
+
+# *** Create text information
+print "$txtname\n";
+$giftext = `giftext $gifname`;
+open GIFTEXT, ">$txtname" || die "Couldn't open $giftext!\n";
+while ( $giftext=~/Image Size - Left = (\d+), Top = (\d+), Width = (\d+), Height = (\d+)/g ) {
+ printf GIFTEXT "{ 'x'=>%3d, 'y'=>%3d, 'w'=>%3d, 'h'=>%3d },\n", $1, $2, $3, $4;
+}
+close GIFTEXT;
+
+# *** Flip and append the image
+# `gifflip -y $gifname > _GIF2DATFLIP.GIF`;
+# `gifasm $gifname _GIF2DATFLIP.GIF > _GIF2DATASM.GIF`;
+
+print "$datname\n";
+
+
+# *** Translate transparent color to 0
+
+print "Translating transparent color $trcolor to 0.\n";
+
+open TRANS, ">_GIF2DATTRANS";
+#print TRANS "0 $trcolor\n";
+print TRANS "0 $trcolor\n";
+for ($i=1; $i<256; $i++)
+{
+ if ($i == $trcolor) { print TRANS "$i 0\n"; }
+ else { print TRANS "$i $i\n"; }
+}
+close TRANS;
+
+`gifclrmp -t _GIF2DATTRANS $gifname > _GIF2DATTMP.GIF`;
+
+# *** Split the gif up
+
+print "Splitting up the gif.\n";
+
+`gifasm -d _GIF2DATFRAME _GIF2DATTMP.GIF`;
+while(<_GIF2DATFRAME*.gif>)
+{
+ $frame = $_;
+ print "Converting $frame to $frame.pcx\n";
+ `convert $frame $frame.pcx`;
+}
+
+while (<_GIF2DATFRAME*.pcx>)
+{
+ ($i) = /(\d\d+)/;
+ $j = sprintf( "%03d", $i );
+ # print "FRAME$j.pcx\n";
+ `mv $_ FRAME$j.pcx`;
+}
+
+
+`cp FRAME000.pcx COLORS.PCX`;
+
+# *** dat cannot handle >256 files at a time..
+# Split it up into chunks, at most 50 files at a time.
+
+print "Saving images to .dat file with dat\n";
+
+@frames = `ls FRAME*`;
+chomp @frames;
+$i = $j = 0;
+
+while ( $i < scalar @frames )
+{
+ $command = "dat -v -c0 -a -t RLE $datname";
+ for ( $j = $i; $j< $i + 50; ++$j )
+ {
+ last if $j == scalar @frames;
+ $command .= " $frames[$j]";
+ }
+ $i = $j;
+ `$command`;
+}
+#`dat -v -c0 -a -t RLE $datname FRAME*`;
+
+#`dat -v -c0 -a -t RLE $datname FRAME* >&2`;
+`dat -v -c0 -a -t PAL $datname COLORS.PCX >&2`;
+`rm _GIF* FRAME* COLORS.PCX`;
+
+
diff --git a/editor/images/editcopy b/editor/images/editcopy
new file mode 100644
index 0000000..51ce930
Binary files /dev/null and b/editor/images/editcopy differ
diff --git a/editor/images/editcut b/editor/images/editcut
new file mode 100644
index 0000000..79c6f4b
Binary files /dev/null and b/editor/images/editcut differ
diff --git a/editor/images/editpaste b/editor/images/editpaste
new file mode 100644
index 0000000..87f55f5
Binary files /dev/null and b/editor/images/editpaste differ
diff --git a/editor/images/filenew b/editor/images/filenew
new file mode 100644
index 0000000..2886821
Binary files /dev/null and b/editor/images/filenew differ
diff --git a/editor/images/fileopen b/editor/images/fileopen
new file mode 100644
index 0000000..da6ec63
Binary files /dev/null and b/editor/images/fileopen differ
diff --git a/editor/images/filesave b/editor/images/filesave
new file mode 100644
index 0000000..cc9b609
Binary files /dev/null and b/editor/images/filesave differ
diff --git a/editor/images/print b/editor/images/print
new file mode 100644
index 0000000..670bee0
Binary files /dev/null and b/editor/images/print differ
diff --git a/editor/images/redo b/editor/images/redo
new file mode 100644
index 0000000..cbffac5
Binary files /dev/null and b/editor/images/redo differ
diff --git a/editor/images/searchfind b/editor/images/searchfind
new file mode 100644
index 0000000..1af77dc
Binary files /dev/null and b/editor/images/searchfind differ
diff --git a/editor/images/undo b/editor/images/undo
new file mode 100644
index 0000000..18b8ec0
Binary files /dev/null and b/editor/images/undo differ
diff --git a/editor/images/xrefresh.png b/editor/images/xrefresh.png
new file mode 100644
index 0000000..a8287fb
Binary files /dev/null and b/editor/images/xrefresh.png differ
diff --git a/editor/images/zoomin.png b/editor/images/zoomin.png
new file mode 100644
index 0000000..85b0650
Binary files /dev/null and b/editor/images/zoomin.png differ
diff --git a/editor/images/zoomout.png b/editor/images/zoomout.png
new file mode 100644
index 0000000..333af7c
Binary files /dev/null and b/editor/images/zoomout.png differ
diff --git a/editor/main.cpp b/editor/main.cpp
new file mode 100644
index 0000000..06dbcad
--- /dev/null
+++ b/editor/main.cpp
@@ -0,0 +1,18 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+#include <qapplication.h>
+#include "mortaleditor.h"
+
+int main( int argc, char ** argv )
+{
+ QApplication a( argc, argv );
+ MortalEditor *w = new MortalEditor;
+ w->show();
+ a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
+ return a.exec();
+}
diff --git a/editor/mortaleditor.ui b/editor/mortaleditor.ui
new file mode 100644
index 0000000..8e63835
--- /dev/null
+++ b/editor/mortaleditor.ui
@@ -0,0 +1,928 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>MortalEditor</class>
+<widget class="QMainWindow">
+ <property name="name">
+ <cstring>MortalEditor</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>786</width>
+ <height>931</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>MortalEditor</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>TabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Images</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>sbImage</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>tbZoomIn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>zoomin.png</iconset>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>tbZoomOut</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>zoomout.png</iconset>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lFrameName</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>???</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>cbExtrapolated</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Extrapolated</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string> HeadW:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>sbHeadW</cstring>
+ </property>
+ <property name="value">
+ <number>35</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string> HeadH:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>sbHeadH</cstring>
+ </property>
+ <property name="value">
+ <number>45</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string> BodyW:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>sbBodyW</cstring>
+ </property>
+ <property name="value">
+ <number>55</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string> Body%:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>sbBodyP</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lImage</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Names</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTextEdit" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>teFrames</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>applyFrames</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Apply</string>
+ </property>
+ </widget>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>Spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>121</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>Spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>191</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Detection</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>191</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="1">
+ <property name="name">
+ <cstring>Spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>271</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Detection parameters</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>SpinBox2</cstring>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Body %</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Head height</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>SpinBox3</cstring>
+ </property>
+ <property name="minValue">
+ <number>50</number>
+ </property>
+ </widget>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>Spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>111</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>101</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<menubar>
+ <property name="name">
+ <cstring>menubar</cstring>
+ </property>
+ <item text="&amp;File" name="fileMenu">
+ <action name="fileOpenAction"/>
+ <action name="fileSaveAction"/>
+ <action name="fileSaveAsAction"/>
+ <separator/>
+ <action name="filePrintAction"/>
+ <separator/>
+ <action name="fileExitAction"/>
+ </item>
+ <item text="&amp;Edit" name="editMenu">
+ <action name="editUndoAction"/>
+ <action name="editRedoAction"/>
+ <separator/>
+ <action name="editCutAction"/>
+ <action name="editCopyAction"/>
+ <action name="editPasteAction"/>
+ <action name="copyPrevious"/>
+ <separator/>
+ <action name="editFindAction"/>
+ </item>
+ <item text="&amp;Help" name="helpMenu">
+ <action name="helpContentsAction"/>
+ <action name="helpIndexAction"/>
+ <separator/>
+ <action name="helpAboutAction"/>
+ </item>
+</menubar>
+<toolbars>
+ <toolbar dock="2">
+ <property name="name">
+ <cstring>toolBar</cstring>
+ </property>
+ <property name="label">
+ <string>Tools</string>
+ </property>
+ <action name="fileOpenAction"/>
+ <action name="fileSaveAction"/>
+ <action name="editUndoAction"/>
+ <action name="editRedoAction"/>
+ <action name="editCopyAction"/>
+ <action name="editPasteAction"/>
+ <action name="copyPrevious"/>
+ </toolbar>
+</toolbars>
+<actions>
+ <action>
+ <property name="name">
+ <cstring>fileNewAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>filenew</iconset>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;New</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileOpenAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>fileopen</iconset>
+ </property>
+ <property name="text">
+ <string>Open</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Open...</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileSaveAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>filesave</iconset>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Save</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileSaveAsAction</cstring>
+ </property>
+ <property name="text">
+ <string>Save As</string>
+ </property>
+ <property name="menuText">
+ <string>Save &amp;As...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>filePrintAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>print</iconset>
+ </property>
+ <property name="text">
+ <string>Print</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Print...</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+P</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileExitAction</cstring>
+ </property>
+ <property name="text">
+ <string>Exit</string>
+ </property>
+ <property name="menuText">
+ <string>E&amp;xit</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editUndoAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>undo</iconset>
+ </property>
+ <property name="text">
+ <string>Undo</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Undo</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+Z</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editRedoAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>redo</iconset>
+ </property>
+ <property name="text">
+ <string>Redo</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Redo</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+Y</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editCutAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>editcut</iconset>
+ </property>
+ <property name="text">
+ <string>Cut</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Cut</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+X</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editCopyAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>editcopy</iconset>
+ </property>
+ <property name="text">
+ <string>Copy</string>
+ </property>
+ <property name="menuText">
+ <string>C&amp;opy</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+C</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editPasteAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>editpaste</iconset>
+ </property>
+ <property name="text">
+ <string>Paste</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Paste</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+V</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editFindAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>searchfind</iconset>
+ </property>
+ <property name="text">
+ <string>Find</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Find...</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+F</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpContentsAction</cstring>
+ </property>
+ <property name="text">
+ <string>Contents</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Contents...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpIndexAction</cstring>
+ </property>
+ <property name="text">
+ <string>Index</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Index...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpAboutAction</cstring>
+ </property>
+ <property name="text">
+ <string>About</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;About...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>copyPrevious</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>xrefresh.png</iconset>
+ </property>
+ <property name="text">
+ <string>Copy Previous</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Copy Previous</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+P</string>
+ </property>
+ </action>
+</actions>
+<connections>
+ <connection>
+ <sender>fileNewAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>fileNew()</slot>
+ </connection>
+ <connection>
+ <sender>fileOpenAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>fileOpen()</slot>
+ </connection>
+ <connection>
+ <sender>fileSaveAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>fileSave()</slot>
+ </connection>
+ <connection>
+ <sender>fileSaveAsAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>fileSaveAs()</slot>
+ </connection>
+ <connection>
+ <sender>filePrintAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>filePrint()</slot>
+ </connection>
+ <connection>
+ <sender>fileExitAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>fileExit()</slot>
+ </connection>
+ <connection>
+ <sender>editUndoAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>editUndo()</slot>
+ </connection>
+ <connection>
+ <sender>editRedoAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>editRedo()</slot>
+ </connection>
+ <connection>
+ <sender>editCutAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>editCut()</slot>
+ </connection>
+ <connection>
+ <sender>editCopyAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>editCopy()</slot>
+ </connection>
+ <connection>
+ <sender>editPasteAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>editPaste()</slot>
+ </connection>
+ <connection>
+ <sender>editFindAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>editFind()</slot>
+ </connection>
+ <connection>
+ <sender>helpIndexAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>helpIndex()</slot>
+ </connection>
+ <connection>
+ <sender>helpContentsAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>helpContents()</slot>
+ </connection>
+ <connection>
+ <sender>helpAboutAction</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>helpAbout()</slot>
+ </connection>
+ <connection>
+ <sender>sbImage</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>sbImage_valueChanged(int)</slot>
+ </connection>
+ <connection>
+ <sender>cbExtrapolated</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>cbExtrapolated_toggled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>tbZoomIn</sender>
+ <signal>clicked()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>tbZoomIn_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>tbZoomOut</sender>
+ <signal>clicked()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>tbZoomOut_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>applyFrames</sender>
+ <signal>clicked()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>applyFrames_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>sbHeadW</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>detectionParamChanged()</slot>
+ </connection>
+ <connection>
+ <sender>sbHeadH</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>detectionParamChanged()</slot>
+ </connection>
+ <connection>
+ <sender>sbBodyW</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>detectionParamChanged()</slot>
+ </connection>
+ <connection>
+ <sender>sbBodyP</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>detectionParamChanged()</slot>
+ </connection>
+ <connection>
+ <sender>copyPrevious</sender>
+ <signal>activated()</signal>
+ <receiver>MortalEditor</receiver>
+ <slot>copyPrevious_activated()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in declaration">qstringlist.h</include>
+ <include location="local" impldecl="in implementation">mortaleditor.ui.h</include>
+</includes>
+<forwards>
+ <forward>struct ImageData;</forward>
+ <forward>class QImage;</forward>
+ <forward>class RlePack;</forward>
+ <forward>class ImageEditor;</forward>
+</forwards>
+<variables>
+ <variable>QString m_sFileName;</variable>
+ <variable>int currentImage;</variable>
+ <variable>QImage* image;</variable>
+ <variable>RlePack* images;</variable>
+ <variable>ImageEditor* imageEditor;</variable>
+ <variable>QStringList frameNames;</variable>
+</variables>
+<slots>
+ <slot>init()</slot>
+ <slot>load()</slot>
+ <slot>fileNew()</slot>
+ <slot>fileOpen()</slot>
+ <slot>fileSave()</slot>
+ <slot>fileSaveAs()</slot>
+ <slot>filePrint()</slot>
+ <slot>fileExit()</slot>
+ <slot>editUndo()</slot>
+ <slot>editRedo()</slot>
+ <slot>editCut()</slot>
+ <slot>editCopy()</slot>
+ <slot>editPaste()</slot>
+ <slot>editFind()</slot>
+ <slot>helpIndex()</slot>
+ <slot>helpContents()</slot>
+ <slot>helpAbout()</slot>
+ <slot>transferImage()</slot>
+ <slot>sbImage_valueChanged( int i )</slot>
+ <slot>cbExtrapolated_toggled( bool ex )</slot>
+ <slot>imageEditor_extrapolated( bool ex )</slot>
+ <slot>tbZoomIn_clicked()</slot>
+ <slot>tbZoomOut_clicked()</slot>
+ <slot>applyFrames_clicked()</slot>
+ <slot>updatelFrameName()</slot>
+ <slot>detectionParamChanged()</slot>
+ <slot>copyPrevious_activated()</slot>
+</slots>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/editor/mortaleditor.ui.h b/editor/mortaleditor.ui.h
new file mode 100644
index 0000000..b276f4d
--- /dev/null
+++ b/editor/mortaleditor.ui.h
@@ -0,0 +1,297 @@
+/***************************************************************************
+This file is part of MortalEditor, the OpenMortal character editor.
+This is an internal tool, no warranty or support. Use at your own risk.
+
+Copyright 2004 UPi upi@sourceforge
+ ***************************************************************************/
+
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename slots use Qt Designer which will
+** update this file, preserving your code. Create an init() slot in place of
+** a constructor, and a destroy() slot in place of a destructor.
+*****************************************************************************/
+
+#ifndef QIMAGE_H
+#include <qimage.h>
+#endif
+#ifndef QWMATRIX_H
+#include <qwmatrix.h>
+#endif
+#include <qfiledialog.h>
+
+#include "RlePack.h"
+#include "ImageEditor.h"
+#include "ImageStorage.h"
+
+// #define CHARNAME "CUMI"
+
+
+bool bLoaded = false;
+#define CHECKLOADED if ( !bLoaded ) return;
+
+
+void MortalEditor::init()
+{
+ // Load images and image4 data
+ images = NULL;
+ m_sFileName = "";
+
+ // Set up widgets
+ lImage->hide();
+ QCanvas *c = new QCanvas( this );
+ c->resize( 1000, 700 );
+ imageEditor = new ImageEditor( tab );
+ imageEditor->setCanvas( c );
+ imageEditor->setSizePolicy( QSizePolicy(
+ (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)5, 0, false ) );
+ imageEditor->setFrameShape( QLabel::Panel );
+ imageEditor->setFrameShadow( QLabel::Plain );
+ imageEditor->setLineWidth( 1 );
+ tabLayout->addWidget( imageEditor );
+
+ connect( imageEditor, SIGNAL(extrapolated(bool)),
+ this, SLOT(imageEditor_extrapolated(bool)) );
+
+}
+
+void MortalEditor::load( )
+{
+ delete images;
+ images = new RlePack( m_sFileName );
+ ImageStorage::instance().load( m_sFileName + ".txt" );
+ bLoaded = true;
+ currentImage = 0;
+ sbImage->setMaxValue( images->count()-1 );
+ sbImage->setValue(0);
+ transferImage();
+}
+
+void MortalEditor::fileNew()
+{
+
+}
+
+void MortalEditor::fileOpen()
+{
+ QString sOpen = QFileDialog::getOpenFileName ( QString::null, QString::null, this );
+ if ( sOpen.isEmpty() )
+ {
+ return;
+ }
+ m_sFileName = sOpen;
+ load();
+}
+
+void MortalEditor::fileSave()
+{
+ CHECKLOADED;
+ ImageStorage::instance().save( m_sFileName + ".txt", images );
+}
+
+void MortalEditor::fileSaveAs()
+{
+
+}
+
+void MortalEditor::filePrint()
+{
+
+}
+
+void MortalEditor::fileExit()
+{
+
+}
+
+void MortalEditor::editUndo()
+{
+
+}
+
+void MortalEditor::editRedo()
+{
+
+}
+
+void MortalEditor::editCut()
+{
+
+}
+
+void MortalEditor::editCopy()
+{
+
+}
+
+void MortalEditor::editPaste()
+{
+
+}
+
+void MortalEditor::editFind()
+{
+
+}
+
+void MortalEditor::helpIndex()
+{
+
+}
+
+void MortalEditor::helpContents()
+{
+
+}
+
+void MortalEditor::helpAbout()
+{
+
+}
+
+void MortalEditor::transferImage()
+{
+ CHECKLOADED;
+
+ QSize size = images->getSize( currentImage );
+ QImage image( size, 8, 256 );
+ images->transferPalette( image );
+ image.fill( 0 );
+ images->draw( image, currentImage, 0, 0 );
+ image.setAlphaBuffer( true );
+ image.setColor( 0, qRgba( 0,0,0,0 ) );
+
+ ImageData data = ImageStorage::instance().getImageData( currentImage, images );
+
+ imageEditor->setImage( image );
+ imageEditor->setData( data );
+}
+
+void MortalEditor::sbImage_valueChanged( int i )
+{
+ CHECKLOADED;
+
+ ImageData data = imageEditor->getData();
+ debug( "Data %d extrapolated=%d", currentImage, data.isExtrapolated );
+ ImageStorage::instance().setImageData( currentImage, data );
+
+ currentImage = i;
+ transferImage();
+ updatelFrameName();
+}
+
+void MortalEditor::cbExtrapolated_toggled( bool ex )
+{
+ CHECKLOADED;
+
+ if ( ex )
+ {
+ ImageData data;
+ ImageStorage::instance().setImageData( currentImage, data );
+ transferImage();
+ }
+ else
+ {
+ ImageData data = imageEditor->getData();
+ data.isExtrapolated = false;
+ }
+}
+
+void MortalEditor::imageEditor_extrapolated( bool ex )
+{
+ CHECKLOADED;
+ cbExtrapolated->blockSignals( true );
+ cbExtrapolated->setChecked( ex );
+ cbExtrapolated->blockSignals( false );
+}
+
+
+void MortalEditor::tbZoomIn_clicked()
+{
+ CHECKLOADED;
+ QWMatrix wm = imageEditor->worldMatrix();
+ double _zoom = wm.m11();
+ if ( _zoom >= 1.0 )
+ {
+ _zoom += 1.0;
+ wm.setMatrix( _zoom, 0, 0, _zoom, 0, 0 );
+ }
+ else
+ {
+ wm.scale( 2.0, 2.0 );
+ }
+
+ imageEditor->setWorldMatrix( wm );
+}
+
+
+
+void MortalEditor::tbZoomOut_clicked()
+{
+ CHECKLOADED;
+ QWMatrix wm = imageEditor->worldMatrix();
+ double _zoom = wm.m11();
+ if ( _zoom > 1.0 )
+ {
+ _zoom -= 1.0;
+ wm.setMatrix( _zoom, 0, 0, _zoom, 0, 0 );
+ }
+ else
+ {
+ wm.scale( 0.5, 0.5 );
+ }
+
+ imageEditor->setWorldMatrix( wm );
+}
+
+
+void MortalEditor::applyFrames_clicked()
+{
+ CHECKLOADED;
+ frameNames.clear();
+ QStringList sl = QStringList::split( ',', teFrames->text() );
+ QString s;
+
+ for ( int i=0; i<sl.count()-1; i+=2 )
+ {
+ QString name = sl[i].stripWhiteSpace();
+
+ int n = sl[i+1].toInt();
+
+ for ( int j=0; j<n; ++j )
+ {
+ s = name + QString::number(j+1);
+ frameNames.push_back(s);
+ }
+ }
+
+ updatelFrameName();
+}
+
+void MortalEditor::updatelFrameName()
+{
+ CHECKLOADED;
+ int i = sbImage->value();
+
+ if ( i>= frameNames.count() )
+ {
+ lFrameName->setText( "???" );
+ }
+ else
+ {
+ lFrameName->setText( frameNames[i] );
+ }
+}
+
+void MortalEditor::detectionParamChanged()
+{
+ CHECKLOADED;
+ ImageStorage::instance().setDetectionParams(
+ sbHeadW->value(),
+ sbHeadH->value(),
+ sbBodyW->value(),
+ double(sbBodyP->value()) / 100.0 );
+ transferImage();
+ updatelFrameName();
+}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 15, 11:26 PM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72014
Default Alt Text
(82 KB)

Event Timeline