void BuildPalmap( void ){ #ifdef TABLECOLORS int r, g, b; int bestcolor; if ( palmap_built ) { return; } palmap_built = qtrue; for ( r = 4 ; r < 256 ; r += 8 ) { for ( g = 4 ; g < 256 ; g += 8 ) { for ( b = 4 ; b < 256 ; b += 8 ) { bestcolor = BestColor( r, g, b, 1, 254 ); palmap[r >> 3][g >> 3][b >> 3] = bestcolor; } } } #endif if ( !colormap_issued ) { Error( "You must issue a $colormap command first" ); } }
BYTE FColorMatcher::Pick (int r, int g, int b) { if (Pal == NULL) return 1; return (BYTE)BestColor ((uint32 *)Pal, r, g, b); }
/* ============= FindColor ============= */ int FindColor( int r, int g, int b ){ int bestcolor; if ( r > 255 ) { r = 255; } if ( r < 0 ) { r = 0; } if ( g > 255 ) { g = 255; } if ( g < 0 ) { g = 0; } if ( b > 255 ) { b = 255; } if ( b < 0 ) { b = 0; } #ifndef TABLECOLORS bestcolor = BestColor( r, g, b, 0, 254 ); #else bestcolor = palmap[r >> 3][g >> 3][b >> 3]; #endif return bestcolor; }
// Draw a list of player colors on a team. Lines up with player names. void EATeamPlayerColors(int x, int y, const unsigned short w, const unsigned short h, const float scale, const x_align_t x_align, const y_align_t y_align, const x_align_t x_origin, const y_align_t y_origin, const short padding, const short limit, const byte team) { byte drawn = 0; for (size_t i = 0;i < sortedPlayers().size();i++) { // Make sure we're not overrunning our limit. if (limit != 0 && drawn >= limit) { break; } player_t* player = sortedPlayers()[i]; if (inTeamPlayer(player, team)) { int playercolor = CL_GetPlayerColor(player); int color = BestColor(GetDefaultPalette()->basecolors, RPART(playercolor), GPART(playercolor), BPART(playercolor), GetDefaultPalette()->numcolors); hud::Clear(x, y, w, h, scale, x_align, y_align, x_origin, y_origin, color); y += h + padding; drawn += 1; } } }
void RenderPortal::RenderLinePortalHighlight(PortalDrawseg* pds) { // [ZZ] NO OVERFLOW CHECKS HERE // I believe it won't break. if it does, blame me. :( auto viewport = Thread->Viewport.get(); if (viewport->RenderTarget->IsBgra()) // Assuming this is just a debug function return; uint8_t color = (uint8_t)BestColor((uint32_t *)GPalette.BaseColors, 255, 0, 0, 0, 255); uint8_t* pixels = viewport->RenderTarget->GetBuffer(); // top edge for (int x = pds->x1; x < pds->x2; x++) { if (x < 0 || x >= viewport->RenderTarget->GetWidth()) continue; int p = x - pds->x1; int Ytop = pds->ceilingclip[p]; int Ybottom = pds->floorclip[p]; if (x == pds->x1 || x == pds->x2 - 1) { viewport->RenderTarget->DrawLine(x, Ytop, x, Ybottom + 1, color, 0); continue; } int YtopPrev = pds->ceilingclip[p - 1]; int YbottomPrev = pds->floorclip[p - 1]; if (abs(Ytop - YtopPrev) > 1) viewport->RenderTarget->DrawLine(x, YtopPrev, x, Ytop, color, 0); else *(pixels + Ytop * viewport->RenderTarget->GetPitch() + x) = color; if (abs(Ybottom - YbottomPrev) > 1) viewport->RenderTarget->DrawLine(x, YbottomPrev, x, Ybottom, color, 0); else *(pixels + Ybottom * viewport->RenderTarget->GetPitch() + x) = color; } }
byte FColorMatcher::Pick (int r, int g, int b) { if (Pal == NULL) return 0; #ifdef BEFAST byte bestcolor; int bestdist; byte color = FirstColor[(r+CLOSIZE/2)>>CLOBITS][(g+CLOSIZE/2)>>CLOBITS][(b+CLOSIZE/2)>>CLOBITS]; if (NextColor[color] == 0) return color; bestcolor = 0; bestdist = 257*257+257*257+257*257; do { int dist = (r-Pal[color].r)*(r-Pal[color].r)+ (g-Pal[color].g)*(g-Pal[color].g)+ (b-Pal[color].b)*(b-Pal[color].b); if (dist < bestdist) { if (dist == 0) return color; bestdist = dist; bestcolor = color; } color = NextColor[color]; } while (color != 0); return bestcolor; #else return BestColor ((DWORD *)Pal, r, g, b); #endif }
/* ============== Cmd_Colormap $colormap filename the brightes colormap is first in the table (FIXME: reverse this now?) 64 rows of 256 : lightmaps 256 rows of 256 : translucency table ============== */ void Cmd_Colormap( void ){ int levels, brights; int l, c; float frac, red, green, blue; float range; byte *cropped, *lump_p; char savename[1024]; char dest[1024]; colormap_issued = qtrue; if ( !g_release ) { memcpy( colormap_palette, lbmpalette, 768 ); } if ( !TokenAvailable() ) { // just setting colormap_issued return; } GetToken( qfalse ); sprintf( savename, "%spics/%s.pcx", writedir, token ); if ( g_release ) { sprintf( dest, "pics/%s.pcx", token ); ReleaseFile( dest ); return; } range = 2; levels = 64; brights = 1; // ignore 255 (transparent) cropped = malloc( ( levels + 256 ) * 256 ); lump_p = cropped; // shaded levels for ( l = 0; l < levels; l++ ) { frac = range - range * (float)l / ( levels - 1 ); for ( c = 0 ; c < 256 - brights ; c++ ) { red = lbmpalette[c * 3]; green = lbmpalette[c * 3 + 1]; blue = lbmpalette[c * 3 + 2]; red = (int)( red * frac + 0.5 ); green = (int)( green * frac + 0.5 ); blue = (int)( blue * frac + 0.5 ); // // note: 254 instead of 255 because 255 is the transparent color, and we // don't want anything remapping to that // don't use color 0, because NT can't remap that (or 255) // *lump_p++ = BestColor( red,green,blue, 1, 254 ); } // fullbrights allways stay the same for ( ; c < 256 ; c++ ) *lump_p++ = c; } // 66% transparancy table for ( l = 0; l < 255; l++ ) { for ( c = 0 ; c < 255 ; c++ ) { red = lbmpalette[c * 3] * 0.33 + lbmpalette[l * 3] * 0.66; green = lbmpalette[c * 3 + 1] * 0.33 + lbmpalette[l * 3 + 1] * 0.66; blue = lbmpalette[c * 3 + 2] * 0.33 + lbmpalette[l * 3 + 2] * 0.66; *lump_p++ = BestColor( red,green,blue, 1, 254 ); } *lump_p++ = 255; } for ( c = 0 ; c < 256 ; c++ ) *lump_p++ = 255; // save off the new image printf( "saving %s\n", savename ); CreatePath( savename ); WritePCXfile( savename, cropped, 256, levels + 256, lbmpalette ); free( cropped ); }
void RenderPortal::RenderLinePortal(PortalDrawseg* pds, int depth) { auto viewport = Thread->Viewport.get(); auto &viewpoint = viewport->viewpoint; // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. if (depth >= r_portal_recursions) { uint8_t color = (uint8_t)BestColor((uint32_t *)GPalette.BaseColors, 0, 0, 0, 0, 255); int spacing = viewport->RenderTarget->GetPitch(); for (int x = pds->x1; x < pds->x2; x++) { if (x < 0 || x >= viewport->RenderTarget->GetWidth()) continue; int Ytop = pds->ceilingclip[x - pds->x1]; int Ybottom = pds->floorclip[x - pds->x1]; if (viewport->RenderTarget->IsBgra()) { uint32_t *dest = (uint32_t*)viewport->RenderTarget->GetBuffer() + x + Ytop * spacing; uint32_t c = GPalette.BaseColors[color].d; for (int y = Ytop; y <= Ybottom; y++) { *dest = c; dest += spacing; } } else { uint8_t *dest = viewport->RenderTarget->GetBuffer() + x + Ytop * spacing; for (int y = Ytop; y <= Ybottom; y++) { *dest = color; dest += spacing; } } } if (r_highlight_portals) RenderLinePortalHighlight(pds); return; } DAngle startang = viewpoint.Angles.Yaw; DVector3 startpos = viewpoint.Pos; DVector3 savedpath[2] = { viewpoint.Path[0], viewpoint.Path[1] }; ActorRenderFlags savedvisibility = viewpoint.camera ? viewpoint.camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0); viewpoint.camera->renderflags &= ~RF_INVISIBLE; CurrentPortalUniq++; unsigned int portalsAtStart = WallPortals.Size(); if (pds->mirror) { //vertex_t *v1 = ds->curline->v1; vertex_t *v1 = pds->src->v1; // Reflect the current view behind the mirror. if (pds->src->Delta().X == 0) { // vertical mirror viewpoint.Pos.X = v1->fX() - startpos.X + v1->fX(); } else if (pds->src->Delta().Y == 0) { // horizontal mirror viewpoint.Pos.Y = v1->fY() - startpos.Y + v1->fY(); } else { // any mirror vertex_t *v2 = pds->src->v2; double dx = v2->fX() - v1->fX(); double dy = v2->fY() - v1->fY(); double x1 = v1->fX(); double y1 = v1->fY(); double x = startpos.X; double y = startpos.Y; // the above two cases catch len == 0 double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy); viewpoint.Pos.X = (x1 + r * dx) * 2 - x; viewpoint.Pos.Y = (y1 + r * dy) * 2 - y; } viewpoint.Angles.Yaw = pds->src->Delta().Angle() * 2 - startang; } else { P_TranslatePortalXY(pds->src, viewpoint.Pos.X, viewpoint.Pos.Y); P_TranslatePortalZ(pds->src, viewpoint.Pos.Z); P_TranslatePortalAngle(pds->src, viewpoint.Angles.Yaw); P_TranslatePortalXY(pds->src, viewpoint.Path[0].X, viewpoint.Path[0].Y); P_TranslatePortalXY(pds->src, viewpoint.Path[1].X, viewpoint.Path[1].Y); if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], pds->dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], pds->dst)) { double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length(); if (distp > EQUAL_EPSILON) { double dist1 = (viewpoint.Pos - viewpoint.Path[0]).Length(); double dist2 = (viewpoint.Pos - viewpoint.Path[1]).Length(); if (dist1 + dist2 < distp + 1) { viewpoint.camera->renderflags |= RF_INVISIBLE; } } } } viewpoint.Sin = viewpoint.Angles.Yaw.Sin(); viewpoint.Cos = viewpoint.Angles.Yaw.Cos(); viewpoint.TanSin = Thread->Viewport->viewwindow.FocalTangent * viewpoint.Sin; viewpoint.TanCos = Thread->Viewport->viewwindow.FocalTangent * viewpoint.Cos; CopyStackedViewParameters(); validcount++; PortalDrawseg* prevpds = CurrentPortal; CurrentPortal = pds; Thread->PlaneList->ClearKeepFakePlanes(); Thread->ClipSegments->Clear(pds->x1, pds->x2); WindowLeft = pds->x1; WindowRight = pds->x2; // RF_XFLIP should be removed before calling the root function int prevmf = MirrorFlags; if (pds->mirror) { if (MirrorFlags & RF_XFLIP) MirrorFlags &= ~RF_XFLIP; else MirrorFlags |= RF_XFLIP; } // some portals have height differences, account for this here Thread->Clip3D->EnterSkybox(); // push 3D floor height map CurrentPortalInSkybox = false; // first portal in a skybox should set this variable to false for proper clipping in skyboxes. // first pass, set clipping auto ceilingclip = Thread->OpaquePass->ceilingclip; auto floorclip = Thread->OpaquePass->floorclip; memcpy(ceilingclip + pds->x1, &pds->ceilingclip[0], pds->len * sizeof(*ceilingclip)); memcpy(floorclip + pds->x1, &pds->floorclip[0], pds->len * sizeof(*floorclip)); Thread->OpaquePass->RenderScene(); Thread->Clip3D->ResetClip(); // reset clips (floor/ceiling) if (!savedvisibility && viewpoint.camera) viewpoint.camera->renderflags &= ~RF_INVISIBLE; Thread->PlaneList->Render(); RenderPlanePortals(); double vzp = viewpoint.Pos.Z; int prevuniq = CurrentPortalUniq; // depth check is in another place right now unsigned int portalsAtEnd = WallPortals.Size(); for (; portalsAtStart < portalsAtEnd; portalsAtStart++) { RenderLinePortal(WallPortals[portalsAtStart], depth + 1); } int prevuniq2 = CurrentPortalUniq; CurrentPortalUniq = prevuniq; if (Thread->MainThread) NetUpdate(); Thread->TranslucentPass->Render(); // this is required since with portals there often will be cases when more than 80% of the view is inside a portal. if (Thread->MainThread) NetUpdate(); Thread->Clip3D->LeaveSkybox(); // pop 3D floor height map CurrentPortalUniq = prevuniq2; // draw a red line around a portal if it's being highlighted if (r_highlight_portals) RenderLinePortalHighlight(pds); CurrentPortal = prevpds; MirrorFlags = prevmf; viewpoint.Angles.Yaw = startang; viewpoint.Pos = startpos; viewpoint.Path[0] = savedpath[0]; viewpoint.Path[1] = savedpath[1]; }