3
3
package bsptracer
4
4
5
5
import (
6
- "path/filepath"
7
-
8
6
"github.com/galaco/bsp"
9
7
"github.com/galaco/bsp/lumps"
10
8
"github.com/galaco/bsp/primitives/brush"
11
9
"github.com/galaco/bsp/primitives/brushside"
10
+ "github.com/galaco/bsp/primitives/dispinfo"
11
+ "github.com/galaco/bsp/primitives/disptris"
12
+ "github.com/galaco/bsp/primitives/dispvert"
12
13
"github.com/galaco/bsp/primitives/face"
13
14
"github.com/galaco/bsp/primitives/leaf"
14
15
"github.com/galaco/bsp/primitives/node"
15
16
"github.com/galaco/bsp/primitives/plane"
17
+ "github.com/galaco/studiomodel"
18
+ "github.com/galaco/vpk2"
16
19
"github.com/go-gl/mathgl/mgl32"
20
+ "github.com/pkg/errors"
17
21
)
18
22
19
23
const (
@@ -35,19 +39,28 @@ type Map struct {
35
39
surfaces []face.Face
36
40
surfEdges []int32
37
41
vertices []mgl32.Vec3
42
+ game * lumps.Game // TODO: may be needed for props + leaves? or maybe not ...
43
+ dispInfo []dispinfo.DispInfo // TODO: trace against displacements
44
+ dispVerts []dispvert.DispVert
45
+ dispTris []disptris.DispTri
38
46
39
47
// constructed by this package
48
+ entities []map [string ]string // TODO: not yet sure if we'll need this
40
49
polygons []polygon
50
+ props []* studiomodel.StudioModel // TODO: place props in the world and trace against them
41
51
}
42
52
43
- // LoadMap loads a BSP map from a file.
44
- func LoadMap (directory , mapName string ) (* Map , error ) {
45
- bspfile , err := bsp .ReadFromFile (filepath .Join (directory , mapName ))
46
- if err != nil {
47
- return nil , err
48
- }
53
+ // LoadMap loads a map from a BSP file and VPKs.
54
+ // May return MissingModelsError if models can't be found - this is not fatal and the map can still be used.
55
+ func LoadMap (bspfile * bsp.Bsp , vpks ... * vpk.VPK ) (Map , error ) {
56
+ entitiesStr := bspfile .Lump (bsp .LumpEntities ).(* lumps.EntData ).GetData ()
57
+ entities := parseEntities (entitiesStr )
49
58
50
- m := & Map {
59
+ polygons := parsePolygons (bspfile )
60
+
61
+ props , missingModelsErr := loadProps (bspfile , vpks )
62
+
63
+ m := Map {
51
64
brushes : bspfile .Lump (bsp .LumpBrushes ).(* lumps.Brush ).GetData (),
52
65
brushSides : bspfile .Lump (bsp .LumpBrushSides ).(* lumps.BrushSide ).GetData (),
53
66
edges : bspfile .Lump (bsp .LumpEdges ).(* lumps.Edge ).GetData (),
@@ -59,55 +72,69 @@ func LoadMap(directory, mapName string) (*Map, error) {
59
72
surfaces : bspfile .Lump (bsp .LumpFaces ).(* lumps.Face ).GetData (),
60
73
surfEdges : bspfile .Lump (bsp .LumpSurfEdges ).(* lumps.Surfedge ).GetData (),
61
74
vertices : bspfile .Lump (bsp .LumpVertexes ).(* lumps.Vertex ).GetData (),
75
+ game : bspfile .Lump (bsp .LumpGame ).(* lumps.Game ).GetData (),
76
+ dispInfo : bspfile .Lump (bsp .LumpDispInfo ).(* lumps.DispInfo ).GetData (),
77
+ dispVerts : bspfile .Lump (bsp .LumpDispVerts ).(* lumps.DispVert ).GetData (),
78
+ dispTris : bspfile .Lump (bsp .LumpDispTris ).(* lumps.DispTris ).GetData (),
79
+ entities : entities ,
80
+ polygons : polygons ,
81
+ props : props ,
62
82
}
63
83
64
- m .parsePolygons ()
84
+ if missingModelsErr != nil {
85
+ return m , missingModelsErr
86
+ }
65
87
66
88
return m , nil
67
89
}
68
90
69
- func (m * Map ) parsePolygons () {
70
- m .polygons = make ([]polygon , len (m .surfaces ), 2 * len (m .surfaces ))
71
-
72
- for _ , surface := range m .surfaces {
73
- firstEdge := int (surface .FirstEdge )
74
- numEdges := int (surface .NumEdges )
91
+ // LoadMapFromFileSystem loads a BSP map from the file system.
92
+ // vpkPaths is a list of paths to either single or multi VPKs to load models, in order of priority.
93
+ // for CS:GO, vpkPaths should be paths to ("SteamLibrary/steamapps/common/Counter-Strike Global Offensive/csgo/pak01", "SteamLibrary/steamapps/common/Counter-Strike Global Offensive/platform/platform_pak01")
94
+ // See also LoadMap()
95
+ func LoadMapFromFileSystem (mapPath string , vpkPaths ... string ) (Map , error ) {
96
+ bspfile , err := bsp .ReadFromFile (mapPath )
97
+ if err != nil {
98
+ return Map {}, err
99
+ }
75
100
76
- if numEdges < 3 || numEdges > maxSurfinfoVerts || surface .TexInfo <= 0 {
77
- continue
78
- }
101
+ vpks := make ([]* vpk.VPK , len (vpkPaths ))
79
102
80
- var (
81
- polygon polygon
82
- edge mgl32.Vec3
83
- )
103
+ for i , path := range vpkPaths {
104
+ var err error
84
105
85
- for i := 0 ; i < numEdges ; i ++ {
86
- edgeIndex := m .surfEdges [firstEdge + i ]
87
- if edgeIndex >= 0 {
88
- edge = m .vertices [m .edges [edgeIndex ][0 ]]
89
- } else {
90
- edge = m .vertices [m .edges [- edgeIndex ][1 ]]
106
+ vpks [i ], err = vpk .Open (vpk .MultiVPK (path ))
107
+ if err != nil {
108
+ vpks [i ], err = vpk .Open (vpk .SingleVPK (path ))
109
+ if err != nil {
110
+ return Map {}, errors .Wrapf (err , "failed to open vpk %q" , path )
91
111
}
92
-
93
- polygon .verts [i ] = edge
94
112
}
95
-
96
- polygon .numVerts = numEdges
97
- polygon .plane .origin = m .planes [surface .Planenum ].Normal
98
- polygon .plane .distance = m .planes [surface .Planenum ].Distance
99
- m .polygons = append (m .polygons , polygon )
100
113
}
114
+
115
+ return LoadMap (bspfile , vpks ... )
101
116
}
102
117
103
118
// IsVisible returns true if destination is visible from origin, as computed by
104
119
// a ray trace.
105
- func (m * Map ) IsVisible (origin , destination mgl32.Vec3 ) bool {
120
+ func (m Map ) IsVisible (origin , destination mgl32.Vec3 ) bool {
106
121
return m .TraceRay (origin , destination ).Fraction >= 1
107
122
}
108
123
124
+ // Trace captures the result of a ray trace.
125
+ type Trace struct {
126
+ AllSolid bool
127
+ StartSolid bool
128
+ Fraction float32
129
+ FractionLeftSolid float32
130
+ EndPos mgl32.Vec3
131
+ Contents int32
132
+ Brush * brush.Brush
133
+ NumBrushSides int32
134
+ }
135
+
109
136
// TraceRay traces a ray from origin to destination and returns the result.
110
- func (m * Map ) TraceRay (origin , destination mgl32.Vec3 ) * Trace {
137
+ func (m Map ) TraceRay (origin , destination mgl32.Vec3 ) * Trace {
111
138
out := & Trace {
112
139
AllSolid : true ,
113
140
StartSolid : true ,
@@ -127,7 +154,7 @@ func (m *Map) TraceRay(origin, destination mgl32.Vec3) *Trace {
127
154
return out
128
155
}
129
156
130
- func (m * Map ) rayCastNode (nodeIndex int32 , startFraction , endFraction float32 ,
157
+ func (m Map ) rayCastNode (nodeIndex int32 , startFraction , endFraction float32 ,
131
158
origin , destination mgl32.Vec3 , out * Trace ,
132
159
) {
133
160
if out .Fraction <= startFraction {
@@ -237,7 +264,7 @@ func (m *Map) rayCastNode(nodeIndex int32, startFraction, endFraction float32,
237
264
}
238
265
}
239
266
240
- func (m * Map ) rayCastBrush (brush * brush.Brush , origin , destination mgl32.Vec3 , out * Trace ) {
267
+ func (m Map ) rayCastBrush (brush * brush.Brush , origin , destination mgl32.Vec3 , out * Trace ) {
241
268
if brush .NumSides != 0 {
242
269
fractionToEnter := float32 (- 99 )
243
270
fractionToLeave := float32 (1 )
@@ -324,7 +351,7 @@ func (m *Map) rayCastBrush(brush *brush.Brush, origin, destination mgl32.Vec3, o
324
351
}
325
352
}
326
353
327
- func (m * Map ) rayCastSurface (index int , origin , destination mgl32.Vec3 , out * Trace ) {
354
+ func (m Map ) rayCastSurface (index int , origin , destination mgl32.Vec3 , out * Trace ) {
328
355
if index >= len (m .polygons ) {
329
356
return
330
357
}
@@ -367,33 +394,3 @@ func (m *Map) rayCastSurface(index int, origin, destination mgl32.Vec3, out *Tra
367
394
}
368
395
}
369
396
}
370
-
371
- type polygon struct {
372
- verts [maxSurfinfoVerts ]mgl32.Vec3
373
- numVerts int
374
- plane vplane
375
- edgePlanes []vplane
376
- vec2d [maxSurfinfoVerts ]mgl32.Vec3
377
- skip int
378
- }
379
-
380
- type vplane struct {
381
- origin mgl32.Vec3
382
- distance float32
383
- }
384
-
385
- func (v * vplane ) dist (destination mgl32.Vec3 ) float32 {
386
- return v .origin .Dot (destination ) - v .distance
387
- }
388
-
389
- // Trace captures the result of a ray trace.
390
- type Trace struct {
391
- AllSolid bool
392
- StartSolid bool
393
- Fraction float32
394
- FractionLeftSolid float32
395
- EndPos mgl32.Vec3
396
- Contents int32
397
- Brush * brush.Brush
398
- NumBrushSides int32
399
- }
0 commit comments