3D planet uses now phong lighting, from PhracturedBlue
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@436 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -59,8 +59,22 @@ DWORD **getpixelarray(FRAME FramePtr,int width, int height);
|
|||||||
//RADIUS^2
|
//RADIUS^2
|
||||||
#define RADIUS_2 (RADIUS * RADIUS)
|
#define RADIUS_2 (RADIUS * RADIUS)
|
||||||
#define DIAMETER (TWORADIUS + 1)
|
#define DIAMETER (TWORADIUS + 1)
|
||||||
#define PHONG_BITS 24
|
#define DIFFUSE_BITS 24
|
||||||
#define GET_PHONG(val, ph) ((((val)<<PHONG_BITS)-((val)*ph))>>PHONG_BITS)
|
|
||||||
|
//#define GET_LIGHT(val, dif, sp) \
|
||||||
|
// ( (UBYTE)min ((sp) + \
|
||||||
|
// ( ( ( (DWORD)(val) << DIFFUSE_BITS ) - (DWORD)(val) * (dif) ) >> DIFFUSE_BITS ) \
|
||||||
|
// , 255) )
|
||||||
|
UBYTE GET_LIGHT (UBYTE val, DWORD dif, UBYTE sp)
|
||||||
|
{
|
||||||
|
DWORD i = (DWORD)val << DIFFUSE_BITS;
|
||||||
|
i -= val * dif;
|
||||||
|
i >>= DIFFUSE_BITS;
|
||||||
|
i += sp;
|
||||||
|
if (i > 255)
|
||||||
|
i = 255;
|
||||||
|
return ((UBYTE)i);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef M_TWOPI
|
#ifndef M_TWOPI
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
@@ -72,7 +86,8 @@ DWORD **getpixelarray(FRAME FramePtr,int width, int height);
|
|||||||
#define M_DEG2RAD (M_TWOPI / 360.0)
|
#define M_DEG2RAD (M_TWOPI / 360.0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DWORD phong[DIAMETER][DIAMETER];
|
DWORD light_diff[DIAMETER][DIAMETER];
|
||||||
|
UBYTE light_spec[DIAMETER][DIAMETER];
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
POINT p[4];
|
POINT p[4];
|
||||||
@@ -80,6 +95,9 @@ typedef struct
|
|||||||
} MAP3D_POINT;
|
} MAP3D_POINT;
|
||||||
MAP3D_POINT map_rotate[DIAMETER][DIAMETER];
|
MAP3D_POINT map_rotate[DIAMETER][DIAMETER];
|
||||||
//POINT map_rotate[DIAMETER][DIAMETER];
|
//POINT map_rotate[DIAMETER][DIAMETER];
|
||||||
|
typedef struct {
|
||||||
|
double x, y, z;
|
||||||
|
} POINT3;
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderTopography (BOOLEAN Reconstruct)
|
RenderTopography (BOOLEAN Reconstruct)
|
||||||
@@ -204,68 +222,110 @@ RenderTopography (BOOLEAN Reconstruct)
|
|||||||
SetContext (OldContext);
|
SetContext (OldContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void P3mult (POINT3 *res, POINT3 *vec, double cnst)
|
||||||
|
{
|
||||||
|
res->x = vec->x * cnst;
|
||||||
|
res->y = vec->y * cnst;
|
||||||
|
res->z = vec->z * cnst;
|
||||||
|
}
|
||||||
|
void P3sub (POINT3 *res, POINT3 *v1, POINT3 *v2)
|
||||||
|
{
|
||||||
|
res->x = v1->x - v2->x;
|
||||||
|
res->y = v1->y - v2->y;
|
||||||
|
res->z = v1->z - v2->z;
|
||||||
|
}
|
||||||
|
double P3dot (POINT3 *v1, POINT3 *v2)
|
||||||
|
{
|
||||||
|
return (v1->x * v2->x + v1->y * v2->y + v1->z * v2->z);
|
||||||
|
}
|
||||||
|
void P3norm (POINT3 *res, POINT3 *vec)
|
||||||
|
{
|
||||||
|
double mag = sqrt (P3dot (vec, vec));
|
||||||
|
P3mult (res, vec, 1/mag);
|
||||||
|
}
|
||||||
|
|
||||||
// RenderPhongMask builds a shadow map for the rotating planet
|
// RenderPhongMask builds a shadow map for the rotating planet
|
||||||
// loc indicates the planets position relavtive to the sun
|
// loc indicates the planets position relavtive to the sun
|
||||||
static void
|
static void
|
||||||
RenderPhongMask (POINT loc)
|
RenderPhongMask (POINT loc)
|
||||||
{
|
{
|
||||||
POINT pt, light;
|
POINT pt;
|
||||||
|
POINT3 light, view;
|
||||||
double lrad;
|
double lrad;
|
||||||
int lmag;
|
|
||||||
DWORD step;
|
DWORD step;
|
||||||
double lmag2;
|
|
||||||
int y, x;
|
int y, x;
|
||||||
|
|
||||||
#define LIGHT_MULT 0.8
|
#define LIGHT_INTENS 0.4
|
||||||
#define AMBIENT_LIGHT 0.05
|
#define AMBIENT_LIGHT 0.1
|
||||||
#define LIGHT_RADIUS 1.6
|
#define MSHI 2
|
||||||
light.x = (int)(LIGHT_MULT * RADIUS *
|
#define LIGHT_Z 1.2
|
||||||
cos (atan2 (-(double)loc.y, -(double)loc.x)));
|
// lrad is the distance from the sun to the planet
|
||||||
light.y = (int)(LIGHT_MULT * RADIUS *
|
lrad = sqrt (loc.x * loc.x + loc.y * loc.y);
|
||||||
sin (atan2 (-(double)loc.y, -(double)loc.x)));
|
// light is the sun's position. the z-coordinate is whatever
|
||||||
// light.x=(int)(RADIUS*0.8);
|
// looks good
|
||||||
// light.y=(int)(-RADIUS*0.6);
|
light.x = -((double)loc.x);
|
||||||
// fprintf(stderr,"light: (%d,%d)->(%d,%d)\n",loc.x,loc.y,light.x,light.y);
|
light.y = -((double)loc.y);
|
||||||
lmag = (int)(LIGHT_RADIUS * RADIUS);
|
light.z = LIGHT_Z * lrad;
|
||||||
lmag2 = lmag * lmag;
|
P3norm (&light, &light);
|
||||||
step = 1 << PHONG_BITS;
|
// always view along the z-axis
|
||||||
|
// ideally use a view point, and have the view change per pixel
|
||||||
|
// but that is too much effort for now.
|
||||||
|
// the view MUST be normalized!
|
||||||
|
view.x = 0;
|
||||||
|
view.y = 0;
|
||||||
|
view.z = 1.0;
|
||||||
|
step = 1 << DIFFUSE_BITS;
|
||||||
for (pt.y = 0, y = -RADIUS; pt.y <= TWORADIUS; ++pt.y, y++)
|
for (pt.y = 0, y = -RADIUS; pt.y <= TWORADIUS; ++pt.y, y++)
|
||||||
{
|
{
|
||||||
int y_2, deltay_2;
|
DWORD y_2;
|
||||||
y_2 = y * y;
|
y_2 = y * y;
|
||||||
deltay_2 = (y - light.y) * (y - light.y);
|
|
||||||
for (pt.x = 0, x = -RADIUS; pt.x <= TWORADIUS; ++pt.x, x++)
|
for (pt.x = 0, x = -RADIUS; pt.x <= TWORADIUS; ++pt.x, x++)
|
||||||
{
|
{
|
||||||
int rad;
|
DWORD x_2, rad_2, stepint;
|
||||||
DWORD stepint;
|
POINT3 norm, rvec;
|
||||||
double lrad2;
|
double diff, spec = 0.0, fb;
|
||||||
double intens;
|
x_2 = x * x;
|
||||||
rad = x * x + y_2;
|
rad_2 = x_2 + y_2;
|
||||||
if (rad <= RADIUS_2)
|
if (rad_2 <= RADIUS_2)
|
||||||
{
|
{
|
||||||
lrad = ((x - light.x) * (x - light.x) + deltay_2);
|
// norm is the sphere's surface normal.
|
||||||
lrad2 = lrad;
|
norm.x = (double)x;
|
||||||
//lrad2=pow(lrad,1);
|
norm.y = (double)y;
|
||||||
if (lrad2 >= lmag2)
|
norm.z = (sqrt (RADIUS_2 - x_2) * sqrt (RADIUS_2 - y_2)) / RADIUS;
|
||||||
intens = AMBIENT_LIGHT;
|
P3norm(&norm,&norm);
|
||||||
|
// diffuse component is norm dot light
|
||||||
|
diff =P3dot (&norm, &light);
|
||||||
|
// negative diffuse is bad
|
||||||
|
if(diff < 0)
|
||||||
|
diff = 0.0;
|
||||||
|
// specular highlight is the phong equation: (rvec dot view)^MSHI
|
||||||
|
// where rvec = (2*diff)*norm - light (reflection of light around norm)
|
||||||
|
P3mult (&rvec,&norm,2 * diff);
|
||||||
|
P3sub (&rvec, &rvec, &light);
|
||||||
|
fb = P3dot (&rvec, &view);
|
||||||
|
if (fb > 0.0)
|
||||||
|
spec = LIGHT_INTENS * pow (fb, MSHI);
|
||||||
else
|
else
|
||||||
{
|
spec = 0;
|
||||||
intens = 1 * cos ((M_PI / 2) * (double)lrad2 / (double)lmag2);
|
// adjust for the ambient light
|
||||||
if (intens < AMBIENT_LIGHT)
|
if (diff < AMBIENT_LIGHT)
|
||||||
intens = AMBIENT_LIGHT;
|
diff = AMBIENT_LIGHT;
|
||||||
}
|
// stepint allows us multiply by a ratio without usig floating-point
|
||||||
stepint = step - (DWORD)(intens * step + 0.5);
|
// instead of color*diff, we use ((color << 24) - stepint*color) >> 24
|
||||||
if(rad > (RADIUS - 1) * (RADIUS - 1))
|
stepint = step - (DWORD)(diff * step + 0.5);
|
||||||
|
// Now we antialias the edge of the spere to look nice
|
||||||
|
if(rad_2 > (RADIUS - 1) * (RADIUS - 1))
|
||||||
{
|
{
|
||||||
DWORD r;
|
DWORD r;
|
||||||
r = rad - (RADIUS - 1) * (RADIUS - 1);
|
r = rad_2 - (RADIUS - 1) * (RADIUS - 1);
|
||||||
stepint += (step >> 7) * (r + 1);
|
stepint += (step >> 7) * (r + 1);
|
||||||
if (stepint > step)
|
if (stepint > step)
|
||||||
stepint = step;
|
stepint = step;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
stepint = step;
|
stepint = 1 << 31;
|
||||||
phong[pt.y][pt.x] = (int)stepint;
|
light_diff[pt.y][pt.x] = (DWORD)stepint;
|
||||||
|
light_spec[pt.y][pt.x] = (UBYTE)(spec*255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,7 +572,6 @@ RenderLevelMasks (int offset)
|
|||||||
clock_t t1;
|
clock_t t1;
|
||||||
t1 = clock ();
|
t1 = clock ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rgba = (DWORD *)HMalloc (sizeof (DWORD *) * (DIAMETER) * (DIAMETER));
|
rgba = (DWORD *)HMalloc (sizeof (DWORD *) * (DIAMETER) * (DIAMETER));
|
||||||
p_rgba = rgba;
|
p_rgba = rgba;
|
||||||
// Choose the correct Frame to wrte to
|
// Choose the correct Frame to wrte to
|
||||||
@@ -523,12 +582,14 @@ RenderLevelMasks (int offset)
|
|||||||
for (pt.x = 0, x = -RADIUS; pt.x <= TWORADIUS; ++pt.x, ++x)
|
for (pt.x = 0, x = -RADIUS; pt.x <= TWORADIUS; ++pt.x, ++x)
|
||||||
{
|
{
|
||||||
UBYTE c[3];
|
UBYTE c[3];
|
||||||
int ph;
|
DWORD diffus;
|
||||||
|
UBYTE spec;
|
||||||
COUNT i;
|
COUNT i;
|
||||||
DWORD p1[4];
|
DWORD p1[4];
|
||||||
MAP3D_POINT *ppt = &map_rotate[pt.y][pt.x];
|
MAP3D_POINT *ppt = &map_rotate[pt.y][pt.x];
|
||||||
ph = phong[pt.y][pt.x];
|
diffus = light_diff[pt.y][pt.x];
|
||||||
if (ph < 1 << PHONG_BITS)
|
spec = light_spec[pt.y][pt.x];
|
||||||
|
if (diffus < 1 << DIFFUSE_BITS)
|
||||||
{
|
{
|
||||||
if (ppt->m[0] == 0)
|
if (ppt->m[0] == 0)
|
||||||
{
|
{
|
||||||
@@ -544,18 +605,18 @@ RenderLevelMasks (int offset)
|
|||||||
for (i = 1; i < 4; i++)
|
for (i = 1; i < 4; i++)
|
||||||
c[i-1] = get_avg_rgb (p1, ppt->m, i);
|
c[i-1] = get_avg_rgb (p1, ppt->m, i);
|
||||||
}
|
}
|
||||||
// Apply the lightinng model. This also bounds the sphere to make it circular
|
// Apply the lighting model. This also bounds the sphere to make it circular
|
||||||
if (pSolarSysState->ShieldFrame)
|
if (pSolarSysState->ShieldFrame)
|
||||||
{
|
{
|
||||||
c[2] = GET_PHONG (255, ph);
|
c[2] = GET_LIGHT (255, diffus, spec);
|
||||||
c[1] = GET_PHONG (c[1] >> 1, ph);
|
c[1] = GET_LIGHT ((UBYTE)(c[1] >> 1), diffus, spec);
|
||||||
c[0] = GET_PHONG (c[0] >> 1, ph);
|
c[0] = GET_LIGHT ((UBYTE)(c[0] >> 1), diffus, spec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c[2] = GET_PHONG (c[2], ph);
|
c[2] = GET_LIGHT (c[2], diffus, spec);
|
||||||
c[1] = GET_PHONG (c[1], ph);
|
c[1] = GET_LIGHT (c[1], diffus, spec);
|
||||||
c[0] = GET_PHONG (c[0], ph);
|
c[0] = GET_LIGHT (c[0], diffus, spec);
|
||||||
}
|
}
|
||||||
*p_rgba++ = frame_mapRGBA (
|
*p_rgba++ = frame_mapRGBA (
|
||||||
MaskFrame, c[2], c[1], c[0], (UBYTE)255);
|
MaskFrame, c[2], c[1], c[0], (UBYTE)255);
|
||||||
|
|||||||
Reference in New Issue
Block a user