OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
globaleffects.cpp
Go to the documentation of this file.
1#include "globaleffects.h"
2
3#include <Tempest/Log>
4#include <charconv>
5
7#include "world/world.h"
8#include "graphics/visualfx.h"
9
10using namespace Tempest;
11
13 }
14
15void GlobalEffects::tick(uint64_t dt) {
16 tick(dt,timeEff);
17 tick(dt,scrEff);
18 tick(dt,morphEff);
19 tick(dt,quakeEff);
20 }
21
22template<class T>
23void GlobalEffects::tick(uint64_t /*dt*/, std::vector<T>& eff) {
24 uint64_t time = owner.tickCount();
25 for(size_t i=0; i<eff.size(); ) {
26 if(eff[i]->timeUntil<time) {
27 eff.erase(eff.begin()+int(i));
28 } else {
29 ++i;
30 }
31 }
32 }
33
34void GlobalEffects::scaleTime(uint64_t& dt) {
35 for(auto& pi:timeEff) {
36 auto& i = *pi;
37 dt = dt*i.mul + timeWrldRem;
38 timeWrldRem = dt%i.div;
39 dt /=i.div;
40 }
41 }
42
43static float generator(uint64_t dt, uint64_t period) {
44 float a0 = float((dt+period/2)%period)/float(period); //[0..1]
45 a0 = a0*2.f-1.f;
46 return a0;
47 }
48
49void GlobalEffects::morph(Tempest::Matrix4x4& proj) {
50 for(auto& pi:morphEff) {
51 auto& i = *pi;
52 float x = i.amplitude*0.075f;
53 float y = i.amplitude*0.075f;
54
55 uint64_t time = owner.tickCount()-i.timeStart;
56 // a0 = std::sin(float(2*a0*M_PI));
57
58 float a0 = generator(time,5000);
59 float a1 = generator(time,9000);
60 a0 = std::sin(a0*float(M_PI));
61 a1 = std::sin(a1*float(M_PI));
62
63 proj.scale(1.f+a0*x,1.f-a0*y,1.f);
64 proj.scale(1.f+a1*x,1.f+a1*y,1.f);
65 }
66 }
67
68void GlobalEffects::scrBlend(Tempest::Painter& p, const Tempest::Rect& rect) {
69 for(auto& pi:scrEff) {
70 auto& i = *pi;
71 auto cl = i.cl;
72 if(i.inout>0) {
73 uint64_t now = owner.tickCount();
74 float a0 = std::min(1.f, (float(now-i.timeStart)/1000.f)/i.inout);
75 float a1 = std::min(1.f, (float(i.timeUntil-now)/1000.f)/i.inout);
76 float a = std::min(a0,a1);
77 cl.set(cl.r(),cl.g(),cl.b(),cl.a()*a);
78 }
79 if(i.frames.size()==0) {
80 p.setBrush(Tempest::Brush(cl,Tempest::Painter::Alpha));
81 } else {
82 uint64_t dt = owner.tickCount()-i.timeStart;
83 size_t frame = size_t(i.fps*dt)/1000;
84 if(i.fps>0)
85 frame%=i.fps;
86 p.setBrush(Tempest::Brush(*i.frames[frame],Tempest::Color(1,1,1,cl.a()),Tempest::Painter::Alpha));
87 }
88 p.drawRect(rect.x,rect.y,rect.w,rect.h,0,0,p.brush().w(),p.brush().h());
89 }
90 }
91
92GlobalFx GlobalEffects::startEffect(std::string_view what, uint64_t len, const std::string* argv, size_t argc) {
93 auto ret = create(what,argv,argc);
94 auto& eff = *ret.h;
95 if(len==0)
96 eff.timeUntil = uint64_t(-1); else
97 eff.timeUntil = owner.tickCount()+len;
98 eff.timeStart = owner.tickCount();
99 eff.timeLen = len==0 ? uint64_t(-1) : len;
100 return ret;
101 }
102
104 auto& what = vfx.visName_S;
105 if(what=="time.slw")
106 timeEff.clear();
107 if(what=="screenblend.scx")
108 scrEff.clear();
109 if(what=="morph.fov")
110 morphEff.clear();
111 if(what=="earthquake.eqk")
112 quakeEff.clear();
113 }
114
115GlobalFx GlobalEffects::create(std::string_view what, const std::string* argv, size_t argc) {
116 if(what=="time.slw")
117 return addSlowTime(argv,argc);
118 if(what=="screenblend.scx")
119 return addScreenBlend(argv,argc);
120 if(what=="morph.fov")
121 return addMorphFov(argv,argc);
122 if(what=="earthquake.eqk")
123 return addEarthQuake(argv,argc);
124 return GlobalFx();
125 }
126
127GlobalFx GlobalEffects::addSlowTime(const std::string* argv, size_t argc) {
128 double val[2] = {1,1};
129 for(size_t i=0; i<argc && i<2; ++i) {
130 try {
131 val[i] = std::stof(argv[i]);
132 }
133 catch(...) {
134 Log::e("invalid time.slw parameter [",i,"]: \"", argv[i], "\"");
135 }
136 }
137 uint64_t v[2] = {};
138 for(int i=0; i<2; ++i)
139 v[i] = uint64_t(val[i]*1000);
140 // todo: separated time-scale
141 SlowTime s;
142 s.mul = v[0];
143 s.div = 1000;
144 timeEff.emplace_back(std::make_shared<SlowTime>(s));
145 return GlobalFx(timeEff.back());
146 }
147
148GlobalFx GlobalEffects::addScreenBlend(const std::string* argv, size_t argc) {
149 ScreenBlend sc;
150
151 if(0<argc) try {
152 sc.loop = float(std::stof(argv[0]));
153 }
154 catch(...) {
155 Log::e("invalid screenblend.scx parameter [0]: \"", argv[0], "\"");
156 }
157
158 if(1<argc) {
159 sc.cl = parseColor(argv[1]);
160 }
161
162 if(2<argc) try {
163 sc.inout = float(std::stof(argv[2]));
164 }
165 catch(...){
166 Log::e("invalid screenblend.scx parameter [2]: \"", argv[2], "\"");
167 }
168
169 if(3<argc) {
170 sc.frames = Resources::loadTextureAnim(argv[3]);
171 }
172
173 if(4<argc) try {
174 sc.fps = size_t(std::stoi(argv[4]));
175 }
176 catch(...) {
177 Log::e("invalid screen-blend parameter [4]: \"", argv[4], "\"");
178 }
179
180 sc.timeLoop = uint64_t(sc.loop*1000.f);
181
182 scrEff.emplace_back(std::make_shared<ScreenBlend>(sc));
183 return GlobalFx(scrEff.back());
184 }
185
186GlobalFx GlobalEffects::addMorphFov(const std::string* argv, size_t argc) {
187 double val[4] = {0,0,0,0};
188 for(size_t i=0; i<argc && i<4; ++i) {
189 val[i] = std::stof(argv[i]);
190 }
191 Morph m;
192 m.amplitude = float(val[0]);
193 m.speed = float(val[1]);
194 m.baseX = float(val[2]);
195 m.baseY = float(val[3]);
196
197 morphEff.emplace_back(std::make_shared<Morph>(m));
198 return GlobalFx(morphEff.back());
199 }
200
201GlobalFx GlobalEffects::addEarthQuake(const std::string*, size_t) {
202 quakeEff.emplace_back(std::make_shared<Quake>());
203 return GlobalFx(quakeEff.back());
204 }
205
206Tempest::Color GlobalEffects::parseColor(std::string_view sv) {
207 auto s = std::string(sv);
208 auto str = s.data();
209
210 float v[4] = {};
211 for(int i=0;i<4;++i) {
212 char* next=nullptr;
213 v[i] = std::strtof(str,&next)/255.f;
214 if(str==next)
215 if(i==1) {
216 return Tempest::Color(v[0],v[0],v[0],1.f);
217 if(i==2)
218 return Tempest::Color(v[0],v[1],0.f,1.f);
219 if(i==3)
220 return Tempest::Color(v[0],v[1],v[2],1.f);
221 }
222 str = next;
223 }
224 return Tempest::Color(v[0],v[1],v[2],v[3]);
225 }
226
227void GlobalEffects::Effect::stop() {
228 timeUntil = 0;
229 }
void scrBlend(Tempest::Painter &p, const Tempest::Rect &rect)
friend class GlobalFx
void tick(uint64_t dt)
void scaleTime(uint64_t &dt)
GlobalEffects(World &owner)
void stopEffect(const VisualFx &vfx)
GlobalFx startEffect(std::string_view what, uint64_t len, const std::string *argv, size_t argc)
void morph(Tempest::Matrix4x4 &proj)
static auto loadTextureAnim(std::string_view name) -> std::vector< const Tempest::Texture2d * >
std::string visName_S
Definition visualfx.h:104
Definition world.h:31
uint64_t tickCount() const
Definition world.cpp:387
static float generator(uint64_t dt, uint64_t period)