@quake2ts/engine 0.0.849 → 0.0.850

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ServerCommand, SURF_NONE, CvarFlags, ConfigStringIndex, MAX_CONFIGSTRINGS, MAX_MODELS, MAX_SOUNDS, MAX_IMAGES, MAX_LIGHTSTYLES, MAX_SHADOW_LIGHTS, MAX_ITEMS, MAX_CLIENTS, MAX_GENERAL, MAX_SOUND_CHANNELS, SoundChannel, ZERO_VEC3, ATTN_NONE, attenuationToDistanceMultiplier, SOUND_FULLVOLUME, calculateMaxAudibleDistance, lengthVec3, subtractVec3, RAD2DEG, DEG2RAD, normalizeVec3 as normalizeVec3$1, mat4FromBasis, RandomGenerator, BinaryStream, ANORMS, TempEntity, U_REMOVE, BinaryWriter, U_MOREBITS1, U_MOREBITS2, U_MOREBITS3, U_MOREBITS4, U_MODEL, U_MODEL2, U_MODEL3, U_MODEL4, U_FRAME8, U_FRAME16, U_SKIN8, U_SKIN16, U_EFFECTS8, U_EFFECTS16, U_RENDERFX8, U_RENDERFX16, U_ORIGIN1, U_ORIGIN2, U_ORIGIN3, U_ANGLE1, U_ANGLE2, U_ANGLE3, U_SOUND, U_EVENT, U_SOLID, U_ALPHA, U_SCALE, U_INSTANCE_BITS, U_LOOP_VOLUME, U_LOOP_ATTENUATION_HIGH, U_OWNER_HIGH, U_OLD_FRAME_HIGH, U_OLDORIGIN, NetChan, crc8, CMD_BACKUP, ClientCommand, writeUserCommand, NetworkMessageBuilder, multiplyMat4, SURF_FLOWING, SURF_WARP, SURF_SKY, SURF_TRANS33, SURF_TRANS66, configStringSize, CS_MAX_STRING_LENGTH, transformPointMat4, U_NUMBER16 } from '@quake2ts/shared';
2
2
  export { ATTN_IDLE, ATTN_LOOP_NONE, ATTN_NONE, ATTN_NORM, ATTN_STATIC, MAX_SOUND_CHANNELS, SOUND_FULLVOLUME, SOUND_LOOP_ATTENUATE, SoundChannel, U_ALPHA, U_ANGLE1, U_ANGLE2, U_ANGLE3, U_EFFECTS16, U_EFFECTS8, U_EVENT, U_FRAME16, U_FRAME8, U_INSTANCE_BITS, U_LOOP_ATTENUATION_HIGH, U_LOOP_VOLUME, U_MODEL, U_MODEL2, U_MODEL3, U_MODEL4, U_OLDORIGIN, U_OLD_FRAME_HIGH, U_ORIGIN1, U_ORIGIN2, U_ORIGIN3, U_OWNER_HIGH, U_REMOVE, U_RENDERFX16, U_RENDERFX8, U_SCALE, U_SKIN16, U_SKIN8, U_SOLID, U_SOUND, attenuationToDistanceMultiplier, calculateMaxAudibleDistance } from '@quake2ts/shared';
3
3
  import { OggVorbisDecoder } from '@wasm-audio-decoders/ogg-vorbis';
4
- import { vec3, mat4, quat, vec4 } from 'gl-matrix';
4
+ import { vec3, mat4, quat, vec4, mat3 } from 'gl-matrix';
5
5
 
6
6
  // src/loop.ts
7
7
  var DEFAULT_FIXED_DELTA_MS = 25;
@@ -10736,7 +10736,7 @@ var SpriteRenderer2 = class {
10736
10736
  };
10737
10737
 
10738
10738
  // raw-loader:/home/runner/work/quake2/quake2/quake2ts/packages/engine/src/render/webgpu/shaders/skybox.wgsl
10739
- var skybox_default = "struct Uniforms {\n viewProjection: mat4x4<f32>,\n scroll: vec2<f32>,\n}\n\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\n@group(0) @binding(1) var t_skybox: texture_cube<f32>;\n@group(0) @binding(2) var s_skybox: sampler;\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) direction: vec3<f32>,\n}\n\n@vertex\nfn vertexMain(@location(0) position: vec3<f32>) -> VertexOutput {\n var output: VertexOutput;\n\n // Pass the RAW position (not normalized) as direction\n // This preserves the face-relative direction and avoids corner tie issues\n // The cubemap sampler handles normalization internally\n var dir = position;\n\n // Apply scrolling in Quake horizontal plane (X/Y)\n // Small scrolling offset that doesn't break dominant component detection\n dir.x += uniforms.scroll.x * 0.01;\n dir.y += uniforms.scroll.y * 0.01;\n\n output.direction = dir;\n output.position = uniforms.viewProjection * vec4<f32>(position, 1.0);\n return output;\n}\n\n@fragment\nfn fragmentMain(@location(0) direction: vec3<f32>) -> @location(0) vec4<f32> {\n // Transform from Quake coordinates to GL/WebGPU cubemap coordinates\n // Quake: +X forward, +Y left, +Z up\n // GL cubemap: +X right, +Y up, -Z forward\n var cubemapDir: vec3<f32>;\n cubemapDir.x = -direction.y; // Quake +Y (left) \u2192 GL -X (left)\n cubemapDir.y = direction.z; // Quake +Z (up) \u2192 GL +Y (up)\n cubemapDir.z = -direction.x; // Quake +X (forward) \u2192 GL -Z (forward)\n\n return textureSample(t_skybox, s_skybox, cubemapDir);\n}\n";
10739
+ var skybox_default = "// Skybox shader using full-screen triangle approach\n// This avoids the w\u22480 issue with cube geometry at diagonal view angles\n// by computing the world-space direction analytically per-pixel\n\nstruct Uniforms {\n // Inverse view rotation matrix (view\u2192world transform for directions)\n // Stored as 3 vec4s due to std140 padding\n inverseViewRotation_col0: vec4<f32>,\n inverseViewRotation_col1: vec4<f32>,\n inverseViewRotation_col2: vec4<f32>,\n tanHalfFov: f32,\n aspect: f32,\n scroll: vec2<f32>,\n}\n\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\n@group(0) @binding(1) var t_skybox: texture_cube<f32>;\n@group(0) @binding(2) var s_skybox: sampler;\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n}\n\n@vertex\nfn vertexMain(@location(0) position: vec2<f32>) -> VertexOutput {\n var output: VertexOutput;\n\n // Position is already in NDC space (-1 to 1)\n output.position = vec4<f32>(position, 0.999, 1.0); // z near 1.0 for far plane\n\n return output;\n}\n\n// Hard-coded screen size for now (should be passed as uniform)\nconst SCREEN_SIZE: vec2<f32> = vec2<f32>(256.0, 256.0);\n\n@fragment\nfn fragmentMain(@builtin(position) fragCoord: vec4<f32>) -> @location(0) vec4<f32> {\n // Compute NDC from fragment coordinates\n // fragCoord.xy is in framebuffer coordinates (0 to width, 0 to height)\n // NDC.x: 0 -> -1, width -> +1\n // NDC.y: 0 -> +1, height -> -1 (Y is flipped in WebGPU framebuffer)\n let ndc = vec2<f32>(\n (fragCoord.x / SCREEN_SIZE.x) * 2.0 - 1.0,\n 1.0 - (fragCoord.y / SCREEN_SIZE.y) * 2.0\n );\n // Get columns directly from uniforms\n let col0 = uniforms.inverseViewRotation_col0.xyz;\n let col1 = uniforms.inverseViewRotation_col1.xyz;\n let col2 = uniforms.inverseViewRotation_col2.xyz;\n\n // Compute view-space direction from NDC\n // The view-space ray direction for a pixel at NDC (x, y) with perspective projection:\n // viewDir = normalize(vec3(x * aspect * tanHalfFov, y * tanHalfFov, -1.0))\n // Note: -1.0 for Z because we look down -Z in view space\n let viewDir = normalize(vec3<f32>(\n ndc.x * uniforms.aspect * uniforms.tanHalfFov,\n ndc.y * uniforms.tanHalfFov,\n -1.0\n ));\n\n // Transform view-space direction to world-space (Quake coordinates)\n // Manually unroll: worldDir = col0 * viewDir.x + col1 * viewDir.y + col2 * viewDir.z\n var worldDir = col0 * viewDir.x + col1 * viewDir.y + col2 * viewDir.z;\n\n // Apply small scroll offset in Quake horizontal plane\n worldDir.x += uniforms.scroll.x * 0.01;\n worldDir.y += uniforms.scroll.y * 0.01;\n\n // Transform from Quake coordinates to GL/WebGPU cubemap coordinates\n // Quake: +X forward, +Y left, +Z up\n // GL cubemap: +X right, +Y up, -Z forward\n var cubemapDir: vec3<f32>;\n cubemapDir.x = -worldDir.y; // Quake +Y (left) \u2192 GL -X (left)\n cubemapDir.y = worldDir.z; // Quake +Z (up) \u2192 GL +Y (up)\n cubemapDir.z = -worldDir.x; // Quake +X (forward) \u2192 GL -Z (forward)\n\n return textureSample(t_skybox, s_skybox, cubemapDir);\n}\n";
10740
10740
 
10741
10741
  // src/render/types/coordinates.ts
10742
10742
  var CoordinateSystem = /* @__PURE__ */ ((CoordinateSystem2) => {
@@ -10831,121 +10831,27 @@ var WebGPUMatrixBuilder = class {
10831
10831
  return view;
10832
10832
  }
10833
10833
  };
10834
- var SKYBOX_POSITIONS2 = new Float32Array([
10835
- // Front face (+X) - Quake forward direction
10836
- 1,
10837
- -1,
10838
- -1,
10839
- 1,
10840
- 1,
10841
- -1,
10842
- 1,
10843
- 1,
10844
- 1,
10845
- 1,
10846
- -1,
10847
- -1,
10848
- 1,
10849
- 1,
10850
- 1,
10851
- 1,
10852
- -1,
10853
- 1,
10854
- // Back face (-X) - Quake backward direction
10855
- -1,
10856
- 1,
10857
- -1,
10858
- -1,
10859
- -1,
10860
- -1,
10861
- -1,
10862
- -1,
10863
- 1,
10864
- -1,
10865
- 1,
10866
- -1,
10867
- -1,
10868
- -1,
10869
- 1,
10870
- -1,
10871
- 1,
10872
- 1,
10873
- // Left face (+Y) - Quake left direction
10874
- -1,
10875
- 1,
10876
- -1,
10877
- -1,
10878
- 1,
10879
- 1,
10880
- 1,
10881
- 1,
10882
- 1,
10883
- -1,
10884
- 1,
10885
- -1,
10886
- 1,
10887
- 1,
10888
- 1,
10889
- 1,
10890
- 1,
10891
- -1,
10892
- // Right face (-Y) - Quake right direction
10893
- 1,
10894
- -1,
10895
- -1,
10896
- 1,
10897
- -1,
10898
- 1,
10899
- -1,
10900
- -1,
10901
- 1,
10902
- 1,
10903
- -1,
10904
- -1,
10834
+ var FULLSCREEN_QUAD = new Float32Array([
10835
+ // Triangle 1: bottom-left, bottom-right, top-right
10905
10836
  -1,
10906
10837
  -1,
10838
+ // vertex 0: bottom-left
10907
10839
  1,
10908
10840
  -1,
10909
- -1,
10910
- -1,
10911
- // Top face (+Z) - Quake up direction
10912
- -1,
10913
- -1,
10841
+ // vertex 1: bottom-right
10914
10842
  1,
10915
10843
  1,
10844
+ // vertex 2: top-right
10845
+ // Triangle 2: bottom-left, top-right, top-left
10916
10846
  -1,
10917
- 1,
10918
- 1,
10919
- 1,
10920
- 1,
10921
10847
  -1,
10922
- -1,
10923
- 1,
10924
- 1,
10848
+ // vertex 3: bottom-left
10925
10849
  1,
10926
10850
  1,
10851
+ // vertex 4: top-right
10927
10852
  -1,
10928
- 1,
10929
- 1,
10930
- // Bottom face (-Z) - Quake down direction
10931
- -1,
10932
- 1,
10933
- -1,
10934
- 1,
10935
- 1,
10936
- -1,
10937
- 1,
10938
- -1,
10939
- -1,
10940
- -1,
10941
- 1,
10942
- -1,
10943
- 1,
10944
- -1,
10945
- -1,
10946
- -1,
10947
- -1,
10948
- -1
10853
+ 1
10854
+ // vertex 5: top-left
10949
10855
  ]);
10950
10856
  var SkyboxPipeline3 = class {
10951
10857
  constructor(device, format) {
@@ -10958,15 +10864,15 @@ var SkyboxPipeline3 = class {
10958
10864
  });
10959
10865
  this.vertexBuffer = device.createBuffer({
10960
10866
  label: "skybox-vertex-buffer",
10961
- size: SKYBOX_POSITIONS2.byteLength,
10867
+ size: FULLSCREEN_QUAD.byteLength,
10962
10868
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
10963
10869
  mappedAtCreation: true
10964
10870
  });
10965
- new Float32Array(this.vertexBuffer.getMappedRange()).set(SKYBOX_POSITIONS2);
10871
+ new Float32Array(this.vertexBuffer.getMappedRange()).set(FULLSCREEN_QUAD);
10966
10872
  this.vertexBuffer.unmap();
10967
10873
  this.uniformBuffer = device.createBuffer({
10968
10874
  label: "skybox-uniform-buffer",
10969
- size: 80,
10875
+ size: 64,
10970
10876
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
10971
10877
  });
10972
10878
  this.sampler = device.createSampler({
@@ -10982,7 +10888,7 @@ var SkyboxPipeline3 = class {
10982
10888
  entries: [
10983
10889
  {
10984
10890
  binding: 0,
10985
- visibility: GPUShaderStage.VERTEX,
10891
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
10986
10892
  buffer: { type: "uniform" }
10987
10893
  },
10988
10894
  {
@@ -11006,12 +10912,12 @@ var SkyboxPipeline3 = class {
11006
10912
  module,
11007
10913
  entryPoint: "vertexMain",
11008
10914
  buffers: [{
11009
- arrayStride: 12,
11010
- // vec3<f32>
10915
+ arrayStride: 8,
10916
+ // vec2<f32> for full-screen triangle
11011
10917
  attributes: [{
11012
10918
  shaderLocation: 0,
11013
10919
  offset: 0,
11014
- format: "float32x3"
10920
+ format: "float32x2"
11015
10921
  }]
11016
10922
  }]
11017
10923
  },
@@ -11037,48 +10943,63 @@ var SkyboxPipeline3 = class {
11037
10943
  },
11038
10944
  depthStencil: {
11039
10945
  format: "depth24plus",
11040
- depthWriteEnabled: true,
11041
- depthCompare: "less-equal"
11042
- // Proper depth testing ensures front faces occlude back faces
10946
+ depthWriteEnabled: false,
10947
+ // Skybox at infinite distance, don't affect depth
10948
+ depthCompare: "always"
10949
+ // Always draw skybox (rendered first as background)
11043
10950
  },
11044
10951
  primitive: {
11045
10952
  topology: "triangle-list",
11046
10953
  cullMode: "none"
11047
- // Inside the box
11048
10954
  }
11049
10955
  });
11050
10956
  this.bindGroupHelper = new SkyboxBindGroupHelper(device, bindGroupLayout, this.uniformBuffer, this.sampler);
11051
10957
  }
11052
10958
  draw(passEncoder, options) {
11053
- let viewProjection;
11054
- let useNative = 0;
11055
- if (options.cameraState) {
11056
- const view = this.matrixBuilder.buildViewMatrix(options.cameraState);
11057
- const projection = this.matrixBuilder.buildProjectionMatrix(options.cameraState);
11058
- view[12] = 0;
11059
- view[13] = 0;
11060
- view[14] = 0;
11061
- const vp = mat4.create();
11062
- mat4.multiply(vp, projection, view);
11063
- viewProjection = vp;
11064
- useNative = 1;
11065
- } else if (options.viewProjection) {
11066
- viewProjection = options.viewProjection;
11067
- useNative = 0;
11068
- } else {
11069
- throw new Error("SkyboxPipeline: Either cameraState or viewProjection must be provided");
11070
- }
11071
- const uniformData = new Float32Array(20);
11072
- uniformData.set(viewProjection);
11073
- uniformData[16] = options.scroll[0];
11074
- uniformData[17] = options.scroll[1];
11075
- uniformData[18] = useNative;
10959
+ if (!options.cameraState) {
10960
+ throw new Error("SkyboxPipeline: cameraState is required for full-screen skybox rendering");
10961
+ }
10962
+ const camera = options.cameraState;
10963
+ const view = this.matrixBuilder.buildViewMatrix(camera);
10964
+ const inverseViewRotation = mat3.fromValues(
10965
+ view[0],
10966
+ view[4],
10967
+ view[8],
10968
+ // First column becomes first row
10969
+ view[1],
10970
+ view[5],
10971
+ view[9],
10972
+ // Second column becomes second row
10973
+ view[2],
10974
+ view[6],
10975
+ view[10]
10976
+ // Third column becomes third row
10977
+ );
10978
+ const tanHalfFov = Math.tan(camera.fov * DEG2RAD / 2);
10979
+ const aspect = camera.aspect;
10980
+ const uniformData = new Float32Array(16);
10981
+ uniformData[0] = inverseViewRotation[0];
10982
+ uniformData[1] = inverseViewRotation[1];
10983
+ uniformData[2] = inverseViewRotation[2];
10984
+ uniformData[3] = 0;
10985
+ uniformData[4] = inverseViewRotation[3];
10986
+ uniformData[5] = inverseViewRotation[4];
10987
+ uniformData[6] = inverseViewRotation[5];
10988
+ uniformData[7] = 0;
10989
+ uniformData[8] = inverseViewRotation[6];
10990
+ uniformData[9] = inverseViewRotation[7];
10991
+ uniformData[10] = inverseViewRotation[8];
10992
+ uniformData[11] = 0;
10993
+ uniformData[12] = tanHalfFov;
10994
+ uniformData[13] = aspect;
10995
+ uniformData[14] = options.scroll[0];
10996
+ uniformData[15] = options.scroll[1];
11076
10997
  this.device.queue.writeBuffer(this.uniformBuffer, 0, uniformData);
11077
10998
  const bindGroup = this.bindGroupHelper.getBindGroup(options.cubemap);
11078
10999
  passEncoder.setPipeline(this.pipeline);
11079
11000
  passEncoder.setBindGroup(0, bindGroup);
11080
11001
  passEncoder.setVertexBuffer(0, this.vertexBuffer);
11081
- passEncoder.draw(SKYBOX_POSITIONS2.length / 3);
11002
+ passEncoder.draw(6);
11082
11003
  }
11083
11004
  destroy() {
11084
11005
  this.vertexBuffer.destroy();