mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
fix(dashboard): white pines, see-through hills and fighting surfaces in the 3D views
- Shader 94 ("Basic") draws with vertex colors: its class's technique setup
names Technique_Basic_Lighting_VertColor, as 38 "Basic VC" does. The views
treated it as having none, so Nimbus Station's glom pines (tag S84) came
out as their grey texture, white. The other shader looks in use were
checked the same way (33, 35, 37, 70, 82, 84, 105 hold).
- Two layer shaders: NiTexturingProperty's dark texture and the UV set each
texture's flags name are read, and the views draw "Two Layers Blended" as
the dark texture under the base one by the vertex alpha (no longer as
opacity) and "Two Textures Added" as in TwoLayersAdded_PS. Avant Gardens'
snowy grass mounds were see-through hills. The client ships no technique
for the blended ones, so that blend follows the meshes' data.
- The near plane follows how far out the camera is (distance / 400, 0.5 to
20) instead of a fixed 0.5 over a far plane in the thousands, so ground
overlays, floor rings and road pieces stop fighting in far views.
- Conversion format 3 (new model data), so kept conversions are made again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -213,6 +213,56 @@ TEST(NifFileTests, PassesPropertiesDownTheTree) {
|
||||
EXPECT_TRUE(m.doubleSided);
|
||||
}
|
||||
|
||||
// Two layer shaders use NiTexturingProperty's dark texture too, each texture on the UV set its flags name
|
||||
TEST(NifFileTests, ReadsTheDarkTextureAndEachTexturesUvSet) {
|
||||
NifBuilder nif;
|
||||
const auto snow = nif.String("snow.dds"), rock = nif.String("rock.dds");
|
||||
const auto source = [&nif](int32_t name) {
|
||||
return nif.Add("NiSourceTexture", Net().Put<uint8_t>(1).Put(name).Put<int32_t>(-1).Floats({ 0, 0, 0 }).Put<uint8_t>(1).Put<uint8_t>(1).Put<uint8_t>(0));
|
||||
};
|
||||
const auto base = source(snow), dark = source(rock);
|
||||
// Base on UV set 1 with a texture transform (32 bytes to skip), dark on UV set 0
|
||||
auto texturing = Net().Put<uint16_t>(0).Put<uint32_t>(9).Put<uint8_t>(1).Put(base).Put<uint16_t>(0x3201).Put<uint8_t>(1);
|
||||
texturing.Raw(std::string(32, '\0'));
|
||||
texturing.Put<uint8_t>(1).Put(dark).Put<uint16_t>(0x3200).Put<uint8_t>(0);
|
||||
for (int slot = 2; slot < 9; slot++) texturing.Put<uint8_t>(0);
|
||||
texturing.Put<uint32_t>(0);
|
||||
const auto property = nif.Add("NiTexturingProperty", texturing);
|
||||
// A triangle with two UV sets: set 0 all (0.25, 0.75), set 1 all (0.5, 0.5)
|
||||
Bytes data;
|
||||
data.Put<int32_t>(0).Put<uint16_t>(3).Put<uint8_t>(0).Put<uint8_t>(0).Put<uint8_t>(1);
|
||||
for (int i = 0; i < 3; i++) data.Floats({ static_cast<float>(i == 1), static_cast<float>(i == 2), 0.0f });
|
||||
data.Put<uint16_t>(2).Put<uint8_t>(0).Floats({ 0, 0, 0, 1 }).Put<uint8_t>(0);
|
||||
for (int i = 0; i < 3; i++) data.Floats({ 0.25f, 0.75f });
|
||||
for (int i = 0; i < 3; i++) data.Floats({ 0.5f, 0.5f });
|
||||
data.Put<uint16_t>(0).Put<int32_t>(-1).Put<uint16_t>(1).Put<uint32_t>(3).Put<uint8_t>(1).Put<uint16_t>(0).Put<uint16_t>(1).Put<uint16_t>(2).Put<uint16_t>(0);
|
||||
const auto root = nif.Add("NiNode", {});
|
||||
const auto shape = nif.Add("NiTriShape", {});
|
||||
const auto shapeData = nif.Add("NiTriShapeData", data);
|
||||
nif.Set(root, Node(Av(0, { 0, 0, 0 }, IDENTITY, 1.0f, {}), { shape }));
|
||||
nif.Set(shape, Geometry(Av(0, { 0, 0, 0 }, IDENTITY, 1.0f, { property }), shapeData));
|
||||
std::string error;
|
||||
const auto model = NifFile::Parse(nif.Build({ root }), 0, error);
|
||||
ASSERT_TRUE(model) << error;
|
||||
ASSERT_EQ(model->meshes.size(), 1u);
|
||||
const auto& mesh = model->meshes[0];
|
||||
EXPECT_EQ(mesh.material.texture, "snow.dds");
|
||||
EXPECT_EQ(mesh.material.darkTexture, "rock.dds");
|
||||
ASSERT_EQ(mesh.uvs.size(), 6u);
|
||||
EXPECT_FLOAT_EQ(mesh.uvs[0], 0.5f); // the base texture's set 1
|
||||
ASSERT_EQ(mesh.uvs2.size(), 6u);
|
||||
EXPECT_FLOAT_EQ(mesh.uvs2[1], 0.75f); // the dark texture's set 0
|
||||
|
||||
// The browser gets the dark texture and its UVs
|
||||
const auto encoded = NifFile::Encode(*model, { "mesh/snow.dds" }, { "mesh/rock.dds" });
|
||||
uint32_t length{};
|
||||
std::memcpy(&length, encoded.data(), 4);
|
||||
const auto header = nlohmann::json::parse(encoded.substr(4, length));
|
||||
EXPECT_EQ(header["textures"], nlohmann::json::array({ "mesh/snow.dds", "mesh/rock.dds" }));
|
||||
EXPECT_EQ(header["meshes"][0]["darkTexture"], 1);
|
||||
EXPECT_EQ(header["meshes"][0]["uv2"], true);
|
||||
}
|
||||
|
||||
TEST(NifFileTests, TurnsStripsIntoTriangles) {
|
||||
NifBuilder nif;
|
||||
const auto root = nif.Add("NiNode", {});
|
||||
@@ -434,6 +484,8 @@ TEST(WorldSceneTests, LightsAZoneAsMostOfItsObjectsAre) {
|
||||
|
||||
TEST(NifFileTests, KnowsWhatEachShaderLeavesOut) {
|
||||
EXPECT_EQ(NifFile::ShaderLookFor(38), 0); // Basic VC: lit, textured, vertex colors
|
||||
EXPECT_EQ(NifFile::ShaderLookFor(94), 0); // "Basic" draws with vertex colors too (Nimbus Station's pines)
|
||||
EXPECT_EQ(NifFile::ShaderLookFor(84), NifFile::UNLIT); // Opaque NL VC NoFog
|
||||
EXPECT_EQ(NifFile::ShaderLookFor(NifFile::LEGO_SHADER), 0);
|
||||
EXPECT_EQ(NifFile::ShaderLookFor(-1), 0); // fixed function is lit by Gamebryo
|
||||
EXPECT_EQ(NifFile::ShaderLookFor(33), NifFile::UNLIT | NifFile::NO_TEXTURE); // Basic NL VC NT
|
||||
|
||||
@@ -33,13 +33,13 @@ same(S.textureAlphaMode(manifest, 1, { shaderTag: 1 }), 'decal', 'LEGO part text
|
||||
same(S.textureAlphaMode(manifest, 1, { shaderTag: 30 }), 'opacity', 'Basic VC part texture alpha');
|
||||
|
||||
// Lit, textured, vertex colors, no material colors: Basic VC
|
||||
same(S.gameLook(manifest, 1, { ...colored, shaderTag: 30 }), { lit: true, texture: true, vertexColors: true, material: false }, 'Basic VC');
|
||||
same(S.gameLook(manifest, 1, { ...colored, shaderTag: 30 }), { lit: true, texture: true, vertexColors: true, material: false, layers: null }, 'Basic VC');
|
||||
// Vertex colors are read even when NiVertexColorProperty ignores them, but only if the mesh has some
|
||||
same(S.gameLook(manifest, 0, { ...colored, vertexColors: 0 }).vertexColors, true, 'shader reads vertex colors');
|
||||
same(S.gameLook(manifest, 0, {}).vertexColors, false, 'mesh without vertex colors');
|
||||
same(S.gameLook(manifest, 3, colored), { lit: false, texture: false, vertexColors: true, material: false }, 'Basic NL VC NT');
|
||||
same(S.gameLook(manifest, 3, colored), { lit: false, texture: false, vertexColors: true, material: false, layers: null }, 'Basic NL VC NT');
|
||||
// Fixed function: NiVertexColorProperty and the material decide
|
||||
same(S.gameLook(manifest, 2, { ...colored, vertexColors: 0 }), { lit: true, texture: true, vertexColors: false, material: true }, 'fixed function');
|
||||
same(S.gameLook(manifest, 2, { ...colored, vertexColors: 0 }), { lit: true, texture: true, vertexColors: false, material: true, layers: null }, 'fixed function');
|
||||
// Without the zone's lighting the viewer lights scenery itself
|
||||
same(S.gameLook({ ...manifest, lighting: null }, 0, colored), null, 'no lighting');
|
||||
|
||||
@@ -57,6 +57,15 @@ same([...S.loadedScenes(scenes, 0)], [0], 'loaded in the global scene');
|
||||
// A run longer than the map stops at its end
|
||||
same(S.decodeSceneMap({ chunks: [{ x: 0, z: 0, maxX: 1, maxZ: 1, size: 1, runs: runs([9, 4]) }] }).chunks[0].cells.length, 1, 'runs clipped');
|
||||
|
||||
// Two layer shaders
|
||||
const layered = { ...manifest, shaders: [106, 107], shaderLooks: { 106: S.SHADER_LOOK.TWO_LAYERS_BLENDED, 107: S.SHADER_LOOK.TWO_LAYERS_ADDED } };
|
||||
same(S.gameLook(layered, 0, colored).layers, 'blended', 'two layers blended');
|
||||
same(S.gameLook(layered, 1, colored).layers, 'added', 'two layers added');
|
||||
same(S.gameLook(manifest, 0, colored).layers, null, 'one layer');
|
||||
|
||||
// The near plane grows with the distance, within limits
|
||||
same([S.nearPlaneFor(10), S.nearPlaneFor(2000), S.nearPlaneFor(100000)], [0.5, 5, 20], 'near plane');
|
||||
|
||||
if (failures) {
|
||||
console.error(`${failures} failed`);
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user