forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

I need a rotation tut

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Lua Player Development
View previous topic :: View next topic  
Author Message
yor1001



Joined: 21 Jun 2006
Posts: 2

PostPosted: Wed Jun 21, 2006 7:32 am    Post subject: I need a rotation tut Reply with quote

I notice there are alot of topics about rotation but none of them really addresses the issue and those that do doesn't work properly. could some one please explain how rotating an image works and how to set up the cosine and sine.
I would appreciate it.
Back to top
View user's profile Send private message AIM Address
Altair



Joined: 20 May 2006
Posts: 76
Location: The Netherlands

PostPosted: Wed Jun 21, 2006 9:22 am    Post subject: Reply with quote

This one works, however its a bit slow:

Code:
function rotateImage(theImage, angle)
screen:blit(0,0,theImage) 
angle = angle*(6 + (1/3))/360
   for x = 1, theImage:width() do
      for y = 1, theImage:height() do
         tX = math.cos(angle)*(x-theImage:width()) - math.sin(angle) * (y-theImage:height())
         tY = math.sin(angle)*(x-theImage:width()) + math.cos(angle) * (y-theImage:height())
         screen:fillRect(tX + 240, tY + 136, 2, 2, screen:pixel(x, y))
      end
   end
end
Back to top
View user's profile Send private message
sdfnanderson



Joined: 27 Jan 2006
Posts: 12

PostPosted: Fri Jun 23, 2006 9:53 pm    Post subject: TRANSFORMATION MATRIX Reply with quote

GREETINGS.

Using this method, you´re using MATRIX MULTIPLY METHOD TO ROTATE THE OBJECT.

cos(ang) -sen (ang) 0 Coordinate X
sen (ang cos (ang) 0 * Coordinate Y
0 0 1 1


but, only for purpose rotating in Z Axis, or (rotating 2D).


To rotate X axis or Y Axis, seek for MATRIX ROTATE FOR 3D, like axis X and Y. the algorithm is very simple like this, but the position of sin and cosins is different than that first algorithm..


thanks.
Back to top
View user's profile Send private message Send e-mail
sdfnanderson



Joined: 27 Jan 2006
Posts: 12

PostPosted: Fri Jun 23, 2006 10:03 pm    Post subject: THE MATRIX METHOD Reply with quote

ROTATE 2D (OR Z AXIS)

| cos (ang) - sin (ang) 0| | Coordinate X
| sin (ang) cos (ang) 0| * | Y
| 0 0 1| |1


ROTATE X AXIS

X
*(*(MATRIZA+1)+1)=1;
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=cos(angulo);
*(*(MATRIZA+2)+3)=sin(angulo);
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=-sin(angulo);
*(*(MATRIZA+3)+3)=cos(angulo);



ROTATE Y AXIS


Y
*(*(MATRIZA+1)+1)=cos(angulo);
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=-sin(angulo);
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=1;
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=sin(angulo);
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=cos(angulo);
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;





USING C++ LANGUAGE, LIKE THIS:



float **MATRIZA;
float **MATRIZB;
float **MATRIZC;





case 34:{
int n;
/* Efetua Espelhamento de Objetos x > X ou X > x */
CENTRO print ("[OBJETO][Espelhamento]\n");
CENTRO var1=atof(lineinput("X (1;-1):"));

/* Coordenada Y */
CENTRO var2=atof(lineinput("Y (1;-1):"));

/* Coordenada Z */
CENTRO var3=atof(lineinput("Z (1;-1):"));

/* Limpa o Objeto da Tela */
cobject (objeto, tela);

/* Efetua a Alocacao propriamente dita */
criarmatriz(4,4,1,0);

/* Efetua Espelhamento */
espelharmatriz(var1,var2,var3);

/* Aplica Escalonamento nas coordenadas */
for (n=0;n<=objeto.i;n++){
*(*(MATRIZB+1)+1)= objeto.nuvem[n].x;
*(*(MATRIZB+2)+1)= objeto.nuvem[n].y;
*(*(MATRIZB+3)+1)= objeto.nuvem[n].z;
*(*(MATRIZB+4)+1)= 1;

multiplicarmatriz(4,4,1);

objeto.nuvem[n].x=(int) *(*(MATRIZC+1)+1);
objeto.nuvem[n].y=(int) *(*(MATRIZC+2)+1);
objeto.nuvem[n].z=(int) *(*(MATRIZC+3)+1);
};

break;

};

case 35:{
int n;
/* Efetua Escala de Objetos x > X ou X > x */
CENTRO print ("[OBJETO][Escalonamento]\n");

/* Coordenada X */
CENTRO var1=val(lineinput("X (1:N):"));
/* Coordenada Y */
CENTRO var2=val(lineinput("Y (1:N):"));
/* Coordenada Z */
CENTRO var3=val(lineinput("Z (1:N):"));

/* Limpa o Objeto da Tela */
cobject (objeto, tela);

/* Efetua a Alocacao propriamente dita */
criarmatriz(4,4,1,0);

/* Efetua Escalonamento */
escalonarmatriz(var1,var2,var3);

/* Aplica Espelhamento nas coordenadas */
for (n=0;n<=objeto.i;n++){
*(*(MATRIZB+1)+1)= objeto.nuvem[n].x;
*(*(MATRIZB+2)+1)= objeto.nuvem[n].y;
*(*(MATRIZB+3)+1)= objeto.nuvem[n].z;

multiplicarmatriz(4,4,1);

objeto.nuvem[n].x= *(*(MATRIZC+1)+1);
objeto.nuvem[n].y= *(*(MATRIZC+2)+1);
objeto.nuvem[n].z= *(*(MATRIZC+3)+1);
};

break;

};

case 36:{
int n;

CENTRO print ("[OBJETO][Transla‡Æo]\n");

/* Coordenada X */
CENTRO var1=(float) val(lineinput("X ():"));
/* Coordenada Y */
CENTRO var2=(float) val(lineinput("Y ():"));
/* Coordenada Z */
CENTRO var3=(float) val(lineinput("Z ():"));

/* Limpa o Objeto da Tela */
cobject (objeto, tela);

/* Efetua a Alocacao propriamente dita */
criarmatriz(4,4,1,0);

/* Efetua Translacao */
transladarmatriz(var1,var2,var3);

/* Aplica Mascara nas coordenadas */
for (n=0;n<=objeto.i;n++){

*(*(MATRIZB+1)+1)= objeto.nuvem[n].x;
*(*(MATRIZB+2)+1)= objeto.nuvem[n].y;
*(*(MATRIZB+3)+1)= objeto.nuvem[n].z;
*(*(MATRIZB+4)+1)= 1;

multiplicarmatriz(4,4,1);

objeto.nuvem[n].x= *(*(MATRIZC+1)+1);
objeto.nuvem[n].y= *(*(MATRIZC+2)+1);
objeto.nuvem[n].z= *(*(MATRIZC+3)+1);
};

break;

};

case 37: {
int n,sentido;

CENTRO print ("[OBJETO][Rotacao]\n");
/* Obtem o Angulo */
CENTRO var1=atof(lineinput("ANGULO :"));

/* Limpa o Objeto da Tela */
cobject (objeto, tela);

/* Efetua a Alocacao propriamente dita */
criarmatriz(4,4,1,0);

/* Obtem o Angulo */
CENTRO sentido=atof(lineinput("EIXO: X=1, Y=2, Z=3 :"));

/* Efetua Rotacao no eixo determinado */
if (sentido==3) rotacionarmatrizZ(var1);
if (sentido==2) rotacionarmatrizY(var1);
if (sentido==1) rotacionarmatrizX(var1);

/* Aplica Rotacao nas coordenadas */
for (n=0;n<=objeto.i;n++){
*(*(MATRIZB+1)+1)= objeto.nuvem[n].x;
*(*(MATRIZB+2)+1)= objeto.nuvem[n].y;
*(*(MATRIZB+3)+1)= objeto.nuvem[n].z;

multiplicarmatriz(4,4,1);

objeto.nuvem[n].x= *(*(MATRIZC+1)+1) ;
objeto.nuvem[n].y= *(*(MATRIZC+2)+1) ;
objeto.nuvem[n].z= *(*(MATRIZC+3)+1) ;

};

break;
};




/********************************************

MATRIZES

********************************************/


void criarmatriz(int ALINHAS, int ACOLUNAS, int BCOLUNAS, int BLINHAS){
/* Alocação Dinamica de Matrizes */
int f,g,i;
if (BLINHAS==0)
BLINHAS=ACOLUNAS;

if(MATRIZA!=NULL) free(MATRIZA);
if(MATRIZB!=NULL) free(MATRIZB);
if(MATRIZC!=NULL) free(MATRIZC);


/* Matriz A */
MATRIZA = (float **) malloc((ALINHAS+1) * sizeof(float));
if (!MATRIZA) {printf("Erro na alocacao MATRIZ A\n"); (exit(0x0a));}

for (i=0;i<=ALINHAS;i++){
*(MATRIZA +i)=(float *) malloc((ACOLUNAS+1) * sizeof(float));

if (! *(MATRIZA+ i)) {printf("Erro na alocacao colunas MATRIZA\n");exit(0x0a);}
}

/* Matriz B */
MATRIZB = (float **) malloc((BLINHAS+1) * sizeof(float));
if (!MATRIZB) {printf("Erro na alocacao MATRIZ B\n"); (exit(0x0b));}

for (i=0;i<=BLINHAS;i++){
*(MATRIZB +i)=(float *) malloc((BCOLUNAS+1) * sizeof(float));

if (! *(MATRIZB+ i)) {printf("Erro na alocacao colunas MATRIZB\n");exit(0x0b);}
}

/* Matriz C */
MATRIZC = (float **) malloc((ALINHAS+1) * sizeof(float));
if (!MATRIZB) {printf("Erro na alocacao MATRIZ C\n"); (exit(0x0c));}

for (i=0;i<ALINHAS;i++){
*(MATRIZC +i)=(float *) malloc(BCOLUNAS * sizeof(float));
if (! *(MATRIZC+ i)) {printf("Erro na alocacao colunas MATRIZCB\n");exit(0x0c);}
}

/* inicializar valores nas matrizes */
/* Matriz A */
for(f=1;f<=ALINHAS;f++)
for(g=1;g<=ACOLUNAS;g++) {
*(*(MATRIZA+f)+g)=0;
}
/* Matriz B */
for(f=1;f<=BLINHAS;f++)
for(g=1;g<=BCOLUNAS;g++) {
*(*(MATRIZB+f)+g)=0;
}
/* Matriz C */
multiplicarmatriz(ALINHAS,ACOLUNAS,BCOLUNAS); /* linhas de a, colunas de a, colunas de b */
}
void preenchermatriz(int ALINHAS, int ACOLUNAS, int BCOLUNAS, int BLINHAS){
/* solicita preenchimento manual da MATRIZ B E MATRIZ A */
if (BLINHAS==0)
BLINHAS=ACOLUNAS;
printf("ETAPA 1 - ENTRADA\n");
printf("Digite os valores de cada coluna, passe para a proxima linha, sucessivamente\n\n");

lermatriza(ALINHAS,ACOLUNAS,BCOLUNAS,BLINHAS);
lermatrizb(ALINHAS,ACOLUNAS,BCOLUNAS,BLINHAS);

}

void somamatriz(int ALINHAS, int ACOLUNAS, int BCOLUNAS, int BLINHAS){
/* Efetua a Soma de Matrizes */
int l,c;
l=BCOLUNAS;/* (Corrigir warning...) */
if (BLINHAS==0)
BLINHAS=ACOLUNAS;

for (l=1;l<=ALINHAS;l++){
for (c=1;c<=ACOLUNAS;c++){
*(*(MATRIZC+l)+c)=*(*(MATRIZA+l)+c)+ *(*(MATRIZB+l)+c);
}
}

}
void multiplicarmatriz(int ALINHAS, int ACOLUNAS, int BCOLUNAS){
/* Efetua a Multiplicacao de Matrizes */
int i,j,k;
float x,n,y;
int BLINHAS=ACOLUNAS;

for(i=1;i<=ALINHAS;i++)
for(j=1;j<=BCOLUNAS;j++) {
x=0;
for(k=1;k<=BLINHAS;k++)
x= x + *(*(MATRIZA+i)+k) * *(*(MATRIZB+k)+j);
*(*(MATRIZC+i)+j)=x;
};
};
void imprimirmatriz(int ALINHAS, int ACOLUNAS, int BCOLUNAS, int BLINHAS){
/* Imprime os dados das matrizes A, B C na saida padrao */
int f,g,x;

/* Coordenadas IGUAIS - Multiplicacao de Matrizes...*/
if (BLINHAS==0)
BLINHAS=ACOLUNAS;

/* Cabecalho */
printf("\nVALORES DAS matrizes\n");
printf("MATRIZ C MATRIZ A MATRIZ B\n");

/* Efetua a Impressao */
x=ALINHAS;
if(ALINHAS<=BLINHAS)x=BLINHAS;
for(f=1;f<=x;f++) {

/* Matriz C */
for (g=1;g<=BCOLUNAS;g++)
if (f<=ALINHAS)
printf("%f ",*(*(MATRIZC+f)+g));
printf(" ");

/* Matriz A */
for(g=1;g<=ACOLUNAS;g++)
if (f<=ALINHAS)
printf("%f ",*(*(MATRIZA+f)+g));
printf(" ");

/* Matriz B */
for(g=1;g<=BCOLUNAS;g++)
if (f<=BLINHAS)
printf("%f ",*(*(MATRIZB+f)+g));
NOVALINHA
}
return;
}

void transladarmatriz(float x, float y,float z){
/* Mascara para Translacao de Coordenadas */
/* Elemento Neutro */
// z++;

*(*(MATRIZA+1)+1)=1;
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=x;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=1;
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=y;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=1;
*(*(MATRIZA+3)+4)=z;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;

}

void lermatriza(int ALINHAS, int ACOLUNAS, int BCOLUNAS, int BLINHAS){
/* Entrada de dados pelo usuario na Matriz A (Mascara) */
int f,g;

f=BCOLUNAS; /* corrigir warning ...*/
if (BLINHAS==0)
BLINHAS=ACOLUNAS;

/* Leitura dos dados para MATRIZ A (MASCARA) */
for(f=1;f<=ALINHAS;f++)
for(g=1;g<=ACOLUNAS;g++) {
CENTRO printf("MATRIZ A (%i,%i):",f,g);
*(*(MATRIZA +f)+g)=atof(lineinput(""));
}
}

void lermatrizb(int ALINHAS, int ACOLUNAS, int BCOLUNAS, int BLINHAS){
/* Entrada de Dados na Matriz de Dados B */
STRING linha;
int f,g;

/* Coordenada BLINHAS ZERO = ACOLUNAS (Multiplicacao de matrizes... )*/
if (BLINHAS==0)
BLINHAS=ACOLUNAS;

f=ALINHAS; /* corrigir warning */

/* Leitura dos dados por parte do usuario */
for(f=1;f<=BLINHAS;f++)
for(g=1;g<=BCOLUNAS;g++) {
CENTRO printf("MATRIZ B (%i,%i):",f,g);
linha=lineinput("");
*(*(MATRIZB+f)+g)=atoi(linha);
}
}

void espelharmatriz(float x, float y,float z){
/* Mascara para Espelhar Matriz (Tanto em X como em Y) */
*(*(MATRIZA+1)+1)=x;
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=y;
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=z;
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;

}

void escalonarmatriz(float x, float y,float z){
/* Mascara para Escalonar Matriz */
*(*(MATRIZA+1)+1)=x;
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=y;
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=z;
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;

}

void invertercoordenadas(void){
/* Mascara para Inversao de Coordenadas X>Y e Y>X */
*(*(MATRIZA+1)+1)=0;
*(*(MATRIZA+1)+2)=1;
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=1;
*(*(MATRIZA+2)+2)=0;
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=1;
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;


}
void rotacionarmatrizX(float angulo){
/* rotaciona no sentido ANTI-HORARIO a coordenada dada */

/* Preambulo - matematica */
if (angulo==360) angulo=0;
if (angulo!=360) angulo=(PI/180)*angulo;

/* Mascara para Rotacao no Eixo Z */
*(*(MATRIZA+1)+1)=1;
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=cos(angulo);
*(*(MATRIZA+2)+3)=sin(angulo);
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=-sin(angulo);
*(*(MATRIZA+3)+3)=cos(angulo);
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;

}

void rotacionarmatrizY(float angulo){
/* rotaciona no sentido ANTI-HORARIO a coordenada dada */

/* Preambulo - matematica */
if (angulo==360) angulo=0;
if (angulo!=360) angulo=(PI/180)*angulo;

/* Mascara para Rotacao no Eixo Y */
*(*(MATRIZA+1)+1)=cos(angulo);
*(*(MATRIZA+1)+2)=0;
*(*(MATRIZA+1)+3)=-sin(angulo);
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=0;
*(*(MATRIZA+2)+2)=1;
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=sin(angulo);
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=cos(angulo);
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;

}


void rotacionarmatrizZ(float angulo){
/* rotaciona no sentido ANTI-HORARIO a coordenada dada */

/* Preambulo - matematica */
if (angulo==360) angulo=0;
if (angulo!=360) angulo=(PI/180)*angulo;

/* Mascara para Rotacao no Eixo Z */
*(*(MATRIZA+1)+1)=cos(angulo);
*(*(MATRIZA+1)+2)=sin(angulo);
*(*(MATRIZA+1)+3)=0;
*(*(MATRIZA+1)+4)=0;

*(*(MATRIZA+2)+1)=-sin(angulo);
*(*(MATRIZA+2)+2)=cos(angulo);
*(*(MATRIZA+2)+3)=0;
*(*(MATRIZA+2)+4)=0;

*(*(MATRIZA+3)+1)=0;
*(*(MATRIZA+3)+2)=0;
*(*(MATRIZA+3)+3)=1;
*(*(MATRIZA+3)+4)=0;

*(*(MATRIZA+4)+1)=0;
*(*(MATRIZA+4)+2)=0;
*(*(MATRIZA+4)+3)=0;
*(*(MATRIZA+4)+4)=1;

}


Last edited by sdfnanderson on Fri Jun 23, 2006 10:15 pm; edited 1 time in total
Back to top
View user's profile Send private message Send e-mail
sdfnanderson



Joined: 27 Jan 2006
Posts: 12

PostPosted: Fri Jun 23, 2006 10:10 pm    Post subject: Reply with quote

I´M USING THIS METHOD, BUT THIS CODE IS A VEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEERY SLOW VERSION, TO EVERYONE SEE AND UNDERSTAND HOW TO USE THE MATRIX METHOD.
Back to top
View user's profile Send private message Send e-mail
sdfnanderson



Joined: 27 Jan 2006
Posts: 12

PostPosted: Fri Jun 23, 2006 10:12 pm    Post subject: Reply with quote

THE OGRE 3D USE THIS METHOD TO DO THEIR ROTATES.
Back to top
View user's profile Send private message Send e-mail
yor1001



Joined: 21 Jun 2006
Posts: 2

PostPosted: Mon Jun 26, 2006 11:18 am    Post subject: Reply with quote

omg alhough I gave up on rotating in lua I Have to thank u very much on the amount of codes you distowed on me thanx for the inco and BTW i am gonna go in C++ so thanx for the heads up.
Back to top
View user's profile Send private message AIM Address
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Lua Player Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group