Module: qscroll.cpp

Flat functions
 

BenchCPvoid BenchCP(char *s);
BenchCPvoid BenchCP(char *s)

class QScroller
.h

constructorQScroller(QCanvas *icv,QRect *r)
destructor~QScroller()
GetGelQBob *GetGel(int index)
Addbool Add(QBob *ngel)
ScrollGelvoid ScrollGel(QBob *gel,int vx,int vy)
Scrollvoid Scroll(int vx,int vy)

Flat functions
 

scrollDemovoid scrollDemo()

For qtest



/*
 * QScroll - vertical gel (Bobs/Texts) scroller
 * NOTES:
 * - To be enhanced into a usable Q class
 * 23-04-97: Created!
 * (C) MG/RVG
 */

#include <qlib/scroll.h>
#include <GL/gl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <qlib/filter.h>
#include <qlib/debug.h>
DEBUG_ENABLE

// Due to something in 5.3 OpenGL, copying from front to back or vice versa
// is a lot slower in OpenGL (not in GL)
// Define SAMEBUF will use more intelligent double buffered scrolling
// techniques to keep the copies from BACK to BACK or FRONT to FRONT.
//#define SAMEBUF

void BenchCP(char *s);

// Define ONE_STEP to scroll the entire PAL area, instead of per-gel
// If speedy enough, ONE_STEP should work for worst-case scrollers
// where this entire screen is filled with tiny things.
#define ONE_STEP
//#define BENCH

#define MAX_GEL		100	// Initially

#ifdef BENCH
void BenchCP(char *s)
{ proftime_t t;
  int i;
  printf("BenchCP(%s)\n",s);
  glDisable(GL_BLEND);
  glFinish();
  profStart(&t);
  for(i=0;i<100;i++)
  {
    glRasterPos2i(300,300);
    glCopyPixels(200,200,294,38,GL_COLOR);
    //glFinish();
  }
  profReport(&t,"glCopyPixels 294x38");
  //printf("BenchCP ret\n");
}
#endif

QScroller::QScroller(QCanvas *icv,QRect *r)
{
  //QWidget *wg;
  curX=curY=0;
  cv=icv;
  // Scroll area
  if(r==0)
  { //wg=cv->GetWidget();
    area.x=0; area.y=0;
    //area.wid=wg->GetWidth(); area.hgt=wg->GetHeight();
    area.wid=768; area.hgt=576;
  } else
  { area.x=r->x; area.y=r->y;
    area.wid=r->wid; area.hgt=r->hgt;
  }
  maxGel=MAX_GEL;
  gel=(QBob**)qcalloc(sizeof(QBob*)*maxGel);
  gels=0;
}
QScroller::~QScroller()
{
  if(gel)qfree(gel);
}

QBob *QScroller::GetGel(int index)
{
  if(index<0||index>=gels)
    return 0;
  return gel[index];
}

bool QScroller::Add(QBob *ngel)
{
  if(gels>=maxGel)
  { qwarn("QScroller::Add: no more space for new gels\n");
    return FALSE;
  }
  gel[gels]=ngel;
  gels++;
  if(!strcmp(ngel->ClassName(),"text"))
  { // Burn the alpha channel onto black, so we can avoid blending
    QFilterBlendBurn(ngel->GetSourceBitMap());
  }
  return TRUE;
}

void QScroller::ScrollGel(QBob *gel,int vx,int vy)
{ QRect r,rArea;
  proftime_t t;
  char buf[80];
  int sx,sy,swid,shgt,dx,dy;	// CopyPixels

 //BenchCP();
  r.x=gel->x->GetCurrent(); //r.x=100;
  r.y=gel->y->GetCurrent(); //r.y=600;
  //printf("org x/y=%d,%d\n",gel->x->GetCurrent(),gel->y->GetCurrent());
  r.wid=gel->GetWidth();
  r.hgt=gel->GetHeight();

#ifdef ONE_STEP
  goto do_new;
#endif

  //r.y-=curY;
  //printf("gel should now be at virtual %d,%d\n",r.x,r.y);
  sx=r.x;
#ifdef SAMEBUF
  sy=r.y-curY+2*vy;
#else
  sy=r.y-curY+vy;
#endif
  dx=r.x; dy=r.y-curY;
  swid=r.wid;
  shgt=r.hgt;

  // Clip to viewport
#ifdef SAMEBUF
  if(sy<area.y+2*vy)
  { shgt=shgt-(area.y-sy)-2*vy;
    sy=area.y+2*vy;
    dy=area.y;
  }
#else
  if(sy<area.y+vy)
  { shgt=shgt-(area.y-sy)-vy;
    sy=area.y+vy;
    dy=area.y;
  }
#endif
  if(sy+shgt>area.y+area.hgt)
  { shgt=area.y+area.hgt-sy;
  }

  if(swid<=0||shgt<=0)goto skip;
  //printf("  copy %d,%d %dx%d to %d,%d\n",sx,sy,swid,shgt,dx,dy);
//#define OPTIMIZE_COPYPIXELS
#ifdef OPTIMIZE_COPYPIXELS
  // Optimized CopyPixels
  sprintf(buf,"glCopyPixels sized %dx%d",swid,shgt); glFinish(); profStart(&t);
  dy=area.hgt-shgt-dy;
  glRasterPos2i(dx,dy);
  glPixelStorei(GL_UNPACK_ROW_LENGTH,area.wid);
  glPixelStorei(GL_PACK_ROW_LENGTH,area.wid);

///*
  glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
  glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);
  glPixelStorei(GL_PACK_SKIP_PIXELS,0);
  glPixelStorei(GL_PACK_SKIP_ROWS,0);
//*/
 
  glDisable(GL_DITHER);
  glDisable(GL_BLEND);
  //glFinish();
  //profStart(&t);
  sy=area.hgt-shgt-sy;			// Reverse Y
  glCopyPixels(sx,sy,swid,shgt,GL_COLOR);
  //glFinish();
  //profReport(&t,buf);
  //BenchCP();		// Slow!
  //printf("blend? %d\n",glIsEnabled(GL_BLEND));
#else
  cv->CopyPixels(sx,sy,swid,shgt,dx,dy);
#endif

 do_new:
  // Add new part
#ifdef SAMEBUF
  sx=0;
  sy=area.y+area.hgt-r.y+curY-2*vy;
  swid=r.wid; shgt=vy*2;
  dx=r.x;
  dy=area.y+area.hgt-2*vy;
#else
  sx=0;
  sy=area.y+area.hgt-r.y+curY-vy;
  swid=r.wid; shgt=vy;
  dx=r.x;
  dy=area.y+area.hgt-vy;
#endif

  // Clip to stay inside bitmap
  if(shgt+sy>r.hgt)
  { shgt=r.hgt-sy;
  }
  // Clip to scroll area
  if(sy>0&&sy<r.hgt&&shgt>0)
  { 
    //cv->Enable(QCANVASF_BLEND);
    //printf("  blit new %d,%d %dx%d, dst %d,%d\n",sx,sy,swid,shgt,dx,dy);
    cv->Blit(gel->GetSourceBitMap(),dx,dy,swid,shgt,sx,sy);
  }
  //sginap(10);
 skip:
  //lastY=r.y;
  ;
}
void QScroller::Scroll(int vx,int vy)
{ proftime_t t;
  int i;
  curX+=vx;
  curY+=vy;
#ifdef OBSOLETE
 //BenchCP();
  BenchCP("QScroller::Scroll1");
  glReadBuffer(GL_FRONT);		// This make it slow?!
  BenchCP("QScroller::Scroll2");
  glDrawBuffer(GL_BACK);
  BenchCP("QScroller::Scroll3");
  glDisable(GL_BLEND);
  BenchCP("QScroller::Scroll4");
  glDisable(GL_DITHER);
  BenchCP("QScroller::Scroll5");
#endif

  glFinish(); profStart(&t);
//#define DO_CLEAR
#ifdef DO_CLEAR
  // You might not clear, but then the bobs must clear after them
  //glClearColor(.2,.5,.8,0);
  //glClearColor(0,0,0,0);
  glClearColor(0,0,1,0);
  glClear(GL_COLOR_BUFFER_BIT);		// So blindingly fast
#endif
 //BenchCP();
#define USE_FRONT2BACK
#ifdef USE_FRONT2BACK
  // Copying from front to back is slow on Indy/OpenGL (fast with GL!)
  glReadBuffer(GL_FRONT);
#else
  glReadBuffer(GL_BACK);
#endif
#ifdef ONE_STEP
  // One big step; far less overhead! (?)
  glReadBuffer(GL_FRONT);
  //glReadBuffer(GL_BACK);		// faster on Indy
  //glReadBuffer(GL_BACK);
  glDisable(GL_BLEND);
  glDisable(GL_DITHER);
  cv->CopyPixels(area.x,area.y+vy,area.wid,area.hgt-vy,area.x,area.y);
  //cv->CopyPixels(area.x,area.y+vy*2,area.wid,area.hgt-vy*2,area.x,area.y);
  //glFinish(); profReport(&t,"PAL scrolled");
#endif
  //return;
  //// Copy Pixels
  //cv->Disable(QCANVASF_BLEND);
  cv->Blend(FALSE);
  //glFinish();
  //BenchCP("QScroller::Scroll9");
  for(i=0;i<gels;i++)
    ScrollGel(gel[i],vx,vy);
  glFinish(); profReport(&t,"gels scrolled");
  glReadBuffer(GL_BACK);
  //glFinish();
 //sginap(70);
}

//#define TEST
#ifdef TEST

//#include <qlib/qgelwg.h>
#include <qlib/shell.h>

// From qtest
QShell *sh;
//extern QGelWidget *gw;
extern QCanvas *cv;
extern QFont *font;
extern QImage *img;

void scrollDemo()
// For qtest
{ QScroller *scroller;
  QText *text[10];
  QBob  *bob[10];
  int i;
  QRect r;
  QImage *imgEye=img;

  sh=app->GetBC();
  printf("scrollDemo\n");
  //gw->Select();
  r.x=0; r.y=0; r.wid=768; r.hgt=576;
  scroller=new QScroller(cv,&r);
  printf("  1\n");
  text[0]=new QText(cv,font,"Scroller doodle doo",QGELF_AA);
  text[0]->SetText("Scrollery doodle doo",QBM_AA_ALG_9POINT);
  //text[0]=txt2;
  printf("  2\n");
  text[0]->x->Set(100);
  text[0]->y->Set(600);
  printf("  3\n");
  scroller->Add(text[0]);
  text[1]=new QText(cv,font,"",QGELF_AA);
  text[1]->SetText("A MarketGraph Product",QBM_AA_ALG_9POINT);
  scroller->Add(text[1]);
  text[1]->x->Set(200);
  text[1]->y->Set(710);
  bob[0]=new QBob(imgEye,0,0,400,100);
  scroller->Add(bob[0]);
  bob[0]->x->Set(130);
  bob[0]->y->Set(760);

  printf("  4\n");
  for(i=0;i<1200;i++)
  { scroller->Scroll(0,1);
    sh->Swap();
  }
  printf("  5\n");
  //delete text;
  //delete scroller;
}

#endif