You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
598 lines
9.7 KiB
598 lines
9.7 KiB
#include "nex.h"
|
|
#include "gui.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <tdeapplication.h>
|
|
#include <tdeaboutdata.h>
|
|
#include <tdecmdlineargs.h>
|
|
#include <tdelocale.h>
|
|
|
|
#include <tqlayout.h>
|
|
#include <tqlabel.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tqmultilineedit.h>
|
|
|
|
#include "renderers.h"
|
|
|
|
Mutex runLock;
|
|
Nex *Nex::sNex=0;
|
|
TQTime timer;
|
|
|
|
Renderer::Renderer() {}
|
|
Renderer::~Renderer() {}
|
|
|
|
Thread::Thread() : mThread(0)
|
|
{
|
|
|
|
}
|
|
|
|
Thread::~Thread()
|
|
{
|
|
if (mThread)
|
|
kill();
|
|
}
|
|
|
|
void Thread::start()
|
|
{
|
|
mThread=SDL_CreateThread(&threadRun, (void*)this);
|
|
}
|
|
|
|
void Thread::kill()
|
|
{
|
|
SDL_KillThread(mThread);
|
|
}
|
|
|
|
int Thread::wait()
|
|
{
|
|
int val;
|
|
SDL_WaitThread(mThread, &val);
|
|
return val;
|
|
}
|
|
|
|
int Thread::threadRun(void *v)
|
|
{
|
|
Thread *t=(Thread*)v;
|
|
return t->run();
|
|
}
|
|
|
|
NexCheckBox::NexCheckBox(TQWidget *parent,
|
|
const TQString &name, bool *v)
|
|
: TQCheckBox(name, parent)
|
|
{
|
|
value=v;
|
|
setChecked(*v);
|
|
connect(this, TQT_SIGNAL(toggled(bool)), TQT_SLOT(change(bool)));
|
|
}
|
|
void NexCheckBox::change(bool b)
|
|
{
|
|
*value=b;
|
|
}
|
|
|
|
|
|
|
|
NexColorButton::NexColorButton(TQWidget *parent, Pixel *color)
|
|
: KColorButton(parent)
|
|
{
|
|
c=color;
|
|
TQColor temp( (*c >> 16) & 0xFF, (*c >> 8) & 0xFF, *c & 0xFF);
|
|
setColor(temp);
|
|
connect(this, TQT_SIGNAL(changed(const TQColor&)), TQT_SLOT(change(const TQColor&)));
|
|
}
|
|
|
|
void NexColorButton::change(const TQColor &co)
|
|
{
|
|
*c= COLOR(tqRed(co.rgb()), tqGreen(co.rgb()), tqBlue(co.rgb()));
|
|
}
|
|
|
|
void Bitmap::resize(int w, int h)
|
|
{
|
|
delete [] mData;
|
|
mData=new Pixel[w*h];
|
|
}
|
|
|
|
void Bitmap::clear()
|
|
{
|
|
memset(mData, 0, bytes());
|
|
}
|
|
|
|
void Bitmap::drawCircle(int x, int y, int r, Pixel color)
|
|
{
|
|
int16_t cx = 0;
|
|
int16_t cy = r;
|
|
int16_t ocx = -1;
|
|
int16_t ocy = -1;
|
|
int16_t df = 1 - r;
|
|
int16_t d_e = 3;
|
|
int16_t d_se = -2 * r + 5;
|
|
int16_t xpcx, xmcx, xpcy, xmcy;
|
|
int16_t ypcy, ymcy, ypcx, ymcx;
|
|
|
|
do
|
|
{ // Draw
|
|
if ((ocy!=cy) || (ocx!=cx))
|
|
{
|
|
xpcx=x+cx;
|
|
xmcx=x-cx;
|
|
if (cy>0)
|
|
{
|
|
ypcy=y+cy;
|
|
ymcy=y-cy;
|
|
setPixel(xmcx,ypcy,color);
|
|
setPixel(xpcx,ypcy,color);
|
|
setPixel(xmcx,ymcy,color);
|
|
setPixel(xpcx,ymcy,color);
|
|
}
|
|
else
|
|
{
|
|
setPixel(xmcx,y,color);
|
|
setPixel(xpcx,y,color);
|
|
}
|
|
|
|
ocy=cy;
|
|
xpcy=x+cy;
|
|
xmcy=x-cy;
|
|
if (cx>0)
|
|
{
|
|
ypcx=y+cx;
|
|
ymcx=y-cx;
|
|
setPixel(xmcy,ypcx,color);
|
|
setPixel(xpcy,ypcx,color);
|
|
setPixel(xmcy,ymcx,color);
|
|
setPixel(xpcy,ymcx,color);
|
|
}
|
|
else
|
|
{
|
|
setPixel(xmcy,y,color);
|
|
setPixel(xpcy,y,color);
|
|
}
|
|
ocx=cx;
|
|
}
|
|
// Update
|
|
if (df < 0)
|
|
{
|
|
df += d_e;
|
|
d_e += 2;
|
|
d_se += 2;
|
|
}
|
|
else
|
|
{
|
|
df += d_se;
|
|
d_e += 2;
|
|
d_se += 4;
|
|
cy--;
|
|
}
|
|
cx++;
|
|
} while(cx <= cy);
|
|
}
|
|
|
|
|
|
void Bitmap::fillCircle(int x, int y, int r, Pixel color)
|
|
{
|
|
int16_t cx = 0;
|
|
int16_t cy = r;
|
|
int16_t ocx = -1;
|
|
int16_t ocy = -1;
|
|
int16_t df = 1 - r;
|
|
int16_t d_e = 3;
|
|
int16_t d_se = -2 * r + 5;
|
|
int16_t xpcx, xmcx, xpcy, xmcy;
|
|
int16_t ypcy, ymcy, ypcx, ymcx;
|
|
|
|
do
|
|
{ // Draw
|
|
if ((ocy!=cy) || (ocx!=cx))
|
|
{
|
|
xpcx=x+cx;
|
|
xmcx=x-cx;
|
|
if (cy>0)
|
|
{
|
|
ypcy=y+cy;
|
|
ymcy=y-cy;
|
|
setPixel(xmcx,ypcy,color);
|
|
setPixel(xpcx,ypcy,color);
|
|
setPixel(xmcx,ymcy,color);
|
|
setPixel(xpcx,ymcy,color);
|
|
for (int h=xmcx; h<xpcx; h++)
|
|
setPixel(h, ypcy, color);
|
|
|
|
for (int h=xmcx; h<xpcx; h++)
|
|
setPixel(h, ymcy, color);
|
|
}
|
|
else
|
|
{
|
|
setPixel(xmcx,y,color);
|
|
setPixel(xpcx,y,color);
|
|
for (int h=xmcx; h<xpcx; h++)
|
|
setPixel(h, y, color);
|
|
}
|
|
|
|
|
|
ocy=cy;
|
|
xpcy=x+cy;
|
|
xmcy=x-cy;
|
|
if (cx>0)
|
|
{
|
|
ypcx=y+cx;
|
|
ymcx=y-cx;
|
|
setPixel(xmcy,ypcx,color);
|
|
setPixel(xpcy,ypcx,color);
|
|
setPixel(xmcy,ymcx,color);
|
|
setPixel(xpcy,ymcx,color);
|
|
for (int h=xmcy; h<xpcy; h++)
|
|
setPixel(h, ypcx, color);
|
|
|
|
for (int h=xmcy; h<xpcy; h++)
|
|
setPixel(h, ymcx, color);
|
|
}
|
|
else
|
|
{
|
|
setPixel(xmcy,y,color);
|
|
setPixel(xpcy,y,color);
|
|
for (int h=xmcy; h<xpcy; h++)
|
|
setPixel(h, y, color);
|
|
}
|
|
ocx=cx;
|
|
}
|
|
// Update
|
|
if (df < 0)
|
|
{
|
|
df += d_e;
|
|
d_e += 2;
|
|
d_se += 2;
|
|
}
|
|
else
|
|
{
|
|
df += d_se;
|
|
d_e += 2;
|
|
d_se += 4;
|
|
cy--;
|
|
}
|
|
cx++;
|
|
} while(cx <= cy);
|
|
}
|
|
|
|
|
|
void Bitmap::drawLine(int x1, int y1, int x2, int y2, Pixel color)
|
|
{
|
|
// Variable setup
|
|
int dx = x2 - x1;
|
|
int sx = (dx >= 0) ? 1 : -1;
|
|
dx = sx * dx + 1;
|
|
|
|
int dy = y2 - y1;
|
|
int sy = (dy >= 0) ? 1 : -1;
|
|
dy = sy * dy + 1;
|
|
|
|
|
|
int pixx = sizeof(Pixel);
|
|
int pixy = width*sizeof(Pixel);
|
|
uint8_t *pixel = (uint8_t*)pixels() + pixx * x1 + pixy * y1;
|
|
pixx *= sx;
|
|
pixy *= sy;
|
|
|
|
if (dx < dy)
|
|
{
|
|
int swaptmp = dx;
|
|
dx = dy;
|
|
dy = swaptmp;
|
|
swaptmp = pixx;
|
|
pixx = pixy;
|
|
pixy = swaptmp;
|
|
}
|
|
|
|
|
|
// Draw
|
|
int y=0;
|
|
|
|
for(int x=0; x < dx; x++, pixel += pixx)
|
|
{
|
|
*(Pixel*)pixel=color;
|
|
y += dy;
|
|
if (y >= dx)
|
|
{
|
|
y -= dx;
|
|
pixel += pixy;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
RendererList::RendererList() : mClearAfter(false)
|
|
{
|
|
mFrame=nex->bitmapPool()->get(true);
|
|
}
|
|
|
|
RendererList::~RendererList()
|
|
{
|
|
nex->bitmapPool()->release(mFrame);
|
|
}
|
|
|
|
Bitmap *RendererList::render(float *pcm[4], Bitmap *source)
|
|
{
|
|
if (mClearAfter) mFrame->clear();
|
|
|
|
lock();
|
|
for (TQPtrListIterator<Renderer> i(mRendererList); i.current(); ++i)
|
|
{
|
|
Bitmap *newframe=(*i)->render(pcm, mFrame);
|
|
|
|
if (newframe!=mFrame)
|
|
{
|
|
nex->bitmapPool()->release(mFrame);
|
|
mFrame=newframe;
|
|
}
|
|
}
|
|
|
|
unlock();
|
|
|
|
// add source+=source; return source;
|
|
|
|
uint8_t *d=(uint8_t*)source->pixels();
|
|
uint8_t *end=(uint8_t*)((uint8_t*)d+source->bytes());
|
|
uint8_t *s=(uint8_t*)mFrame->pixels();
|
|
|
|
while (d<end)
|
|
{
|
|
register int dest=*d;
|
|
if (dest && ((dest | *s) & 128))
|
|
{
|
|
// there's danger of going past 0xFF
|
|
dest+=*s;
|
|
if (dest & 256)
|
|
*d=0xFF; // oops, we did!
|
|
else
|
|
*d=dest;
|
|
}
|
|
else
|
|
{
|
|
// if neither touch the 128th bit, then the sum
|
|
// can't possibly be more than 0xFF
|
|
*d=dest+*s;
|
|
}
|
|
|
|
|
|
++s;
|
|
++d;
|
|
}
|
|
|
|
return source;
|
|
}
|
|
|
|
void RendererList::save(TQDomElement &e)
|
|
{
|
|
lock();
|
|
e.setTagName("List");
|
|
|
|
for (TQPtrListIterator<Renderer> i(mRendererList); *i; ++i)
|
|
{
|
|
TQDomElement item;
|
|
(*i)->save(item);
|
|
e.appendChild(item);
|
|
}
|
|
|
|
unlock();
|
|
}
|
|
|
|
void RendererList::load(const TQDomElement &e)
|
|
{
|
|
lock();
|
|
|
|
for (TQDomNode n=e.firstChild(); !n.isNull(); n=n.nextSibling())
|
|
{
|
|
if (!n.isElement()) continue;
|
|
TQDomElement child=n.toElement();
|
|
|
|
Renderer *r=0;
|
|
|
|
if (e.tagName()=="List")
|
|
r=new RendererList;
|
|
else
|
|
r=nex->renderer(e.tagName());
|
|
|
|
if (!r) continue;
|
|
|
|
r->load(child);
|
|
mRendererList.append(r);
|
|
}
|
|
|
|
unlock();
|
|
}
|
|
|
|
|
|
|
|
TQWidget *RendererList::configure(TQWidget *parent)
|
|
{
|
|
return new RendererListConfigurator(this, parent);
|
|
}
|
|
|
|
RendererListConfigurator::RendererListConfigurator(RendererList *l, TQWidget *parent)
|
|
: TQWidget(parent), mList(l)
|
|
{
|
|
(new TQVBoxLayout(this))->setAutoAdd(true);
|
|
mErase=new TQCheckBox(i18n("&Erase between frames"), this);
|
|
connect(mErase, TQT_SIGNAL(toggled(bool)), TQT_SLOT(eraseOn(bool)));
|
|
mErase->setChecked(mList->mClearAfter);
|
|
|
|
if (nex->rendererList()==l)
|
|
{
|
|
TQCheckBox *mConvolve=new TQCheckBox(i18n("&Convolve audio"), this);
|
|
connect(mConvolve, TQT_SIGNAL(toggled(bool)), TQT_SLOT(convolve(bool)));
|
|
mConvolve->setChecked(nex->input()->convolve());
|
|
}
|
|
|
|
new TQLabel(i18n("Comments"), this);
|
|
|
|
mComments=new TQMultiLineEdit(this);
|
|
mComments->setText(l->mComments);
|
|
mComments->setWordWrap(TQMultiLineEdit::WidgetWidth);
|
|
}
|
|
|
|
RendererListConfigurator::~RendererListConfigurator()
|
|
{
|
|
mList->mComments=mComments->text();
|
|
}
|
|
|
|
void RendererListConfigurator::eraseOn(bool state)
|
|
{
|
|
mList->mClearAfter=state;
|
|
}
|
|
|
|
void RendererListConfigurator::convolve(bool state)
|
|
{
|
|
nex->input()->setConvolve(state);
|
|
}
|
|
|
|
|
|
|
|
#define INSERT(name, func) mCreators.insert(name, new CreatorSig*(&func))
|
|
|
|
Nex::Nex()
|
|
{
|
|
sNex=this;
|
|
mBitmapPool=0;
|
|
mRendererList=0;
|
|
|
|
setupSize(width, height);
|
|
|
|
INSERT("Fade", Creators::fade);
|
|
INSERT("Doubler", Creators::doubler);
|
|
INSERT("Waveform", Creators::waveform);
|
|
INSERT("Hartley", Creators::hartley);
|
|
}
|
|
#undef INSERT
|
|
|
|
void Nex::setupSize(int , int )
|
|
{
|
|
mInput=new Input;
|
|
delete mBitmapPool;
|
|
delete mRendererList;
|
|
mBitmapPool=new BitmapPool();
|
|
mRendererList=new RendererList;
|
|
}
|
|
|
|
Nex::~Nex()
|
|
{
|
|
delete mRendererList;
|
|
delete mBitmapPool;
|
|
}
|
|
|
|
#define NOTHREAD
|
|
|
|
void Nex::go()
|
|
{
|
|
runLock.unlock();
|
|
float *audio[6];
|
|
|
|
Bitmap *frame;
|
|
frame=mBitmapPool->get(true);
|
|
|
|
int frames=0;
|
|
TQTime start(TQTime::currentTime());
|
|
|
|
while (1)
|
|
{
|
|
mInput->getAudio(audio);
|
|
mRendererList->render(audio, frame);
|
|
int result=mOutput.display(frame);
|
|
|
|
frames++;
|
|
|
|
switch (result)
|
|
{
|
|
case OutputSDL::Exit:
|
|
std::cerr << "Trying" << std::endl;
|
|
delete mInput;
|
|
std::cerr << "Deleted" << std::endl;
|
|
|
|
std::cout << "Frames per Second: "
|
|
<< frames/start.secsTo(TQTime::currentTime()) << std::endl;
|
|
return;
|
|
case OutputSDL::Resize:
|
|
// setupSize(width, height);
|
|
break;
|
|
}
|
|
#ifdef NOTHREAD
|
|
kapp->processEvents();
|
|
#endif
|
|
frame->clear();
|
|
}
|
|
}
|
|
|
|
|
|
Renderer *Nex::renderer(const TQString &name)
|
|
{
|
|
CreatorSig **sig=mCreators[name];
|
|
if (sig)
|
|
return (**sig)();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
TQStringList Nex::renderers() const
|
|
{
|
|
TQDictIterator<CreatorSig*> i(mCreators);
|
|
TQStringList list;
|
|
|
|
for (;i.current(); ++i)
|
|
list += i.currentKey();
|
|
|
|
return list;
|
|
}
|
|
|
|
|
|
#ifndef NOTHREAD
|
|
class VisThread : public Thread
|
|
{
|
|
public:
|
|
virtual int run()
|
|
{
|
|
Nex::sNex->go();
|
|
exit(0);
|
|
return 0;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
Nex theNex;
|
|
Nex::sNex=&theNex;
|
|
|
|
#ifndef NOTHREAD
|
|
runLock.lock();
|
|
|
|
VisThread vis;
|
|
vis.start();
|
|
|
|
runLock.lock();
|
|
#endif
|
|
|
|
TDEAboutData aboutData("nex", I18N_NOOP("Nex"), "0.0.1",
|
|
I18N_NOOP("The awesome customizable scope"),
|
|
TDEAboutData::License_LGPL, "(C) 2001 Charles Samuels", 0,
|
|
"http://noatun.kde.org");
|
|
|
|
aboutData.addAuthor("Charles Samuels", I18N_NOOP("Nex Author"),
|
|
"charles@kde.org");
|
|
|
|
TDECmdLineArgs::init( argc, argv, &aboutData );
|
|
TDEApplication app;
|
|
|
|
|
|
(new Control)->show();
|
|
#ifdef NOTHREAD
|
|
theNex.go();
|
|
|
|
#else
|
|
app.exec();
|
|
|
|
vis.wait();
|
|
#endif
|
|
exit(0); //prevent segfault on exit, for some reason
|
|
return 0;
|
|
}
|
|
|
|
#include "nex.moc"
|
|
|