mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-03 09:23:37 +00:00
TRECISION: Move 3Drend into a renderer class
This commit is contained in:
parent
982c0d1444
commit
3094e4ba68
@ -20,131 +20,142 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/nl/3d/3dinc.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/3d.h"
|
||||
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/graphics.h"
|
||||
|
||||
namespace Trecision {
|
||||
#define SHADOWVERTSNUM 42
|
||||
|
||||
int16 _shadowLightNum = 0;
|
||||
int16 _totalShadowVerts = 0;
|
||||
static int16 _shadowVerts[SHADOWVERTSNUM] = {
|
||||
6, 15, 23,
|
||||
24, 32, 78,
|
||||
80, 81, 83,
|
||||
86, 90, 99,
|
||||
107, 108, 116,
|
||||
155, 157, 158,
|
||||
160, 164, 168,
|
||||
169, 173, 174,
|
||||
187, 188, 192,
|
||||
193, 213, 215,
|
||||
227, 229, 235,
|
||||
238, 249, 250,
|
||||
252, 253, 299,
|
||||
306, 330, 336
|
||||
};
|
||||
#define SHADOWFACESNUM 48
|
||||
|
||||
int16 _shadowVertsNum = 42;
|
||||
int16 _shadowVerts[42] = {
|
||||
6, 15, 23,
|
||||
24, 32, 78,
|
||||
80, 81, 83,
|
||||
86, 90, 99,
|
||||
107, 108, 116,
|
||||
155, 157, 158,
|
||||
160, 164, 168,
|
||||
169, 173, 174,
|
||||
187, 188, 192,
|
||||
193, 213, 215,
|
||||
227, 229, 235,
|
||||
238, 249, 250,
|
||||
252, 253, 299,
|
||||
306, 330, 336
|
||||
int16 _shadowFaces[SHADOWFACESNUM][3] = {
|
||||
22, 21, 5,
|
||||
7, 5, 22,
|
||||
7, 19, 5,
|
||||
5, 2, 19,
|
||||
27, 24, 16,
|
||||
27, 16, 18,
|
||||
18, 16, 9,
|
||||
18, 13, 9,
|
||||
13, 9, 2,
|
||||
3, 19, 12,
|
||||
25, 26, 17,
|
||||
17, 15, 25,
|
||||
17, 19, 15,
|
||||
15, 12, 19,
|
||||
20, 23, 8,
|
||||
8, 6, 20,
|
||||
6, 9, 3,
|
||||
3, 8, 6,
|
||||
12, 3, 4,
|
||||
4, 11, 12,
|
||||
35, 4, 11,
|
||||
13, 2, 1,
|
||||
1, 14, 13,
|
||||
14, 37, 1,
|
||||
1, 34, 37,
|
||||
31, 36, 37,
|
||||
37, 30, 31,
|
||||
29, 34, 35,
|
||||
35, 29, 28,
|
||||
36, 11, 31,
|
||||
30, 37, 14,
|
||||
29, 1, 34,
|
||||
28, 4, 35,
|
||||
36, 10, 35,
|
||||
35, 32, 10,
|
||||
37, 0, 34,
|
||||
37, 33, 0,
|
||||
0, 33, 39,
|
||||
39, 40, 0,
|
||||
10, 38, 32,
|
||||
32, 41, 38,
|
||||
36, 35, 34,
|
||||
36, 37, 35,
|
||||
11, 36, 35,
|
||||
38, 40, 41,
|
||||
41, 38, 39,
|
||||
2, 19, 13,
|
||||
3, 9, 12
|
||||
};
|
||||
|
||||
int16 _shadowFacesNum = 48;
|
||||
int16 _shadowFaces[48][3] = {
|
||||
22, 21, 5,
|
||||
7, 5, 22,
|
||||
7, 19, 5,
|
||||
5, 2, 19,
|
||||
27, 24, 16,
|
||||
27, 16, 18,
|
||||
18, 16, 9,
|
||||
18, 13, 9,
|
||||
13, 9, 2,
|
||||
3, 19, 12,
|
||||
25, 26, 17,
|
||||
17, 15, 25,
|
||||
17, 19, 15,
|
||||
15, 12, 19,
|
||||
20, 23, 8,
|
||||
8, 6, 20,
|
||||
6, 9, 3,
|
||||
3, 8, 6,
|
||||
12, 3, 4,
|
||||
4, 11, 12,
|
||||
35, 4, 11,
|
||||
13, 2, 1,
|
||||
1, 14, 13,
|
||||
14, 37, 1,
|
||||
1, 34, 37,
|
||||
31, 36, 37,
|
||||
37, 30, 31,
|
||||
29, 34, 35,
|
||||
35, 29, 28,
|
||||
36, 11, 31,
|
||||
30, 37, 14,
|
||||
29, 1, 34,
|
||||
28, 4, 35,
|
||||
36, 10, 35,
|
||||
35, 32, 10,
|
||||
37, 0, 34,
|
||||
37, 33, 0,
|
||||
0, 33, 39,
|
||||
39, 40, 0,
|
||||
10, 38, 32,
|
||||
32, 41, 38,
|
||||
36, 35, 34,
|
||||
36, 37, 35,
|
||||
11, 36, 35,
|
||||
38, 40, 41,
|
||||
41, 38, 39,
|
||||
2, 19, 13,
|
||||
3, 9, 12
|
||||
};
|
||||
Renderer3D::Renderer3D(TrecisionEngine *vm) : _vm(vm) {
|
||||
_zBuf = nullptr;
|
||||
_curPage = nullptr;
|
||||
|
||||
uint8 _shadowIntens[10];
|
||||
_minXClip = 0;
|
||||
_minYClip = 0;
|
||||
_maxXClip = 0;
|
||||
_maxYClip = 0;
|
||||
_zBufStartX = 0;
|
||||
_zBufStartY = 0;
|
||||
_zBufWid = 0;
|
||||
_shadowLightNum = 0;
|
||||
_totalShadowVerts = 0;
|
||||
|
||||
struct SVVertex {
|
||||
int32 _x, _y, _z;
|
||||
int32 _angle;
|
||||
} _vVertex[MAXVERTEX];
|
||||
// data for the triangle routines
|
||||
for (int i = 0; i < 480; ++i) {
|
||||
_lEdge[i] = 0;
|
||||
_rEdge[i] = 0;
|
||||
_lColor[i] = 0;
|
||||
_rColor[i] = 0;
|
||||
_lZ[i] = 0;
|
||||
_rZ[i] = 0;
|
||||
_lTextX[i] = 0;
|
||||
_rTextX[i] = 0;
|
||||
_lTextY[i] = 0;
|
||||
_rTextY[i] = 0;
|
||||
}
|
||||
|
||||
SVertex _shVertex[MAXVERTEX];
|
||||
for (int i = 0; i < 10; ++i)
|
||||
_shadowIntens[i] = 0;
|
||||
|
||||
uint32 _materials[21][181];
|
||||
for (int i = 0; i < MAXVERTEX; ++i) {
|
||||
_vVertex[i]._x = 0;
|
||||
_vVertex[i]._y = 0;
|
||||
_vVertex[i]._z = 0;
|
||||
_vVertex[i]._angle = 0;
|
||||
|
||||
uint16 *_curPage;
|
||||
int16 *_zBuf;
|
||||
int16 _minXClip;
|
||||
int16 _minYClip;
|
||||
int16 _maxXClip;
|
||||
int16 _maxYClip;
|
||||
_shVertex[i]._x = 0;
|
||||
_shVertex[i]._y = 0;
|
||||
_shVertex[i]._z = 0;
|
||||
_shVertex[i]._nx = 0;
|
||||
_shVertex[i]._ny = 0;
|
||||
_shVertex[i]._nz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16 _zBufStartX;
|
||||
int16 _zBufStartY;
|
||||
int16 _zBufWid;
|
||||
Renderer3D::~Renderer3D() {
|
||||
}
|
||||
|
||||
// data for the triangle routines
|
||||
int16 _lEdge[480];
|
||||
int16 _rEdge[480];
|
||||
uint8 _lColor[480];
|
||||
uint8 _rColor[480];
|
||||
int16 _lZ[480];
|
||||
int16 _rZ[480];
|
||||
uint16 _lTextX[480];
|
||||
uint16 _rTextX[480];
|
||||
uint16 _lTextY[480];
|
||||
uint16 _rTextY[480];
|
||||
|
||||
void textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1,
|
||||
int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2,
|
||||
int32 x3, int32 y3, int32 z3, int32 c3, int32 tx3, int32 ty3,
|
||||
STexture *t) {
|
||||
int32 cl; // color of left edge of horizontal scanline
|
||||
int32 zl; // zbuffer of left edge of horizontal scanline
|
||||
int32 olx; // texture x of left edge of horizontal scanline
|
||||
int32 oly; // texture y of left edge of horizontal scanline
|
||||
int16 y; // looping variable
|
||||
void Renderer3D::textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1,
|
||||
int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2,
|
||||
int32 x3, int32 y3, int32 z3, int32 c3, int32 tx3, int32 ty3,
|
||||
STexture *t) {
|
||||
int32 cl; // color of left edge of horizontal scanline
|
||||
int32 zl; // zbuffer of left edge of horizontal scanline
|
||||
int32 olx; // texture x of left edge of horizontal scanline
|
||||
int32 oly; // texture y of left edge of horizontal scanline
|
||||
int16 y; // looping variable
|
||||
|
||||
if (y1 > _maxYClip)
|
||||
y1 = _maxYClip;
|
||||
@ -213,29 +224,29 @@ void textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty
|
||||
uint16 *screenPtr = _curPage + sl;
|
||||
|
||||
zl <<= 16;
|
||||
cl <<= 8;
|
||||
cl <<= 8;
|
||||
olx <<= 16;
|
||||
oly <<= 16;
|
||||
// loop through every pixel in horizontal scanline
|
||||
while (dx) {
|
||||
sl = zl >> 16;
|
||||
if (*z > sl) {
|
||||
*screenPtr = (uint16)(g_vm->_actor->_textureMat[texture[(olx >> 16) + t->_dx * (oly >> 16)]][cl >> 9]);
|
||||
*screenPtr = (uint16)(_vm->_actor->_textureMat[texture[(olx >> 16) + t->_dx * (oly >> 16)]][cl >> 9]);
|
||||
*z = (int16)sl;
|
||||
}
|
||||
screenPtr++; // increase screen x
|
||||
z++; // increase zbuffer
|
||||
zl += mz; // increase the zbuffer by _dz/_dx
|
||||
cl += mc; // increase the color by dc/_dx
|
||||
screenPtr++; // increase screen x
|
||||
z++; // increase zbuffer
|
||||
zl += mz; // increase the zbuffer by _dz/_dx
|
||||
cl += mc; // increase the color by dc/_dx
|
||||
olx += mtx;
|
||||
oly += mty;
|
||||
dx--; // pixel to do --
|
||||
dx--; // pixel to do --
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2) {
|
||||
void Renderer3D::textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2) {
|
||||
// make sure that edge goes from top to bottom
|
||||
int16 dy = y2 - y1;
|
||||
if (dy < 0) {
|
||||
@ -255,13 +266,13 @@ void textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty
|
||||
// initialize for stepping
|
||||
int32 mx = ((x2 - x1) << 16) / dy; // dx/dy
|
||||
int32 mz = ((z2 - z1) << 16) / dy; // dz/dy
|
||||
int32 mc = ((c2 - c1) << 8) / dy; // dc/dy
|
||||
int32 mc = ((c2 - c1) << 8) / dy; // dc/dy
|
||||
int32 mtx = ((tx2 - tx1) << 16) / dy;
|
||||
int32 mty = ((ty2 - ty1) << 16) / dy;
|
||||
|
||||
x1 <<= 16; // starting x coordinate
|
||||
z1 <<= 16; // starting z coordinate
|
||||
c1 <<= 8; // starting c color
|
||||
c1 <<= 8; // starting c color
|
||||
|
||||
tx1 <<= 16;
|
||||
ty1 <<= 16;
|
||||
@ -270,31 +281,31 @@ void textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty
|
||||
for (int32 count = y1; count < y2; count++) {
|
||||
int16 x = (uint16)(x1 >> 16);
|
||||
if (x < _lEdge[count]) {
|
||||
_lEdge[count] = x;
|
||||
_lZ[count] = (int16)(z1 >> 16);
|
||||
_lEdge[count] = x;
|
||||
_lZ[count] = (int16)(z1 >> 16);
|
||||
_lTextX[count] = (uint16)(tx1 >> 16);
|
||||
_lTextY[count] = (uint16)(ty1 >> 16);
|
||||
_lColor[count] = (uint8)(c1 >> 8);
|
||||
}
|
||||
if (x > _rEdge[count]) {
|
||||
_rEdge[count] = x;
|
||||
_rZ[count] = (int16)(z1 >> 16);
|
||||
_rZ[count] = (int16)(z1 >> 16);
|
||||
_rTextX[count] = (uint16)(tx1 >> 16);
|
||||
_rTextY[count] = (uint16)(ty1 >> 16);
|
||||
_rColor[count] = (uint8)(c1 >> 8);
|
||||
}
|
||||
|
||||
x1 += mx; // x = x + dx/dy
|
||||
c1 += mc; // c = c + dc/dy
|
||||
z1 += mz; // z = z + dz/dy
|
||||
x1 += mx; // x = x + dx/dy
|
||||
c1 += mc; // c = c + dc/dy
|
||||
z1 += mz; // z = z + dz/dy
|
||||
|
||||
tx1 += mtx;
|
||||
ty1 += mty;
|
||||
}
|
||||
}
|
||||
|
||||
void shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2,
|
||||
int32 x3, int32 y3, uint8 cv, int32 zv) {
|
||||
void Renderer3D::shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2,
|
||||
int32 x3, int32 y3, uint8 cv, int32 zv) {
|
||||
if (y1 > _maxYClip)
|
||||
y1 = _maxYClip;
|
||||
if (y1 < _minYClip)
|
||||
@ -358,18 +369,18 @@ void shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2,
|
||||
// loop through every pixel in horizontal scanline
|
||||
while (dx) {
|
||||
if (*zBufferPtr != zv) {
|
||||
*screenPtr = g_vm->_graphicsMgr->shadow(*screenPtr, cv);
|
||||
*zBufferPtr = (int16)zv;
|
||||
*screenPtr = _vm->_graphicsMgr->shadow(*screenPtr, cv);
|
||||
*zBufferPtr = zv;
|
||||
}
|
||||
screenPtr++; // increase screen x
|
||||
zBufferPtr++; // increase zbuffer
|
||||
dx--; // pixel to do --
|
||||
screenPtr++; // increase screen x
|
||||
zBufferPtr++; // increase zbuffer
|
||||
dx--; // pixel to do --
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
void Renderer3D::shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
// make sure that edge goes from top to bottom
|
||||
int16 dy = y2 - y1;
|
||||
if (dy < 0) {
|
||||
@ -388,43 +399,49 @@ void shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
x1 <<= 16; // starting x coordinate
|
||||
|
||||
// step through edge and record color values along the way
|
||||
for (int16 count = y1; count < y2; count++) {
|
||||
int16 x = (uint16)(x1 >> 16);
|
||||
for (int32 count = y1; count < y2; count++) {
|
||||
int16 x = (int16)(x1 >> 16);
|
||||
if (x < _lEdge[count])
|
||||
_lEdge[count] = x;
|
||||
|
||||
if (x > _rEdge[count])
|
||||
_rEdge[count] = x;
|
||||
|
||||
x1 += mx; // x = x + dx/dy
|
||||
x1 += mx; // x = x + dx/dy
|
||||
}
|
||||
}
|
||||
|
||||
void init3DRoom(uint16 *destBuffer, int16 *zBuffer) {
|
||||
/*------------------------------------------------
|
||||
Initialize a 3D Room
|
||||
--------------------------------------------------*/
|
||||
void Renderer3D::init3DRoom(uint16 *destBuffer, int16 *zBuffer) {
|
||||
_curPage = destBuffer;
|
||||
_zBuf = zBuffer;
|
||||
_cx = (MAXX - 1) / 2;
|
||||
_cy = (MAXY - 1) / 2;
|
||||
}
|
||||
|
||||
void setClipping(int16 x1, int16 y1, int16 x2, int16 y2) {
|
||||
/*------------------------------------------------
|
||||
Change the clipping area
|
||||
--------------------------------------------------*/
|
||||
void Renderer3D::setClipping(int16 x1, int16 y1, int16 x2, int16 y2) {
|
||||
_minXClip = x1;
|
||||
_minYClip = y1;
|
||||
_maxXClip = x2;
|
||||
_maxYClip = y2;
|
||||
}
|
||||
|
||||
void setZBufferRegion(int16 sx, int16 sy, int16 dx) {
|
||||
void Renderer3D::setZBufferRegion(int16 sx, int16 sy, int16 dx) {
|
||||
_zBufStartX = sx;
|
||||
_zBufStartY = sy;
|
||||
_zBufWid = dx;
|
||||
_zBufWid = dx;
|
||||
}
|
||||
|
||||
/*------------------------------------------------
|
||||
Determines whether a triangle has clockwise
|
||||
or counterclockwise vertices
|
||||
--------------------------------------------------*/
|
||||
int8 clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3) {
|
||||
int8 Renderer3D::clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3) {
|
||||
x2 -= x1;
|
||||
y2 -= y1;
|
||||
|
||||
@ -435,9 +452,9 @@ int8 clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3) {
|
||||
int32 a2 = ((int32)y2) * x3;
|
||||
|
||||
if (a1 > a2)
|
||||
return 1; // clockwise
|
||||
return 1; // clockwise
|
||||
if (a1 < a2)
|
||||
return -1; // counterclockwise
|
||||
return -1; // counterclockwise
|
||||
|
||||
a1 = ((int32)x2) * x3;
|
||||
a2 = ((int32)y2) * y3;
|
||||
@ -452,10 +469,12 @@ int8 clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------
|
||||
Draw the character
|
||||
--------------------------------------------------*/
|
||||
void Renderer3D::drawCharacter(uint8 flag) {
|
||||
Actor *actor = _vm->_actor;
|
||||
|
||||
void drawCharacter(uint8 flag) {
|
||||
Actor *actor = g_vm->_actor;
|
||||
|
||||
// Compute pointer to frame
|
||||
if (flag & CALCPOINTS) {
|
||||
if (actor->_curAction > hLAST)
|
||||
@ -519,8 +538,8 @@ void drawCharacter(uint8 flag) {
|
||||
float sint = sin(t);
|
||||
|
||||
// Put all vertices in dark color
|
||||
for (int a = 0; a < vertexNum; a++)
|
||||
_vVertex[a]._angle = 180;
|
||||
for (int i = 0; i < MAXVERTEX; ++i)
|
||||
_vVertex[i]._angle = 180;
|
||||
|
||||
float dist;
|
||||
float tx = 0;
|
||||
@ -533,35 +552,35 @@ void drawCharacter(uint8 flag) {
|
||||
// if it has a shadow lint & 0x80
|
||||
|
||||
int lint = _curLight->_inten & 0x7F;
|
||||
if (lint) { // if it's not turned off
|
||||
tx = _curLight->_x - actor->_px - actor->_dx; // computes direction vector
|
||||
if (lint) { // if it's not turned off
|
||||
tx = _curLight->_x - actor->_px - actor->_dx; // computes direction vector
|
||||
tz = _curLight->_z - actor->_pz - actor->_dz; // between light and actor
|
||||
ty = _curLight->_y;
|
||||
|
||||
if (_curLight->_position) { // if it's attenuated
|
||||
dist = sqrt(tx * tx + ty * ty + tz * tz); // Distance light <--> actor
|
||||
if (_curLight->_position) { // if it's attenuated
|
||||
dist = sqrt(tx * tx + ty * ty + tz * tz); // Distance light <--> actor
|
||||
|
||||
// adjust light intensity due to the distance
|
||||
if (dist > _curLight->_outr) // if it's out of range it's off
|
||||
if (dist > _curLight->_outr) // if it's out of range it's off
|
||||
lint = 0;
|
||||
else if (dist > _curLight->_inr) // if it's inside the circle it's decreased
|
||||
else if (dist > _curLight->_inr) // if it's inside the circle it's decreased
|
||||
lint = (int)((float)lint * (_curLight->_outr - dist) / (_curLight->_outr - _curLight->_inr));
|
||||
}
|
||||
}
|
||||
|
||||
if (lint) { // If it's still on
|
||||
if (lint) { // If it's still on
|
||||
// Light rotates around the actor
|
||||
l0 = tx * cost - tz * sint;
|
||||
l2 = tx * sint + tz * cost;
|
||||
l1 = ty;
|
||||
t = sqrt(l0 * l0 + l1 * l1 + l2 * l2);
|
||||
t = sqrt(l0 * l0 + l1 * l1 + l2 * l2);
|
||||
l0 /= t;
|
||||
l1 /= t;
|
||||
l2 /= t;
|
||||
|
||||
// Adjust light intensity according to the spot
|
||||
tx = (float)_curLight->_fallOff;
|
||||
if (tx) { // for light spot only
|
||||
if (tx) { // for light spot only
|
||||
ty = (float)_curLight->_hotspot;
|
||||
|
||||
pa0 = _curLight->_dx * cost - _curLight->_dz * sint;
|
||||
@ -582,21 +601,21 @@ void drawCharacter(uint8 flag) {
|
||||
|
||||
_shadowIntens[_shadowLightNum] = SHADOWAMBIENT;
|
||||
|
||||
if (tz > tx) { // if it's out of the falloff
|
||||
if (tz > tx) { // if it's out of the falloff
|
||||
lint = 0;
|
||||
_shadowIntens[_shadowLightNum] = 0;
|
||||
} else if (tz > ty) { // if it's between the falloff and the hotspot
|
||||
} else if (tz > ty) { // if it's between the falloff and the hotspot
|
||||
lint = (int)((float)lint * (tx - tz) / (tx - ty));
|
||||
_shadowIntens[_shadowLightNum] = (int)((float)_shadowIntens[_shadowLightNum] * (tx - tz) / (tx - ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((_curLight->_inten & 0x80) && lint) { // if it's shadowed and still on
|
||||
if ((_curLight->_inten & 0x80) && lint) { // if it's shadowed and still on
|
||||
_curVertex = actor->_vertex;
|
||||
|
||||
// casts shadow vertices
|
||||
for (int a = 0; a < _shadowVertsNum; a++) {
|
||||
for (int a = 0; a < SHADOWVERTSNUM; a++) {
|
||||
pa0 = _curVertex[_shadowVerts[a]]._x;
|
||||
pa1 = _curVertex[_shadowVerts[a]]._y;
|
||||
pa2 = _curVertex[_shadowVerts[a]]._z;
|
||||
@ -610,7 +629,7 @@ void drawCharacter(uint8 flag) {
|
||||
// _shadowIntens[_shadowLightNum] = SHADOWAMBIENT;
|
||||
|
||||
_shadowLightNum++;
|
||||
_totalShadowVerts += _shadowVertsNum;
|
||||
_totalShadowVerts += SHADOWVERTSNUM;
|
||||
}
|
||||
|
||||
if (lint) { // if still on
|
||||
@ -661,7 +680,7 @@ void drawCharacter(uint8 flag) {
|
||||
pa1 = ty - _shVertex[a]._y;
|
||||
}
|
||||
|
||||
pa0 = tx - (l0 * cost + l1 * sint); // rotate _curVertex
|
||||
pa0 = tx - (l0 * cost + l1 * sint); // rotate _curVertex
|
||||
pa2 = tz - (-l0 * sint + l1 * cost);
|
||||
|
||||
l0 = pa0 * e10 + pa1 * e11 + pa2 * e12; // project _curVertex
|
||||
@ -706,10 +725,10 @@ void drawCharacter(uint8 flag) {
|
||||
setClipping(0, actor->_lim[2], MAXX, actor->_lim[3]);
|
||||
|
||||
for (int b = 0; b < _shadowLightNum; b++) {
|
||||
for (int a = 0; a < _shadowFacesNum; a++) {
|
||||
int p0 = _shadowFaces[a][0] + vertexNum + b * _shadowVertsNum;
|
||||
int p1 = _shadowFaces[a][1] + vertexNum + b * _shadowVertsNum;
|
||||
int p2 = _shadowFaces[a][2] + vertexNum + b * _shadowVertsNum;
|
||||
for (int a = 0; a < SHADOWFACESNUM; a++) {
|
||||
int p0 = _shadowFaces[a][0] + vertexNum + b * SHADOWVERTSNUM;
|
||||
int p1 = _shadowFaces[a][1] + vertexNum + b * SHADOWVERTSNUM;
|
||||
int p2 = _shadowFaces[a][2] + vertexNum + b * SHADOWVERTSNUM;
|
||||
|
||||
int px0 = _vVertex[p0]._x;
|
||||
int py0 = _vVertex[p0]._y;
|
||||
@ -753,8 +772,8 @@ void drawCharacter(uint8 flag) {
|
||||
for (int a = 1; a < _zBufWid; a++) {
|
||||
// CHECKME: These are always 0
|
||||
//bool _shadowSplit;
|
||||
int py1 = 0; //(_zBuf[p0] >= 0x7FF0) * 0x8000 * _shadowSplit;
|
||||
int py2 = 0; //(_zBuf[p0 + 1] >= 0x7FF0) * 0x8000 * _shadowSplit;
|
||||
int py1 = 0; //(_zBuf[p0] >= 0x7FF0) * 0x8000 * _shadowSplit;
|
||||
int py2 = 0; //(_zBuf[p0 + 1] >= 0x7FF0) * 0x8000 * _shadowSplit;
|
||||
|
||||
int p1 = _zBuf[p0] < 0x7FFF;
|
||||
int p2 = _zBuf[p0 + 1] < 0x7FFF;
|
||||
@ -763,8 +782,8 @@ void drawCharacter(uint8 flag) {
|
||||
int px1 = _curPage[px0 + a - 1];
|
||||
int px2 = _curPage[px0 + a];
|
||||
|
||||
_curPage[px0 + a - 1] = g_vm->_graphicsMgr->aliasing(px1, px2, 6); // 75% 25%
|
||||
_curPage[px0 + a] = g_vm->_graphicsMgr->aliasing(px1, px2, 2); // 25% 75%
|
||||
_curPage[px0 + a - 1] = _vm->_graphicsMgr->aliasing(px1, px2, 6); // 75% 25%
|
||||
_curPage[px0 + a] = _vm->_graphicsMgr->aliasing(px1, px2, 2); // 25% 75%
|
||||
|
||||
// if the first is the character
|
||||
if (p1)
|
89
engines/trecision/3d.h
Normal file
89
engines/trecision/3d.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_3D_H
|
||||
#define TRECISION_3D_H
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/trecision.h"
|
||||
|
||||
namespace Trecision {
|
||||
struct SVVertex {
|
||||
int32 _x, _y, _z;
|
||||
int32 _angle;
|
||||
};
|
||||
|
||||
class Renderer3D {
|
||||
private:
|
||||
TrecisionEngine *_vm;
|
||||
|
||||
int16 _minXClip;
|
||||
int16 _minYClip;
|
||||
int16 _maxXClip;
|
||||
int16 _maxYClip;
|
||||
|
||||
int16 *_zBuf;
|
||||
|
||||
int16 _zBufStartX;
|
||||
int16 _zBufStartY;
|
||||
int16 _zBufWid;
|
||||
|
||||
int16 _shadowLightNum;
|
||||
int16 _totalShadowVerts;
|
||||
uint8 _shadowIntens[10];
|
||||
|
||||
uint16 *_curPage;
|
||||
|
||||
SVVertex _vVertex[MAXVERTEX];
|
||||
SVertex _shVertex[MAXVERTEX];
|
||||
|
||||
// data for the triangle routines
|
||||
int16 _lEdge[480];
|
||||
int16 _rEdge[480];
|
||||
uint8 _lColor[480];
|
||||
uint8 _rColor[480];
|
||||
int16 _lZ[480];
|
||||
int16 _rZ[480];
|
||||
uint16 _lTextX[480];
|
||||
uint16 _rTextX[480];
|
||||
uint16 _lTextY[480];
|
||||
uint16 _rTextY[480];
|
||||
|
||||
void setZBufferRegion(int16 sx, int16 sy, int16 dx);
|
||||
int8 clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3);
|
||||
|
||||
public:
|
||||
Renderer3D(TrecisionEngine *vm);
|
||||
~Renderer3D();
|
||||
|
||||
void textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2, int32 x3, int32 y3, int32 z3, int32 c3, int32 tx3, int32 ty3, STexture *t);
|
||||
void textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2);
|
||||
void shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint8 cv, int32 zv);
|
||||
void shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
void init3DRoom(uint16 *destBuffer, int16 *zBuffer);
|
||||
void setClipping(int16 x1, int16 y1, int16 x2, int16 y2);
|
||||
void drawCharacter(uint8 flag);
|
||||
};
|
||||
// end of class
|
||||
|
||||
} // end of namespace
|
||||
#endif
|
||||
|
@ -23,9 +23,11 @@
|
||||
#ifndef TRECISION_ACTOR_H
|
||||
#define TRECISION_ACTOR_H
|
||||
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/trecision.h"
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
class Actor {
|
||||
private:
|
||||
TrecisionEngine *_vm;
|
||||
@ -63,10 +65,7 @@ public:
|
||||
void actorDoAction(int action);
|
||||
void actorStop();
|
||||
void read3D(Common::SeekableReadStream *ff);
|
||||
};
|
||||
|
||||
|
||||
; // end of class
|
||||
}; // end of class
|
||||
|
||||
} // end of namespace
|
||||
#endif
|
||||
|
@ -2299,4 +2299,21 @@ enum InventoryItem {
|
||||
#define PATCHOBJ_ROOM41D 89
|
||||
#define PATCHOBJ_ROOM2C 20
|
||||
|
||||
// 3D Rendering
|
||||
#define MAXVERTEX 1000
|
||||
#define MAXFACE 1000
|
||||
|
||||
#define CALCPOINTS 1
|
||||
#define DRAWFACES 2
|
||||
#define DOALL 3
|
||||
|
||||
#define TEXTUREACTIVE 1
|
||||
#define TEXTUREPLANAR 2
|
||||
#define TEXTURECYLIND 4
|
||||
#define TEXTURELATERAL 8
|
||||
|
||||
#define SHADOWAMBIENT 27 // 0 (black) ... 127 (blank) shadow colors - opposite
|
||||
#define LIGHTRANGE 2048.0 // after 127 * val the light doesn't have an effect (deleted)
|
||||
#define CHARACTERMIDSIZE 91.0 // character half height
|
||||
|
||||
#endif
|
||||
|
@ -23,13 +23,14 @@
|
||||
#include "common/config-manager.h"
|
||||
|
||||
#include "trecision/nl/3d/3dinc.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/nl/extern.h"
|
||||
#include "trecision/nl/message.h"
|
||||
#include "trecision/nl/proto.h"
|
||||
#include "trecision/nl/struct.h"
|
||||
#include "trecision/logic.h"
|
||||
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/3d.h"
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/sound.h"
|
||||
@ -577,7 +578,7 @@ void LogicManager::endChangeRoom() {
|
||||
setPosition(14);
|
||||
else if ((_vm->_oldRoom == kRoom41D) && (_vm->_inventoryObj[kItemPositioner]._flag & kObjFlagExtra)) {
|
||||
setPosition(30);
|
||||
drawCharacter(CALCPOINTS);
|
||||
_vm->_renderer->drawCharacter(CALCPOINTS);
|
||||
}
|
||||
|
||||
// FullMotion
|
||||
|
@ -13,6 +13,7 @@ MODULE_OBJS = \
|
||||
script.o \
|
||||
trecision.o \
|
||||
utils.o \
|
||||
3d.o \
|
||||
video.o \
|
||||
nl/do.o \
|
||||
nl/globvar.o \
|
||||
@ -21,7 +22,6 @@ MODULE_OBJS = \
|
||||
nl/schedule.o \
|
||||
nl/string.o \
|
||||
nl/3d/3dact.o \
|
||||
nl/3d/3drend.o \
|
||||
nl/3d/3dvar.o \
|
||||
nl/3d/3dwalk.o \
|
||||
nl/ll/llmouse.o \
|
||||
|
@ -23,7 +23,6 @@
|
||||
#define TRECISION_3DINC_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "trecision/nl/3d/3drend.h"
|
||||
|
||||
/*--------------------------------------------------
|
||||
Useful global variables:
|
||||
@ -155,11 +154,6 @@ int actionInRoom(int curA);
|
||||
void setPosition(int num);
|
||||
void goToPosition(int num);
|
||||
void lookAt(float x, float z);
|
||||
void textureTriangle(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2, int32 x3, int32 y3, int32 z3, int32 c3, int32 tx3, int32 ty3, STexture *t);
|
||||
void textureScanEdge(int32 x1, int32 y1, int32 z1, int32 c1, int32 tx1, int32 ty1, int32 x2, int32 y2, int32 z2, int32 c2, int32 tx2, int32 ty2);
|
||||
void shadowTriangle(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint8 cv, int32 zv);
|
||||
void shadowScanEdge(int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
int8 clockWise(int16 x1, int16 y1, int16 x2, int16 y2, int16 x3, int16 y3);
|
||||
int read3D(Common::String c);
|
||||
void findPath();
|
||||
void findShortPath();
|
||||
|
@ -1,93 +0,0 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRECISION_3DREND_H
|
||||
#define TRECISION_3DREND_H
|
||||
|
||||
#define MAXVERTEX 1000
|
||||
#define MAXFACE 1000
|
||||
|
||||
#define CALCPOINTS 1
|
||||
#define DRAWFACES 2
|
||||
#define DOALL 3
|
||||
|
||||
#define TEXTUREACTIVE 1
|
||||
#define TEXTUREPLANAR 2
|
||||
#define TEXTURECYLIND 4
|
||||
#define TEXTURELATERAL 8
|
||||
|
||||
#define SHADOWAMBIENT 27 // 0 (black) ... 127 (blank) shadow colors - opposite
|
||||
#define LIGHTRANGE 2048.0 // after 127 * val the light doesn't have an effect (deleted)
|
||||
#define CHARACTERMIDSIZE 91.0 // character half height
|
||||
|
||||
namespace Trecision {
|
||||
|
||||
struct SVertex {
|
||||
float _x, _y, _z;
|
||||
float _nx, _ny, _nz;
|
||||
};
|
||||
|
||||
struct SFace {
|
||||
uint16 _a, _b, _c;
|
||||
uint16 _mat;
|
||||
};
|
||||
|
||||
struct SLight {
|
||||
float _x, _y, _z;
|
||||
float _dx, _dy, _dz;
|
||||
float _inr, _outr;
|
||||
uint8 _hotspot;
|
||||
uint8 _fallOff;
|
||||
int8 _inten;
|
||||
int8 _position;
|
||||
};
|
||||
|
||||
struct SCamera {
|
||||
float _ex, _ey, _ez;
|
||||
float _e1[3];
|
||||
float _e2[3];
|
||||
float _e3[3];
|
||||
float _fovX, _fovY;
|
||||
};
|
||||
|
||||
struct STexture {
|
||||
int16 _dx, _dy, _angle;
|
||||
uint8 *_texture;
|
||||
uint8 _flag;
|
||||
};
|
||||
|
||||
/*------------------------------------------------
|
||||
Initialize a 3D Room
|
||||
--------------------------------------------------*/
|
||||
void init3DRoom(uint16 *destBuffer, int16 *zBuffer);
|
||||
/*------------------------------------------------
|
||||
Change the clipping area
|
||||
--------------------------------------------------*/
|
||||
void setClipping(int16 x1, int16 y1, int16 x2, int16 y2);
|
||||
/*------------------------------------------------
|
||||
Draw the character
|
||||
--------------------------------------------------*/
|
||||
void drawCharacter(uint8 flag);
|
||||
|
||||
} // End of namespace Trecision
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include "common/util.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "trecision/3d.h"
|
||||
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/nl/extern.h"
|
||||
@ -102,8 +103,8 @@ int read3D(Common::String filename) {
|
||||
|
||||
initSortPan();
|
||||
|
||||
init3DRoom(g_vm->_screenBuffer, g_vm->_zBuffer);
|
||||
setClipping(0, TOP, MAXX, AREA + TOP);
|
||||
g_vm->_renderer->init3DRoom(g_vm->_screenBuffer, g_vm->_zBuffer);
|
||||
g_vm->_renderer->setClipping(0, TOP, MAXX, AREA + TOP);
|
||||
|
||||
return 10L;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "trecision/3d.h"
|
||||
|
||||
#include "trecision/nl/3d/3dinc.h"
|
||||
#include "trecision/defines.h"
|
||||
@ -247,7 +248,7 @@ void PaintObjAnm(uint16 CurBox) {
|
||||
}
|
||||
|
||||
if (_actorPos == CurBox && g_vm->_flagShowCharacter && g_vm->_flagCharacterExists) {
|
||||
drawCharacter(CALCPOINTS);
|
||||
g_vm->_renderer->drawCharacter(CALCPOINTS);
|
||||
|
||||
int x1 = g_vm->_actor->_lim[0];
|
||||
int y1 = g_vm->_actor->_lim[2];
|
||||
@ -263,7 +264,7 @@ void PaintObjAnm(uint16 CurBox) {
|
||||
g_vm->resetZBuffer(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
drawCharacter(DRAWFACES);
|
||||
g_vm->_renderer->drawCharacter(DRAWFACES);
|
||||
|
||||
} else if (_actorPos == CurBox && !g_vm->_flagDialogActive) {
|
||||
g_vm->_animMgr->refreshSmkAnim(g_vm->_animMgr->_playingAnims[kSmackerAction]);
|
||||
|
@ -20,19 +20,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "trecision/3d.h"
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/dialog.h"
|
||||
#include "trecision/logic.h"
|
||||
#include "trecision/graphics.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/nl/proto.h"
|
||||
#include "trecision/nl/message.h"
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/sound.h"
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/scaler.h"
|
||||
#include "nl/extern.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include "trecision/nl/proto.h"
|
||||
#include "trecision/nl/message.h"
|
||||
#include "trecision/nl/extern.h"
|
||||
|
||||
|
||||
namespace Trecision {
|
||||
@ -443,7 +445,7 @@ void TrecisionEngine::doSystem() {
|
||||
_logicMgr->endChangeRoom();
|
||||
|
||||
_room[_curRoom]._flag |= kObjFlagDone; // Visited
|
||||
drawCharacter(CALCPOINTS); // for right _actorPos entrance
|
||||
_renderer->drawCharacter(CALCPOINTS); // for right _actorPos entrance
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -21,8 +21,9 @@
|
||||
*/
|
||||
|
||||
#include "trecision/trecision.h"
|
||||
#include "trecision/actor.h"
|
||||
#include "trecision/3d.h"
|
||||
|
||||
#include "actor.h"
|
||||
#include "trecision/nl/3d/3dinc.h"
|
||||
#include "trecision/defines.h"
|
||||
#include "trecision/nl/extern.h"
|
||||
@ -124,7 +125,8 @@ TrecisionEngine::TrecisionEngine(OSystem *syst) : Engine(syst) {
|
||||
_graphicsMgr = nullptr;
|
||||
_logicMgr = nullptr;
|
||||
_soundMgr = nullptr;
|
||||
|
||||
_renderer = nullptr;
|
||||
|
||||
_actorRect = nullptr;
|
||||
_nextRefresh = 0;
|
||||
|
||||
@ -186,7 +188,8 @@ TrecisionEngine::~TrecisionEngine() {
|
||||
delete _graphicsMgr;
|
||||
delete _logicMgr;
|
||||
delete _soundMgr;
|
||||
|
||||
delete _renderer;
|
||||
|
||||
delete[] _font;
|
||||
delete[] _arrows;
|
||||
delete[] _textureArea;
|
||||
|
@ -33,7 +33,6 @@
|
||||
|
||||
#include "common/str-array.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/serializer.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "common/str.h"
|
||||
|
||||
@ -45,6 +44,7 @@ class GraphicsManager;
|
||||
class LogicManager;
|
||||
class SoundManager;
|
||||
class Actor;
|
||||
class Renderer3D;
|
||||
|
||||
#define SAVE_VERSION_ORIGINAL 102
|
||||
#define SAVE_VERSION_SCUMMVM 103
|
||||
@ -70,6 +70,40 @@ enum TrecisionMessageIds {
|
||||
|
||||
typedef Common::List<Common::Rect>::iterator DirtyRectsIterator;
|
||||
|
||||
struct SVertex {
|
||||
float _x, _y, _z;
|
||||
float _nx, _ny, _nz;
|
||||
};
|
||||
|
||||
struct SFace {
|
||||
uint16 _a, _b, _c;
|
||||
uint16 _mat;
|
||||
};
|
||||
|
||||
struct SLight {
|
||||
float _x, _y, _z;
|
||||
float _dx, _dy, _dz;
|
||||
float _inr, _outr;
|
||||
uint8 _hotspot;
|
||||
uint8 _fallOff;
|
||||
int8 _inten;
|
||||
int8 _position;
|
||||
};
|
||||
|
||||
struct SCamera {
|
||||
float _ex, _ey, _ez;
|
||||
float _e1[3];
|
||||
float _e2[3];
|
||||
float _e3[3];
|
||||
float _fovX, _fovY;
|
||||
};
|
||||
|
||||
struct STexture {
|
||||
int16 _dx, _dy, _angle;
|
||||
uint8 *_texture;
|
||||
uint8 _flag;
|
||||
};
|
||||
|
||||
class TrecisionEngine : public Engine {
|
||||
void initMain();
|
||||
void initMessageSystem();
|
||||
@ -271,6 +305,7 @@ public:
|
||||
DialogManager *_dialogMgr;
|
||||
LogicManager *_logicMgr;
|
||||
SoundManager *_soundMgr;
|
||||
Renderer3D *_renderer;
|
||||
|
||||
uint8 *_font;
|
||||
uint16 *_arrows;
|
||||
|
Loading…
x
Reference in New Issue
Block a user