-
-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathlight.go
130 lines (112 loc) · 3.58 KB
/
light.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright © 2014-2024 Galvanized Logic Inc.
package vu
// light.go holder for lighting related code.
// FUTURE: different types of lights and more lights.
import (
"log/slog"
"github.com/gazed/vu/render"
)
// Types of lights
const (
DirectionalLight = iota // no falloff ie: the sun
PointLight // falloff ie: light bulb
)
// AddLight adds a light to a scene.
// Lighting aware shaders combine the light with the models material
// values. Objects in the scene with lighting capable shaders will
// be influenced by the light.
//
// Each light is has a position and orientation in world space.
// The default position is 0,0,0 and the default direction is 0,0,-1.
// A lights default color is white 1,1,1.
//
// Depends on Eng.AddScene.
func (e *Entity) AddLight(lightType int) *Entity {
// lights must be set directly on scenes
if s := e.app.scenes.get(e.eid); s != nil {
me := e.AddPart() // add a transform node for the light.
if l := me.app.lights.create(me, e, lightType); l != nil {
return me
}
}
slog.Error("AddLight requires scene", "eid", e.eid)
return e
}
// SetLight assigns a color and intensity to the light. The lights color is combined
// with objects material color to produce a final color. The R,G,B light values
// are between 0 (no color), and 1 (full color).
//
// Depends on Entity.AddLight.
func (e *Entity) SetLight(r, g, b, intensity float32) *Entity {
if l := e.app.lights.get(e.eid); l != nil {
l.r, l.g, l.b = r, g, b
l.intensity = intensity
return e
}
slog.Error("SetLight needs AddLight", "eid", e.eid)
return e
}
// =============================================================================
// light data.
// light holds light color for now. Anticipate other future light parameters.
// The lights world position are scatch values updated each render loop.
type light struct {
kind int // light type
r, g, b float32 // Light color: values are 0 to 1.
intensity float32 //
}
// newLight creates a white light.
func newLight(lightType int) (l *light) {
return &light{
kind: lightType,
r: 1.0, // default white color.
g: 1.0, // ""
b: 1.0, // ""
intensity: 5.0, // default intensity.
}
}
// =============================================================================
// light component manager.
// lights manages all the active Light instances.
// There's not many lights so not much to optimize.
type lights struct {
data map[eID]*light // All light instance data.
}
// newLights creates a light component manager. Expected to be called
// once on startup.
func newLights() *lights {
return &lights{data: map[eID]*light{}}
}
// get the light associated with the given entity, returning nil
// if there is no such light.
func (ls *lights) get(id eID) *light {
if light, ok := ls.data[id]; ok {
return light
}
return nil
}
// create and associate a light with the given entity. If there
// already is a light for the entity, don't create one and return
// the existing one instead.
func (ls *lights) create(light, scene *Entity, lightType int) (l *light) {
l = newLight(lightType)
ls.data[light.eid] = l // All lights.
return l
}
// fillPass populates the render.Pass data with the light information
// at the given pov.
func (ls *lights) fillLight(light *render.Light, lid eID, pov *pov) {
l := ls.data[lid]
px, py, pz := pov.at()
light.X = float32(px)
light.Y = float32(py)
light.Z = float32(pz)
light.R = l.r
light.G = l.g
light.B = l.b
}
// dispose the light associated for the given entity. Do nothing
// if no such light exists.
func (ls *lights) dispose(id eID) {
delete(ls.data, id)
}