mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 14:01:45 +00:00
Add dynamic lights to pal slope drawer
This commit is contained in:
parent
087050c201
commit
18bc384807
5 changed files with 269 additions and 43 deletions
|
@ -1814,6 +1814,66 @@ namespace swrenderer
|
|||
return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)];
|
||||
}
|
||||
|
||||
uint8_t SWPalDrawers::AddLightsTilted(const DrawerLight* lights, int num_lights, float viewpos_x, float viewpos_y, float viewpos_z, float nx, float ny, float nz, uint8_t fg, uint8_t material)
|
||||
{
|
||||
uint32_t lit_r = 0;
|
||||
uint32_t lit_g = 0;
|
||||
uint32_t lit_b = 0;
|
||||
|
||||
// Screen space to view space
|
||||
viewpos_z = 1.0f / viewpos_z;
|
||||
viewpos_x *= viewpos_z;
|
||||
viewpos_y *= viewpos_y;
|
||||
|
||||
for (int i = 0; i < num_lights; i++)
|
||||
{
|
||||
uint32_t light_color_r = RPART(lights[i].color);
|
||||
uint32_t light_color_g = GPART(lights[i].color);
|
||||
uint32_t light_color_b = BPART(lights[i].color);
|
||||
|
||||
// L = light-pos
|
||||
// dist = sqrt(dot(L, L))
|
||||
// attenuation = 1 - min(dist * (1/radius), 1)
|
||||
float Lx = lights[i].x - viewpos_x;
|
||||
float Ly = lights[i].y - viewpos_y;
|
||||
float Lz = lights[i].z - viewpos_z;
|
||||
float dist2 = Lx * Lx + Ly * Ly + Lz * Lz;
|
||||
#ifdef NO_SSE
|
||||
float rcp_dist = 1.0f / (dist2 * 0.01f);
|
||||
#else
|
||||
float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
|
||||
#endif
|
||||
float dist = dist2 * rcp_dist;
|
||||
float distance_attenuation = (256.0f - min(dist * lights[i].radius, 256.0f));
|
||||
|
||||
// The simple light type
|
||||
float simple_attenuation = distance_attenuation;
|
||||
|
||||
// The point light type
|
||||
// diffuse = dot(N,L) * attenuation
|
||||
float dotNL = max(nx * Lx + ny * Ly + nz * Lz, 0.0f);
|
||||
float point_attenuation = dotNL * rcp_dist * distance_attenuation;
|
||||
uint32_t attenuation = (uint32_t)(lights[i].z == 0.0f ? simple_attenuation : point_attenuation);
|
||||
|
||||
lit_r += (light_color_r * attenuation) >> 8;
|
||||
lit_g += (light_color_g * attenuation) >> 8;
|
||||
lit_b += (light_color_b * attenuation) >> 8;
|
||||
}
|
||||
|
||||
if (lit_r == 0 && lit_g == 0 && lit_b == 0)
|
||||
return fg;
|
||||
|
||||
uint32_t material_r = GPalette.BaseColors[material].r;
|
||||
uint32_t material_g = GPalette.BaseColors[material].g;
|
||||
uint32_t material_b = GPalette.BaseColors[material].b;
|
||||
|
||||
lit_r = min<uint32_t>(GPalette.BaseColors[fg].r + ((lit_r * material_r) >> 8), 255);
|
||||
lit_g = min<uint32_t>(GPalette.BaseColors[fg].g + ((lit_g * material_g) >> 8), 255);
|
||||
lit_b = min<uint32_t>(GPalette.BaseColors[fg].b + ((lit_b * material_b) >> 8), 255);
|
||||
|
||||
return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)];
|
||||
}
|
||||
|
||||
void SWPalDrawers::DrawSpan(const SpanDrawerArgs& args)
|
||||
{
|
||||
const uint8_t* _source = args.TexturePixels();
|
||||
|
@ -2728,6 +2788,8 @@ namespace swrenderer
|
|||
x1 = 0;
|
||||
width++;
|
||||
|
||||
if (args.dc_num_lights == 0)
|
||||
{
|
||||
while (width >= SPANSIZE)
|
||||
{
|
||||
iz += izstep;
|
||||
|
@ -2786,6 +2848,81 @@ namespace swrenderer
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto lights = args.dc_lights;
|
||||
auto num_lights = args.dc_num_lights;
|
||||
auto normal = args.dc_normal;
|
||||
auto viewpos = args.dc_viewpos;
|
||||
auto dc_viewpos_step = args.dc_viewpos_step;
|
||||
while (width >= SPANSIZE)
|
||||
{
|
||||
iz += izstep;
|
||||
uz += uzstep;
|
||||
vz += vzstep;
|
||||
|
||||
double endz = 1.f / iz;
|
||||
double endu = uz * endz;
|
||||
double endv = vz * endz;
|
||||
uint32_t stepu = (uint32_t)int64_t((endu - startu) * INVSPAN);
|
||||
uint32_t stepv = (uint32_t)int64_t((endv - startv) * INVSPAN);
|
||||
u = (uint32_t)(int64_t(startu) + pviewx);
|
||||
v = (uint32_t)(int64_t(startv) + pviewy);
|
||||
|
||||
for (i = SPANSIZE - 1; i >= 0; i--)
|
||||
{
|
||||
uint8_t material = _source[(v >> vshift) | ((u >> ushift) & umask)];
|
||||
uint8_t fg = *(tiltlighting[x1] + material);
|
||||
fb[x1] = AddLightsTilted(lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z, fg, material);
|
||||
x1++;
|
||||
u += stepu;
|
||||
v += stepv;
|
||||
viewpos += dc_viewpos_step;
|
||||
}
|
||||
startu = endu;
|
||||
startv = endv;
|
||||
width -= SPANSIZE;
|
||||
}
|
||||
if (width > 0)
|
||||
{
|
||||
if (width == 1)
|
||||
{
|
||||
u = (uint32_t)int64_t(startu);
|
||||
v = (uint32_t)int64_t(startv);
|
||||
uint8_t material = _source[(v >> vshift) | ((u >> ushift) & umask)];
|
||||
uint8_t fg = *(tiltlighting[x1] + material);
|
||||
fb[x1] = AddLightsTilted(lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z, fg, material);
|
||||
}
|
||||
else
|
||||
{
|
||||
double left = width;
|
||||
iz += plane_sz[0] * left;
|
||||
uz += plane_su[0] * left;
|
||||
vz += plane_sv[0] * left;
|
||||
|
||||
double endz = 1.f / iz;
|
||||
double endu = uz * endz;
|
||||
double endv = vz * endz;
|
||||
left = 1.f / left;
|
||||
uint32_t stepu = (uint32_t)int64_t((endu - startu) * left);
|
||||
uint32_t stepv = (uint32_t)int64_t((endv - startv) * left);
|
||||
u = (uint32_t)(int64_t(startu) + pviewx);
|
||||
v = (uint32_t)(int64_t(startv) + pviewy);
|
||||
|
||||
for (; width != 0; width--)
|
||||
{
|
||||
uint8_t material = _source[(v >> vshift) | ((u >> ushift) & umask)];
|
||||
uint8_t fg = *(tiltlighting[x1] + material);
|
||||
fb[x1] = AddLightsTilted(lights, num_lights, viewpos.X, viewpos.Y, viewpos.Z, normal.X, normal.Y, normal.Z, fg, material);
|
||||
x1++;
|
||||
u += stepu;
|
||||
v += stepv;
|
||||
viewpos += dc_viewpos_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ namespace swrenderer
|
|||
|
||||
inline static uint8_t AddLightsColumn(const DrawerLight* lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material);
|
||||
inline static uint8_t AddLightsSpan(const DrawerLight* lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material);
|
||||
inline static uint8_t AddLightsTilted(const DrawerLight* lights, int num_lights, float viewpos_x, float viewpos_y, float viewpos_z, float nx, float ny, float nz, uint8_t fg, uint8_t material);
|
||||
inline static uint8_t AddLights(uint8_t fg, uint8_t material, uint32_t lit_r, uint32_t lit_g, uint32_t lit_b);
|
||||
|
||||
void CalcTiltedLighting(double lstart, double lend, int width, int planeshade, uint8_t* basecolormapdata);
|
||||
|
|
|
@ -93,7 +93,10 @@ namespace swrenderer
|
|||
planeNormal.Y = worldNormal.X * viewport->viewpoint.Cos + worldNormal.Y * viewport->viewpoint.Sin;
|
||||
planeNormal.Z = worldNormal.Z;
|
||||
planeD = -planeNormal.Z * (pl->height.ZatPoint(viewport->viewpoint.Pos.X, viewport->viewpoint.Pos.Y) - viewport->viewpoint.Pos.Z);
|
||||
if (Thread->Portal->MirrorFlags & RF_XFLIP)
|
||||
planeNormal.X = -planeNormal.X;
|
||||
|
||||
light_list = pl->lights;
|
||||
|
||||
drawerargs.SetSolidColor(3);
|
||||
drawerargs.SetTexture(Thread, texture);
|
||||
|
@ -204,6 +207,84 @@ namespace swrenderer
|
|||
|
||||
void RenderSlopePlane::RenderLine(int y, int x1, int x2)
|
||||
{
|
||||
if (r_dynlights)
|
||||
{
|
||||
int tx = x1;
|
||||
bool mirror = !!(Thread->Portal->MirrorFlags & RF_XFLIP);
|
||||
if (mirror)
|
||||
tx = viewwidth - tx - 1;
|
||||
|
||||
// Find row position in view space
|
||||
DVector3 viewposX1 = Thread->Viewport->ScreenToViewPos(x1, y, planeNormal, planeD);
|
||||
DVector3 viewposX2 = Thread->Viewport->ScreenToViewPos(x2, y, planeNormal, planeD);
|
||||
|
||||
// Convert to screen space
|
||||
viewposX1.Z = 1.0 / viewposX1.Z;
|
||||
viewposX1.X *= viewposX1.Z;
|
||||
viewposX1.Y *= viewposX1.Z;
|
||||
viewposX2.Z = 1.0 / viewposX2.Z;
|
||||
viewposX2.X *= viewposX2.Z;
|
||||
viewposX2.Y *= viewposX2.Z;
|
||||
|
||||
drawerargs.dc_viewpos.X = viewposX1.X;
|
||||
drawerargs.dc_viewpos.Y = viewposX1.Y;
|
||||
drawerargs.dc_viewpos.Z = viewposX1.Z;
|
||||
drawerargs.dc_viewpos_step.X = viewposX2.X - viewposX1.X;
|
||||
drawerargs.dc_viewpos_step.Y = viewposX2.Y - viewposX1.Y;
|
||||
drawerargs.dc_viewpos_step.Z = viewposX2.Z - viewposX1.Z;
|
||||
|
||||
// Plane normal
|
||||
drawerargs.dc_normal.X = planeNormal.X;
|
||||
drawerargs.dc_normal.Y = planeNormal.Y;
|
||||
drawerargs.dc_normal.Z = planeNormal.Z;
|
||||
|
||||
// Calculate max lights that can touch the row so we can allocate memory for the list
|
||||
int max_lights = 0;
|
||||
VisiblePlaneLight* cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
max_lights++;
|
||||
cur_node = cur_node->next;
|
||||
}
|
||||
|
||||
drawerargs.dc_num_lights = 0;
|
||||
drawerargs.dc_lights = Thread->FrameMemory->AllocMemory<DrawerLight>(max_lights);
|
||||
|
||||
// Setup lights for row
|
||||
cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
{
|
||||
double lightX = cur_node->lightsource->X() - Thread->Viewport->viewpoint.Pos.X;
|
||||
double lightY = cur_node->lightsource->Y() - Thread->Viewport->viewpoint.Pos.Y;
|
||||
double lightZ = cur_node->lightsource->Z() - Thread->Viewport->viewpoint.Pos.Z;
|
||||
|
||||
float lx = (float)(lightX * Thread->Viewport->viewpoint.Sin - lightY * Thread->Viewport->viewpoint.Cos);
|
||||
float ly = (float)(lightX * Thread->Viewport->viewpoint.TanCos + lightY * Thread->Viewport->viewpoint.TanSin);
|
||||
float lz = (float)lightZ;
|
||||
|
||||
uint32_t red = cur_node->lightsource->GetRed();
|
||||
uint32_t green = cur_node->lightsource->GetGreen();
|
||||
uint32_t blue = cur_node->lightsource->GetBlue();
|
||||
|
||||
auto& light = drawerargs.dc_lights[drawerargs.dc_num_lights++];
|
||||
light.x = lx;
|
||||
light.y = ly;
|
||||
light.z = lz;
|
||||
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
}
|
||||
|
||||
cur_node = cur_node->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drawerargs.dc_num_lights = 0;
|
||||
}
|
||||
|
||||
drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, lightlevel, foggy, planelightfloat, pviewx, pviewy, basecolormap);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,5 +52,6 @@ namespace swrenderer
|
|||
|
||||
DVector3 planeNormal;
|
||||
double planeD;
|
||||
VisiblePlaneLight* light_list;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -82,6 +82,12 @@ namespace swrenderer
|
|||
return (CenterY - screenY - 0.5) / FocalLengthY * viewZ;
|
||||
}
|
||||
|
||||
DVector3 ScreenToViewPos(int screenX, int screenY, const DVector3& plane, double planeD)
|
||||
{
|
||||
double viewZ = -planeD / ((screenX + 0.5 - CenterX) / FocalLengthX * plane.X + (CenterY - screenY - 0.5) / FocalLengthY * plane.Y + plane.Z);
|
||||
return DVector3(ScreenToViewX(screenX, viewZ), ScreenToViewY(screenY, viewZ), viewZ);
|
||||
}
|
||||
|
||||
FLevelLocals *Level()
|
||||
{
|
||||
return viewpoint.ViewLevel;
|
||||
|
|
Loading…
Reference in a new issue