1 | // This file is a part of the Framsticks GDK library. |
---|
2 | // Copyright (C) 2002-2011 Szymon Ulatowski. See LICENSE.txt for details. |
---|
3 | // Refer to http://www.framsticks.com/ for further information. |
---|
4 | |
---|
5 | #include "neuroimpl.h" |
---|
6 | #include "neurofactory.h" |
---|
7 | #ifndef GDK_WITHOUT_FRAMS |
---|
8 | #include "creature.h" |
---|
9 | #include "creatmechobj.h" |
---|
10 | #include "livegroups.h" |
---|
11 | #include "simul.h" |
---|
12 | #endif |
---|
13 | |
---|
14 | const int NeuroImpl::ENDDRAWING=-9999; |
---|
15 | const int NeuroImpl::MAXDRAWINGXY=0xffff; |
---|
16 | |
---|
17 | int NeuroNetImpl::mytags_id=0; |
---|
18 | |
---|
19 | ///////////////////////////////////////////////////////// |
---|
20 | |
---|
21 | #define FIELDSTRUCT NeuroNetConfig |
---|
22 | static ParamEntry nncfg_paramtab[]= |
---|
23 | { |
---|
24 | {"Creature: Neurons",1,2,"nnsim",}, |
---|
25 | {"randinit",1,0,"Random initialization","f 0 10 0.01",FIELD(randominit),"Allowed range for initializing all neuron states with uniform distribution random numbers and zero mean. Set 0 for deterministic initialization."}, |
---|
26 | {"touchrange",1,0,"T receptor range","f 0 100 1",FIELD(touchrange),}, |
---|
27 | {0,0,0,}, |
---|
28 | }; |
---|
29 | #undef FIELDSTRUCT |
---|
30 | |
---|
31 | NeuroNetConfig::NeuroNetConfig() |
---|
32 | :par(nncfg_paramtab,this), |
---|
33 | randominit(0.01), |
---|
34 | touchrange(1) |
---|
35 | {} |
---|
36 | |
---|
37 | NeuroNetConfig NeuroNetConfig::globalconfig; |
---|
38 | |
---|
39 | ///////////////////////////////////////////////////////////////// |
---|
40 | |
---|
41 | NeuroNetImpl::NeuroNetImpl(Model& model, NeuroNetConfig& conf |
---|
42 | #ifdef NEURO_SIGNALS |
---|
43 | , ChannelSpace *ch |
---|
44 | #endif |
---|
45 | ) |
---|
46 | :mod(model),config(conf), |
---|
47 | isbuilt(1),errorcount(0) |
---|
48 | #ifdef NEURO_SIGNALS |
---|
49 | ,channels(ch) |
---|
50 | #endif |
---|
51 | { |
---|
52 | if (!mytags_id) mytags_id=mod.userdata.newID(); |
---|
53 | |
---|
54 | Neuro *n; |
---|
55 | NeuroImpl *ni; |
---|
56 | Joint *j; |
---|
57 | int i; |
---|
58 | DB(printf("makeNeuroNet(%p)\n",&mod)); |
---|
59 | |
---|
60 | minorder=3; maxorder=0; |
---|
61 | errorcount=0; |
---|
62 | |
---|
63 | for (i=0;j=mod.getJoint(i);i++) |
---|
64 | j->flags&=~(4+8); // todo: !!!neuroitems shouldn't use model fields!!! |
---|
65 | |
---|
66 | for (i=0;n=mod.getNeuro(i);i++) |
---|
67 | { |
---|
68 | ni=NeuroFactory::createNeuroImpl(n); |
---|
69 | n->userdata[mytags_id]=ni; |
---|
70 | if (!ni) { errorcount++; |
---|
71 | FMprintf("NeuroNetImpl","create",FMLV_WARN,"neuron #%d (%s) implementation not available", |
---|
72 | i,(const char*)n->getClassName()); |
---|
73 | continue; } // implementation not available?! |
---|
74 | ni->owner=this; |
---|
75 | ni->neuro=n; |
---|
76 | ni->readParam(); |
---|
77 | } |
---|
78 | |
---|
79 | for (i=0;n=mod.getNeuro(i);i++) |
---|
80 | { |
---|
81 | n->state+=(rnd01-0.5)*config.randominit; |
---|
82 | ni=(NeuroImpl*)n->userdata[mytags_id]; |
---|
83 | if (!ni) continue; |
---|
84 | if (!ni->lateinit()) |
---|
85 | { ni->status=NeuroImpl::InitError; errorcount++; |
---|
86 | FMprintf("NeuroNetImpl","create",FMLV_WARN,"neuron #%d (%s) initialization failed", |
---|
87 | i,(const char*)n->getClassName()); |
---|
88 | continue; } |
---|
89 | ni->status=NeuroImpl::InitOk; |
---|
90 | int order=ni->getSimOrder(); |
---|
91 | if (order<0) order=0; else if (order>2) order=2; |
---|
92 | if (order<minorder) minorder=order; |
---|
93 | if (order>maxorder) maxorder=order; |
---|
94 | neurons[order]+=ni; |
---|
95 | if (ni->getNeedPhysics()) |
---|
96 | neurons[3]+=ni; |
---|
97 | } |
---|
98 | cnode=mod.delmodel_list.add(STATRICKCALLBACK(this,&NeuroNetImpl::destroyNN,0)); |
---|
99 | } |
---|
100 | |
---|
101 | void NeuroNetImpl::destroyNN(CALLBACKARGS) |
---|
102 | { |
---|
103 | if (!isbuilt) return; |
---|
104 | DB(printf("destroyNeuroNet(%p)\n",&mod)); |
---|
105 | NeuroImpl *ni; |
---|
106 | Neuro *n; |
---|
107 | for (int i=0;n=mod.getNeuro(i);i++) |
---|
108 | { |
---|
109 | ni=(NeuroImpl*)n->userdata[mytags_id]; |
---|
110 | delete ni; |
---|
111 | n->userdata[mytags_id]=0; |
---|
112 | } |
---|
113 | mod.delmodel_list.remove(cnode); |
---|
114 | isbuilt=0; errorcount=0; |
---|
115 | delete this; |
---|
116 | } |
---|
117 | |
---|
118 | NeuroNetImpl::~NeuroNetImpl() |
---|
119 | { |
---|
120 | destroyNN(0,0); |
---|
121 | } |
---|
122 | |
---|
123 | void NeuroNetImpl::simulateNeuroNet() |
---|
124 | { |
---|
125 | NeuroImpl *ni; |
---|
126 | for (int order=minorder;order<=maxorder;order++) |
---|
127 | { |
---|
128 | int i; |
---|
129 | SList &nlist=neurons[order]; |
---|
130 | for (i=0;ni=(NeuroImpl*)nlist(i);i++) |
---|
131 | ni->go(); |
---|
132 | for (i=0;ni=(NeuroImpl*)nlist(i);i++) |
---|
133 | ni->commit(); |
---|
134 | } |
---|
135 | } |
---|
136 | |
---|
137 | void NeuroNetImpl::simulateNeuroPhysics() |
---|
138 | { |
---|
139 | NeuroImpl *ni; |
---|
140 | int i; |
---|
141 | SList &nlist=neurons[3]; |
---|
142 | for (i=0;ni=(NeuroImpl*)nlist(i);i++) |
---|
143 | ni->goPhysics(); |
---|
144 | } |
---|
145 | |
---|
146 | /////////////////////////////////////////////// |
---|
147 | |
---|
148 | void NeuroImpl::setChannelCount(int c) |
---|
149 | { |
---|
150 | if (c<1) c=1; |
---|
151 | if (c==channels) return; |
---|
152 | if (c<channels) {channels=c; chstate.trim(c-1); chnewstate.trim(c-1); return;} |
---|
153 | double s=getState(channels-1); |
---|
154 | chnewstate.setSize(c-1); |
---|
155 | chstate.setSize(c-1); |
---|
156 | for(int i=channels;i<c;i++) |
---|
157 | {chstate(i-1)=s; chnewstate(i-1)=s;} |
---|
158 | channels=c; |
---|
159 | } |
---|
160 | |
---|
161 | void NeuroImpl::setState(double st,int channel) |
---|
162 | { |
---|
163 | validateNeuroState(st); |
---|
164 | if (channel>=channels) channel=channels-1; |
---|
165 | if (channel<=0) {newstate=st;return;} |
---|
166 | chnewstate(channel-1)=st; |
---|
167 | } |
---|
168 | |
---|
169 | void NeuroImpl::setCurrentState(double st,int channel) |
---|
170 | { |
---|
171 | validateNeuroState(st); |
---|
172 | if (channel>=channels) channel=channels-1; |
---|
173 | if (channel<=0) {neuro->state=st; return;} |
---|
174 | chstate(channel-1)=st; |
---|
175 | } |
---|
176 | |
---|
177 | double NeuroImpl::getNewState(int channel) |
---|
178 | { |
---|
179 | if (neuro->flags&Neuro::HoldState) return getState(channel); |
---|
180 | if (channel>=channels) channel=channels-1; |
---|
181 | if (channel<=0) {return newstate;} |
---|
182 | return chnewstate(channel-1); |
---|
183 | } |
---|
184 | |
---|
185 | double NeuroImpl::getState(int channel) |
---|
186 | { |
---|
187 | if (channel>=channels) channel=channels-1; |
---|
188 | if (channel<=0) return neuro->state; |
---|
189 | return chstate(channel-1); |
---|
190 | } |
---|
191 | |
---|
192 | void NeuroImpl::commit() |
---|
193 | { |
---|
194 | if (!(neuro->flags&Neuro::HoldState)) |
---|
195 | { |
---|
196 | if (channels>1) |
---|
197 | chstate=chnewstate; |
---|
198 | neuro->state=newstate; |
---|
199 | } |
---|
200 | } |
---|
201 | |
---|
202 | int NeuroImpl::getInputChannelCount(int i) |
---|
203 | { |
---|
204 | if ((i<0)||(i >= neuro->getInputCount())) return 1; |
---|
205 | Neuro *nu=neuro->getInput(i); |
---|
206 | NeuroImpl *ni=NeuroNetImpl::getImpl(nu); |
---|
207 | if (!ni) return 1; |
---|
208 | return ni->channels; |
---|
209 | } |
---|
210 | |
---|
211 | double NeuroImpl::getInputState(int i,int channel) |
---|
212 | { |
---|
213 | if ((i<0)||(i >= neuro->getInputCount())) return 0; |
---|
214 | Neuro *nu=neuro->getInput(i); |
---|
215 | if (channel<=0) return nu->state; |
---|
216 | NeuroImpl *ni=NeuroNetImpl::getImpl(nu); |
---|
217 | if (!ni) return nu->state; |
---|
218 | if (channel>=ni->channels) channel=ni->channels-1; |
---|
219 | if (!channel) return nu->state; |
---|
220 | return ni->chstate(channel-1); |
---|
221 | } |
---|
222 | |
---|
223 | double NeuroImpl::getWeightedInputState(int i, int channel) |
---|
224 | { |
---|
225 | if ((i<0)||(i >= neuro->getInputCount())) return 0; |
---|
226 | float w; |
---|
227 | Neuro *nu=neuro->getInput(i,w); |
---|
228 | if (channel<=0) return nu->state * w; |
---|
229 | NeuroImpl *ni=NeuroNetImpl::getImpl(nu); |
---|
230 | if (!ni) return nu->state * w; |
---|
231 | if (channel>=ni->channels) channel=ni->channels-1; |
---|
232 | if (!channel) return w * nu->state; |
---|
233 | return w * ni->chstate(channel-1); |
---|
234 | } |
---|
235 | |
---|
236 | double NeuroImpl::getInputSum(int startwith) |
---|
237 | { |
---|
238 | if (startwith<0) return 0; |
---|
239 | Neuro *inp; |
---|
240 | double sum=0.0; |
---|
241 | while(inp=neuro->getInput(startwith++)) |
---|
242 | sum+=inp->state; |
---|
243 | return sum; |
---|
244 | } |
---|
245 | |
---|
246 | double NeuroImpl::getWeightedInputSum(int startwith) |
---|
247 | { |
---|
248 | if (startwith<0) return 0; |
---|
249 | Neuro *inp; |
---|
250 | double sum=0.0; |
---|
251 | float w; |
---|
252 | while(inp=neuro->getInput(startwith++,w)) |
---|
253 | sum+=inp->state*w; |
---|
254 | return sum; |
---|
255 | } |
---|
256 | |
---|
257 | void NeuroImpl::readParam() |
---|
258 | { |
---|
259 | static Param par; |
---|
260 | if (!paramentries) return; |
---|
261 | par.setParamTab(paramentries); |
---|
262 | par.select(this); |
---|
263 | par.setDefault(); |
---|
264 | int zero=0; |
---|
265 | par.load2(neuro->getClassParams(),zero); |
---|
266 | } |
---|
267 | |
---|
268 | ///////////////////////////// |
---|
269 | |
---|
270 | #ifdef NEURO_SIGNALS |
---|
271 | #define NEUROIMPL_SIGNAL_PROPS 1 |
---|
272 | #else |
---|
273 | #define NEUROIMPL_SIGNAL_PROPS 0 |
---|
274 | #endif |
---|
275 | |
---|
276 | #define FIELDSTRUCT NeuroImpl |
---|
277 | ParamEntry neuroimpl_tab[]= |
---|
278 | { |
---|
279 | {"Neuro",1,27+NEUROIMPL_SIGNAL_PROPS,"Neuro","Live Neuron object."}, |
---|
280 | |
---|
281 | {"getInputState",0,0,"Get input signal","p f(d input)",PROCEDURE(p_get),}, |
---|
282 | {"getInputWeight",0,0,"Get input weight","p f(d input)",PROCEDURE(p_getweight),}, |
---|
283 | {"getWeightedInputState",0,0,"Get weighted input signal","p f(d input)",PROCEDURE(p_getw),}, |
---|
284 | {"getInputSum",0,0,"Get signal sum","p f(d input)",PROCEDURE(p_getsum),}, |
---|
285 | {"getWeightedInputSum",0,0,"Get weighted signal sum","p f(d input)",PROCEDURE(p_getwsum),"Uses any number of inputs starting with the specified input. getWeightedInputSum(0)=weightedInputSum"}, |
---|
286 | {"getInputCount",0,0,"Get input count","d",GETONLY(count),}, |
---|
287 | {"inputSum",0,0,"Full signal sum","f",GETONLY(sum),}, |
---|
288 | {"weightedInputSum",0,0,"Full weighted signal sum","f",GETONLY(wsum),}, |
---|
289 | {"getInputChannelCount",0,0,"Get channel count for input","p d(d input)",PROCEDURE(p_getchancount),}, |
---|
290 | {"getInputStateChannel",0,0,"Get input signal from channel","p f(d input,d channel)",PROCEDURE(p_getchan),}, |
---|
291 | {"getWeightedInputStateChannel",0,0,"Get weighted input signal from channel","p f(d input,d channel)",PROCEDURE(p_getwchan),}, |
---|
292 | {"state",0,0,"Neuron state (channel 0)","f",GETSET(state),"When read, returns the current neuron state.\nWhen written, sets the next neuron state (for use in the neuron definition)"}, |
---|
293 | {"channelCount",0,0,"Number of output channels","d",GETSET(channels),}, |
---|
294 | {"getStateChannel",0,0,"Get output state for channel","p f(d channel)",PROCEDURE(p_getstate),}, |
---|
295 | {"setStateChannel",0,0,"Set output state for channel","p(d channel,f value)",PROCEDURE(p_setstate),}, |
---|
296 | {"hold",0,0,"Hold state","d 0 1",GETSET(hold),"\"Holding\" means keeping the neuron state as is, blocking the regular neuron operation. This is useful when your script needs to inject some control signals into the NN. Without \"holding\", live neurons would be constantly overwriting your changes, and the rest of the NN could see inconsistent states, depending on the connections. Setting hold=1 ensures the neuron state will be only set by you, and not by the neuron. The enforced signal value can be set using Neuro.currState before or after setting hold=1. Set hold=0 to resume normal operation.",}, |
---|
297 | {"currState",0,0,"Neuron state (channel 0)","f",GETSET(cstate),"The only difference from the \"state\" field is that currState, when written, changes the internal neuron state immediately (which disturbs the regular synchronous NN operation). This feature should only be used while controlling the neuron 'from outside' (like a neuro probe) and not in the neuron definition. See also: Neuro.hold",}, |
---|
298 | {"setCurrStateChannel",0,0,"Set neuron for channel","p(d channel,f value)",PROCEDURE(p_setcstate),"Analogous to \"currState\"."}, |
---|
299 | {"position_x",0,0,"Position x","f",GETONLY(position_x),}, |
---|
300 | {"position_y",0,0,"Position y","f",GETONLY(position_y),}, |
---|
301 | {"position_z",0,0,"Position z","f",GETONLY(position_z),}, |
---|
302 | {"creature",0,0,"Gets owner creature","o Creature",GETONLY(creature),}, |
---|
303 | {"part",0,0,"The Part object where this neuron is located","o MechPart",GETONLY(part),}, |
---|
304 | {"joint",0,0,"The Joint object where this neuron is located","o MechJoint",GETONLY(joint),}, |
---|
305 | {"fields",0,0,"Custom neuron fields","o Fields",GETONLY(fields), |
---|
306 | "Neurons can have different fields depending on their class. Script neurons have their fields defined using the \"prop:\" syntax. If you develop a custom neuron script you should use the Fields object for accessing your own neuron fields. The Neuro.fields property is meant for accessing the neuron fields from the outside script.\n" |
---|
307 | "Examples:\n" |
---|
308 | "var c=Populations.createFromString(\"X[N]\");\n" |
---|
309 | "Simulator.print(\"standard neuron inertia=\"+c.getNeuro(0).fields.in);\n" |
---|
310 | "c=Populations.createFromString(\"X[Nn,e:0.1]\");\n" |
---|
311 | "Simulator.print(\"noisy neuron error rate=\"+c.getNeuro(0).fields.e);\n" |
---|
312 | "\n" |
---|
313 | "The Interface object can be used to discover which fields are available for a certain neuron object:\n" |
---|
314 | "c=Populations.createFromString(\"X[N]\");\n" |
---|
315 | "var iobj=Interface.makeFrom(c.getNeuro(0).fields);\n" |
---|
316 | "var i;\n" |
---|
317 | "for(i=0;i<iobj.properties;i++)\n" |
---|
318 | " Simulator.print(iobj.getId(i)+\" (\"+iobj.getName(i)+\")\");",}, |
---|
319 | {"def",0,0,"Neuron definition from which this live neuron was built","o NeuroDef",GETONLY(neurodef),}, |
---|
320 | {"classObject",0,0,"Neuron class for this neuron","o NeuroClass",GETONLY(classObject),}, |
---|
321 | #ifdef NEURO_SIGNALS |
---|
322 | {"signals",0,PARAM_READONLY,"Signals","o NeuroSignals",FIELD(sigs_obj),}, |
---|
323 | #endif |
---|
324 | |
---|
325 | {0,0,0,}, |
---|
326 | }; |
---|
327 | #undef FIELDSTRUCT |
---|
328 | |
---|
329 | #ifdef NEURO_SIGNALS |
---|
330 | ParamEntry neurosignals_paramtab[]= |
---|
331 | { |
---|
332 | {"NeuroSignals",1,8,"NeuroSignals","Signals attached to the neuron.\nSee also: Signal, WorldSignals, CreatureSignals.\nscripts/light.neuro and scripts/seelight.neuro are simple custom neuron examples demonstrating how to send/receive signals between creatures.",}, |
---|
333 | |
---|
334 | #define FIELDSTRUCT NeuroSignals |
---|
335 | {"add",0,PARAM_NOSTATIC,"Add","p(s channel)",PROCEDURE(p_add),"Create a new signal"}, |
---|
336 | {"receive",0,PARAM_NOSTATIC,"Receive","p f(s channel)",PROCEDURE(p_receive),"Receive the aggregated signal power in a given channel."}, |
---|
337 | {"receiveSet",0,PARAM_NOSTATIC,"Receive","p oVector(s channel,f max distance)",PROCEDURE(p_receiveSet),"Get all signals in the specified range. Returns a readonly vector object containing Signal objects (individual signals can be accessed as result[0] throught result[result.size-1])."}, |
---|
338 | {"receiveFilter",0,PARAM_NOSTATIC,"receive","p f(s channel,f max distance,f flavor,f filter)",PROCEDURE(p_receiveFilter),"Receive the aggregated signal power in a given channel.\n\nAdditional filtering options:\n- Max distance only receives the neighbor signals (based on their physical location)\n- Flavor filtering: only signals having the flavor close to the specified one will be received. The filter value is the maximum allowed difference."}, |
---|
339 | {"receiveSingle",0,PARAM_NOSTATIC,"Receive","p oSignal(s channel,f range)",PROCEDURE(p_receiveSingle),"Find the signal source having the highest signal power (including the distance)"}, |
---|
340 | #undef FIELDSTRUCT |
---|
341 | |
---|
342 | #define FIELDSTRUCT SignalSet |
---|
343 | {"get",0,PARAM_NOSTATIC,"Get","p oSignal(d index)",PROCEDURE(p_get),}, |
---|
344 | {"size",0,1+PARAM_NOSTATIC,"Size","d",GETONLY(size),}, |
---|
345 | {"clear",0,1+PARAM_NOSTATIC,"Clear","p()",PROCEDURE(p_clear),}, |
---|
346 | #undef FIELDSTRUCT |
---|
347 | {0,0,0,}, |
---|
348 | }; |
---|
349 | Param neurosignals_param(neurosignals_paramtab,0); |
---|
350 | #endif |
---|
351 | |
---|
352 | Param st_neuroimplparam(neuroimpl_tab,0,"Neuro"); |
---|
353 | |
---|
354 | #ifdef NEURO_SIGNALS |
---|
355 | class NeuroSigSource: public SigSource |
---|
356 | { |
---|
357 | protected: |
---|
358 | NeuroImpl* owner; |
---|
359 | public: |
---|
360 | NeuroSigSource(NeuroImpl *n,Creature *c):SigSource(0,c),owner(n) {} |
---|
361 | bool update(); |
---|
362 | }; |
---|
363 | |
---|
364 | bool NeuroSigSource::update() |
---|
365 | { |
---|
366 | Pt3D p; |
---|
367 | if (owner->getPosition(p)) |
---|
368 | { |
---|
369 | setLocation(p); |
---|
370 | return true; |
---|
371 | } |
---|
372 | return false; |
---|
373 | } |
---|
374 | |
---|
375 | Creature *NeuroSignals::getCreature() |
---|
376 | { |
---|
377 | if (!cr) |
---|
378 | { |
---|
379 | cr=owner->getCreature(); |
---|
380 | } |
---|
381 | return cr; |
---|
382 | } |
---|
383 | |
---|
384 | void NeuroSignals::p_add(PARAMPROCARGS) |
---|
385 | { |
---|
386 | SigSource *s=new NeuroSigSource(owner,getCreature()); |
---|
387 | if (owner->owner->channels) |
---|
388 | { |
---|
389 | SigChannel *ch=owner->owner->channels->getChannel(args->getString(),true); |
---|
390 | ch->addSource(s); |
---|
391 | } |
---|
392 | else |
---|
393 | SigChannel::dummy_channel.addSource(s); |
---|
394 | sigs+=s; |
---|
395 | s->setupObject(ret); |
---|
396 | } |
---|
397 | |
---|
398 | void NeuroSignals::p_receive(PARAMPROCARGS) |
---|
399 | { |
---|
400 | SigChannel *ch; Pt3D p; |
---|
401 | if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args->getString(),false)) && owner->getPosition(p)) |
---|
402 | ret->setDouble(ch->receive(&p,getCreature())); |
---|
403 | else |
---|
404 | ret->setDouble(0); |
---|
405 | } |
---|
406 | |
---|
407 | void NeuroSignals::p_receiveFilter(PARAMPROCARGS) |
---|
408 | { |
---|
409 | SigChannel *ch; Pt3D p; |
---|
410 | if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[3].getString(),false)) && owner->getPosition(p)) |
---|
411 | ret->setDouble(ch->receive(&p,getCreature(),args[2].getDouble(),args[1].getDouble(),args[0].getDouble())); |
---|
412 | else |
---|
413 | ret->setDouble(0); |
---|
414 | } |
---|
415 | |
---|
416 | void NeuroSignals::p_receiveSet(PARAMPROCARGS) |
---|
417 | { |
---|
418 | SigChannel *ch; Pt3D p; |
---|
419 | SigVector *vec=new SigVector(); |
---|
420 | if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p)) |
---|
421 | ch->receiveSet(vec,&p,getCreature(),args[0].getDouble()); |
---|
422 | ret->setObject(vec->makeObject()); |
---|
423 | } |
---|
424 | |
---|
425 | void NeuroSignals::p_receiveSingle(PARAMPROCARGS) |
---|
426 | { |
---|
427 | SigChannel *ch; Pt3D p; |
---|
428 | if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p)) |
---|
429 | { |
---|
430 | SigSource *src=ch->receiveSingle(&p,getCreature(),args[0].getDouble(),0,1e99); |
---|
431 | if (src) |
---|
432 | { |
---|
433 | src->setupObject(ret); |
---|
434 | return; |
---|
435 | } |
---|
436 | } |
---|
437 | ret->setEmpty(); |
---|
438 | } |
---|
439 | #endif |
---|
440 | |
---|
441 | extern ParamEntry creature_paramtab[]; |
---|
442 | static Param creature_param(creature_paramtab,0); |
---|
443 | |
---|
444 | Creature* NeuroImpl::getCreature() |
---|
445 | { |
---|
446 | #ifndef GDK_WITHOUT_FRAMS |
---|
447 | CreatMechObject *cmo=(CreatMechObject *)neuro->owner->userdata[CreatMechObject::modeltags_id]; |
---|
448 | return cmo->creature; |
---|
449 | #else |
---|
450 | return 0; |
---|
451 | #endif |
---|
452 | } |
---|
453 | |
---|
454 | void NeuroImpl::get_creature(ExtValue *ret) |
---|
455 | { |
---|
456 | #ifndef GDK_WITHOUT_FRAMS |
---|
457 | ret->setObject(ExtObject(&creature_param,getCreature())); |
---|
458 | #endif |
---|
459 | } |
---|
460 | |
---|
461 | void NeuroImpl::get_part(ExtValue *ret) |
---|
462 | { |
---|
463 | #ifndef GDK_WITHOUT_FRAMS |
---|
464 | Part *pa; |
---|
465 | if (pa=neuro->getPart()) |
---|
466 | ret->setObject(ExtObject(&mechpart_param,((MechPart *)pa->userdata[CreatMechObject::modeltags_id]))); |
---|
467 | else |
---|
468 | ret->setEmpty(); |
---|
469 | #endif |
---|
470 | } |
---|
471 | |
---|
472 | void NeuroImpl::get_joint(ExtValue *ret) |
---|
473 | { |
---|
474 | #ifndef GDK_WITHOUT_FRAMS |
---|
475 | Joint *jo; |
---|
476 | if (jo=neuro->getJoint()) |
---|
477 | ret->setObject(ExtObject(&mechjoint_param,((MechJoint*)jo->userdata[CreatMechObject::modeltags_id]))); |
---|
478 | else |
---|
479 | ret->setEmpty(); |
---|
480 | #endif |
---|
481 | } |
---|
482 | |
---|
483 | bool NeuroImpl::getPosition(Pt3D &pos) |
---|
484 | { |
---|
485 | #ifndef GDK_WITHOUT_FRAMS |
---|
486 | Part *pa; Joint *jo; |
---|
487 | if (pa=neuro->getPart()) |
---|
488 | {pos=((MechPart *)pa->userdata[CreatMechObject::modeltags_id])->p; return true;} |
---|
489 | if (jo=neuro->getJoint()) |
---|
490 | { |
---|
491 | if (neuro->getClass()->getVisualHints() & NeuroClass::AtFirstPart) |
---|
492 | pos=((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p; |
---|
493 | else if (neuro->getClass()->getVisualHints() & NeuroClass::AtSecondPart) |
---|
494 | pos=((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p; |
---|
495 | else pos=(((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p |
---|
496 | +((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p)/2; |
---|
497 | return true; |
---|
498 | } |
---|
499 | #endif |
---|
500 | return false; |
---|
501 | } |
---|
502 | |
---|
503 | void NeuroImpl::get_position_x(ExtValue *ret) |
---|
504 | {Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.x); else ret->setEmpty();} |
---|
505 | void NeuroImpl::get_position_y(ExtValue *ret) |
---|
506 | {Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.y); else ret->setEmpty();} |
---|
507 | void NeuroImpl::get_position_z(ExtValue *ret) |
---|
508 | {Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.z); else ret->setEmpty();} |
---|
509 | |
---|
510 | |
---|
511 | void NeuroImpl::createFieldsObject() |
---|
512 | { |
---|
513 | fields_param=new Param(paramentries?paramentries:(ParamEntry*)&empty_paramtab,this,"Fields"); |
---|
514 | fields_object=new ExtObject(fields_param); |
---|
515 | } |
---|
516 | |
---|
517 | void NeuroImpl::get_fields(ExtValue *ret) |
---|
518 | { |
---|
519 | if (!fields_object) |
---|
520 | createFieldsObject(); |
---|
521 | ret->setObject(*fields_object); |
---|
522 | } |
---|
523 | |
---|
524 | void NeuroImpl::get_neurodef(ExtValue *ret) |
---|
525 | { |
---|
526 | ret->setObject(ExtObject(&st_neuroparam,neuro)); |
---|
527 | } |
---|
528 | |
---|
529 | void NeuroImpl::get_classObject(ExtValue *ret) |
---|
530 | { |
---|
531 | #ifndef GDK_WITHOUT_FRAMS |
---|
532 | NeuroClassExt::makeStaticObject(ret,neuroclass); |
---|
533 | #endif |
---|
534 | } |
---|
535 | |
---|
536 | NeuroImpl::~NeuroImpl() |
---|
537 | { |
---|
538 | if (fields_param) |
---|
539 | { |
---|
540 | delete fields_param; |
---|
541 | delete fields_object; |
---|
542 | } |
---|
543 | } |
---|