Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F130239
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
82 KB
Referenced Files
None
Subscribers
None
View Options
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>&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>&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>&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>&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="&File" name="fileMenu">
+ <action name="fileOpenAction"/>
+ <action name="fileSaveAction"/>
+ <action name="fileSaveAsAction"/>
+ <separator/>
+ <action name="filePrintAction"/>
+ <separator/>
+ <action name="fileExitAction"/>
+ </item>
+ <item text="&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="&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>&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>&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>&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 &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>&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&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>&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>&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>&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&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>&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>&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>&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>&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>&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>&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
Details
Attached
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)
Attached To
Mode
R76 OpenMortal
Attached
Detach File
Event Timeline