source: cpp/frams/neuro/neuroimpl.cpp @ 1181

Last change on this file since 1181 was 952, checked in by Maciej Komosinski, 4 years ago

Added new receptors (Gp:"gyroscope" on a Part, Tp:Touch-proximity and Tc:Touch-contact) and improved existing ones (T, G)

  • Property svn:eol-style set to native
File size: 18.6 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "neuroimpl.h"
6#include "neurofactory.h"
7#include <frams/util/rndutil.h>
8#include <common/nonstd_math.h>
9#ifndef SDK_WITHOUT_FRAMS
10#include <frams/simul/creature.h>
11#include <frams/mech/creatmechobj.h>
12#include <frams/simul/livegroups.h>
13#include <frams/simul/simul.h>
14#endif
15#include <frams/vm/classes/3dobject.h>
16
17const int NeuroImpl::ENDDRAWING = -9999;
18const int NeuroImpl::MAXDRAWINGXY = 0xffff;
19
20int NeuroNetImpl::mytags_id = 0;
21
22/////////////////////////////////////////////////////////
23
24#define FIELDSTRUCT NeuroNetConfig
25static ParamEntry nncfg_paramtab[] =
26{
27        { "Creature: Neurons", 1, 3, "nnsim", },
28        { "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 to 0 for deterministic initialization." },
29        { "nnoise", 1, 0, "Noise", "f 0 1 0", FIELD(nnoise), "Gaussian neural noise: a random value is added to each neural output in each simulation step. Set standard deviation here to add random noise, or 0 for deterministic simulation." },
30        { "touchrange", 1, 0, "T receptor range", "f 0 100 1", FIELD(touchrange), },
31        { 0, 0, 0, },
32};
33#undef FIELDSTRUCT
34
35NeuroNetConfig::NeuroNetConfig(NeuroFactory *fac)
36        :par(nncfg_paramtab, this),
37        randominit(0.01),
38        nnoise(0),
39        touchrange(1),
40        factory(fac)
41{}
42
43/////////////////////////////////////////////////////////////////
44
45NeuroNetImpl::NeuroNetImpl(Model& model, NeuroNetConfig& conf
46#ifdef NEURO_SIGNALS
47        , ChannelSpace *ch
48#endif
49)
50        :mod(model), config(conf),
51        isbuilt(1), errorcount(0)
52#ifdef NEURO_SIGNALS
53        , channels(ch)
54#endif
55{
56        if (!mytags_id) mytags_id = mod.userdata.newID();
57
58        Neuro *n;
59        NeuroImpl *ni;
60        Joint *j;
61        int i;
62        DB(printf("makeNeuroNet(%p)\n", &mod));
63
64        minorder = 3; maxorder = 0;
65        errorcount = 0;
66
67        for (i = 0; j = mod.getJoint(i); i++)
68                j->flags &= ~(4 + 8); // todo: !!!neuroitems shouldn't use model fields!!!
69
70        for (i = 0; n = mod.getNeuro(i); i++)
71        {
72                ni = conf.factory->createNeuroImpl(n, mod.getShapeType());
73                n->userdata[mytags_id] = ni;
74                if (!ni)
75                {
76                        errorcount++;
77                        logPrintf("NeuroNetImpl", "create", LOG_WARN, "neuron #%d (%s) implementation not available",
78                                i, n->getClassName().c_str());
79                        continue;
80                } // implementation not available?!
81                ni->owner = this;
82                ni->neuro = n;
83                ni->readParam();
84        }
85
86        for (i = 0; n = mod.getNeuro(i); i++)
87        {
88                n->state += (rndDouble(1) - 0.5) * config.randominit;
89                ni = (NeuroImpl*)n->userdata[mytags_id];
90                if (!ni) continue;
91                if (!ni->lateinit())
92                {
93                        ni->status = NeuroImpl::InitError;
94                        errorcount++;
95                        logPrintf("NeuroNetImpl", "create", LOG_WARN, "neuron #%d (%s) initialization failed",
96                                i, n->getClassName().c_str());
97                        continue;
98                }
99                ni->status = NeuroImpl::InitOk;
100                int order = ni->getSimOrder();
101                if (order < 0) order = 0; else if (order > 2) order = 2;
102                if (order < minorder) minorder = order;
103                if (order > maxorder) maxorder = order;
104                neurons[order] += ni;
105                if (ni->getNeedPhysics())
106                        neurons[3] += ni;
107        }
108        cnode = mod.delmodel_list.add(STATRICKCALLBACK(this, &NeuroNetImpl::destroyNN, 0));
109}
110
111void NeuroNetImpl::destroyNN(CALLBACKARGS)
112{
113        if (!isbuilt) return;
114        DB(printf("destroyNeuroNet(%p)\n", &mod));
115        NeuroImpl *ni;
116        Neuro *n;
117        for (int i = 0; n = mod.getNeuro(i); i++)
118        {
119                ni = (NeuroImpl*)n->userdata[mytags_id];
120                delete ni;
121                n->userdata[mytags_id] = 0;
122        }
123        mod.delmodel_list.remove(cnode);
124        isbuilt = 0; errorcount = 0;
125        delete this;
126}
127
128NeuroNetImpl::~NeuroNetImpl()
129{
130        destroyNN(0, 0);
131}
132
133void NeuroNetImpl::simulateNeuroNet()
134{
135        NeuroImpl *ni;
136        for (int order = minorder; order <= maxorder; order++)
137        {
138                int i;
139                SList &nlist = neurons[order];
140                for (i = 0; ni = (NeuroImpl*)nlist(i); i++)
141                        ni->go();
142                for (i = 0; ni = (NeuroImpl*)nlist(i); i++)
143                        ni->commit();
144        }
145}
146
147void NeuroNetImpl::simulateNeuroPhysics()
148{
149        NeuroImpl *ni;
150        int i;
151        SList &nlist = neurons[3];
152        for (i = 0; ni = (NeuroImpl*)nlist(i); i++)
153                ni->goPhysics();
154}
155
156void NeuroNetImpl::getLiveNeuroObject(Neuro *n, ExtValue *ret)
157{
158        NeuroImpl *ni = getImpl(n);
159        if (ni)
160                ret->setObject(ExtObject(&NeuroImpl::getStaticParam(), ni));
161        else
162                ret->setEmpty();
163}
164
165///////////////////////////////////////////////
166
167void NeuroImpl::setChannelCount(int c)
168{
169        if (c < 1) c = 1;
170        if (c == channels) return;
171        if (c < channels) { channels = c; chstate.trim(c - 1); chnewstate.trim(c - 1); return; }
172        double s = getState(channels - 1);
173        chnewstate.setSize(c - 1);
174        chstate.setSize(c - 1);
175        for (int i = channels; i < c; i++)
176        {
177                chstate(i - 1) = s;
178                chnewstate(i - 1) = s;
179        }
180        channels = c;
181}
182
183void NeuroImpl::setState(double st, int channel)
184{
185        validateNeuroState(st);
186        if (channel >= channels) channel = channels - 1;
187        if (channel <= 0) { newstate = st; return; }
188        chnewstate(channel - 1) = st;
189}
190
191void NeuroImpl::setCurrentState(double st, int channel)
192{
193        validateNeuroState(st);
194        if (channel >= channels) channel = channels - 1;
195        if (channel <= 0) { neuro->state = st; return; }
196        chstate(channel - 1) = st;
197}
198
199double NeuroImpl::getNewState(int channel)
200{
201        if (neuro->flags & Neuro::HoldState) return getState(channel);
202        if (channel >= channels) channel = channels - 1;
203        if (channel <= 0) { return newstate; }
204        return chnewstate(channel - 1);
205}
206
207double NeuroImpl::getState(int channel)
208{
209        if (channel >= channels) channel = channels - 1;
210        if (channel <= 0) return neuro->state;
211        return chstate(channel - 1);
212}
213
214void NeuroImpl::commit()
215{
216        if (!(neuro->flags & Neuro::HoldState))
217        {
218                if (channels > 1)
219                        chstate = chnewstate;
220                neuro->state = newstate;
221                if (owner->getConfig().nnoise > 0.0)
222                {
223                        neuro->state += RndGen.GaussStd() * owner->getConfig().nnoise;
224                        if (channels > 1)
225                                for (int i = 0; i < chstate.size(); i++)
226                                        chstate(0) += RndGen.GaussStd() * owner->getConfig().nnoise;
227                }
228        }
229}
230
231int NeuroImpl::getInputChannelCount(int i)
232{
233        if ((i < 0) || (i >= neuro->getInputCount())) return 1;
234        Neuro *nu = neuro->getInput(i);
235        NeuroImpl *ni = NeuroNetImpl::getImpl(nu);
236        if (!ni) return 1;
237        return ni->channels;
238}
239
240double NeuroImpl::getInputState(int i, int channel)
241{
242        if ((i < 0) || (i >= neuro->getInputCount())) return 0;
243        Neuro *nu = neuro->getInput(i);
244        if (channel <= 0) return nu->state;
245        NeuroImpl *ni = NeuroNetImpl::getImpl(nu);
246        if (!ni) return nu->state;
247        if (channel >= ni->channels) channel = ni->channels - 1;
248        if (!channel) return nu->state;
249        return ni->chstate(channel - 1);
250}
251
252double NeuroImpl::getWeightedInputState(int i, int channel)
253{
254        if ((i < 0) || (i >= neuro->getInputCount())) return 0;
255        double w;
256        Neuro *nu = neuro->getInput(i, w);
257        if (channel <= 0) return nu->state * w;
258        NeuroImpl *ni = NeuroNetImpl::getImpl(nu);
259        if (!ni) return nu->state * w;
260        if (channel >= ni->channels) channel = ni->channels - 1;
261        if (!channel) return w * nu->state;
262        return w * ni->chstate(channel - 1);
263}
264
265double NeuroImpl::getInputSum(int startwith)
266{
267        if (startwith < 0) return 0;
268        Neuro *inp;
269        double sum = 0.0;
270        while (inp = neuro->getInput(startwith++))
271                sum += inp->state;
272        return sum;
273}
274
275double NeuroImpl::getWeightedInputSum(int startwith)
276{
277        if (startwith < 0) return 0;
278        Neuro *inp;
279        double sum = 0.0;
280        double w;
281        while (inp = neuro->getInput(startwith++, w))
282                sum += inp->state * w;
283        return sum;
284}
285
286void NeuroImpl::readParam()
287{
288        Param par;
289        if (!paramentries) return;
290        par.setParamTab(paramentries);
291        par.select(this);
292        par.setDefault();
293        par.load(ParamInterface::FormatSingleLine, neuro->getClassParams());
294}
295
296Param& NeuroImpl::getStaticParam()
297{
298        static Param p(neuroimpl_tab, 0, "Neuro");
299        return p;
300}
301
302/////////////////////////////
303
304#ifdef NEURO_SIGNALS
305#define NEUROIMPL_SIGNAL_PROPS 1
306#else
307#define NEUROIMPL_SIGNAL_PROPS 0
308#endif
309
310#define FIELDSTRUCT NeuroImpl
311ParamEntry neuroimpl_tab[] =
312{
313        { "Neuro", 1, 29 + NEUROIMPL_SIGNAL_PROPS, "Neuro", "Live Neuron object." },
314
315        { "getInputState", 0, 0, "Get input signal", "p f(d input)", PROCEDURE(p_get), },
316        { "getInputWeight", 0, 0, "Get input weight", "p f(d input)", PROCEDURE(p_getweight), },
317        { "getWeightedInputState", 0, 0, "Get weighted input signal", "p f(d input)", PROCEDURE(p_getw), },
318        { "getInputSum", 0, 0, "Get signal sum", "p f(d input)", PROCEDURE(p_getsum), },
319        { "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" },
320        { "getInputCount", 0, PARAM_READONLY, "Get input count", "d", GETONLY(count), },
321        { "inputSum", 0, PARAM_READONLY, "Full signal sum", "f", GETONLY(sum), },
322        { "weightedInputSum", 0, PARAM_READONLY, "Full weighted signal sum", "f", GETONLY(wsum), },
323        { "getInputChannelCount", 0, 0, "Get channel count for input", "p d(d input)", PROCEDURE(p_getchancount), },
324        { "getInputStateChannel", 0, 0, "Get input signal from channel", "p f(d input,d channel)", PROCEDURE(p_getchan), },
325        { "getWeightedInputStateChannel", 0, 0, "Get weighted input signal from channel", "p f(d input,d channel)", PROCEDURE(p_getwchan), },
326        { "state", 0, 0, "Neuron state (channel 0)", "f", GETSET(state), "When read, returns the current neuron state.\nWhen written, sets the 'internal' neuron state that will become current in the next step.\nTypically you should use this field, and not currState." },
327        { "channelCount", 0, 0, "Number of output channels", "d", GETSET(channels), },
328        { "getStateChannel", 0, 0, "Get state for channel", "p f(d channel)", PROCEDURE(p_getstate), },
329        { "setStateChannel", 0, 0, "Set state for channel", "p(d channel,f value)", PROCEDURE(p_setstate), },
330        { "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.", },
331        { "currState", 0, 0, "Current neuron state (channel 0)", "f", GETSET(cstate), "When read, it behaves just like the 'state' field.\nWhen written, changes the current neuron state immediately, which disturbs the regular synchronous NN operation.\nThis 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", },
332        { "setCurrStateChannel", 0, 0, "Set current neuron state for channel", "p(d channel,f value)", PROCEDURE(p_setcstate), "Analogous to \"currState\"." },
333        { "position_x", 0, PARAM_READONLY, "Position x", "f", GETONLY(position_x), },
334        { "position_y", 0, PARAM_READONLY, "Position y", "f", GETONLY(position_y), },
335        { "position_z", 0, PARAM_READONLY, "Position z", "f", GETONLY(position_z), },
336        { "relative_pos", 0, PARAM_READONLY, "Relative position", "oXYZ", GETONLY(relative_pos), },
337        { "relative_orient", 0, PARAM_READONLY, "Relative orientation", "oOrient", GETONLY(relative_orient), },
338        { "creature", 0, PARAM_READONLY, "Gets owner creature", "oCreature", GETONLY(creature), },
339        { "mechpart", 0, PARAM_READONLY, "MechPart object", "oMechPart", GETONLY(part), "The MechPart object where this neuron is located" },
340        { "mechjoint", 0, PARAM_READONLY, "MechJoint object" , "oMechJoint", GETONLY(joint), "The MechJoint object where this neuron is located" },
341        { "neuroproperties", 0, PARAM_READONLY, "Custom neuron fields", "oNeuroProperties", GETONLY(fields),
342        "Neurons can have different fields depending on their class. Script neurons have their fields defined using the \"property:\" syntax. If you develop a custom neuron script you should use the NeuroProperties object for accessing your own neuron fields. The Neuro.neuroproperties property is meant for accessing the neuron fields from the outside script.\n"
343        "Examples:\n"
344        "var c=Populations.createFromString(\"X[N]\");\n"
345        "Simulator.print(\"standard neuron inertia=\"+c.getNeuro(0).neuroproperties.in);\n"
346        "c=Populations.createFromString(\"X[Nn,e:0.1]\");\n"
347        "Simulator.print(\"noisy neuron error rate=\"+c.getNeuro(0).neuroproperties.e);\n"
348        "\n"
349        "The Interface object can be used to discover which fields are available for a certain neuron object:\n"
350        "c=Populations.createFromString(\"X[N]\");\n"
351        "var iobj=Interface.makeFrom(c.getNeuro(0).neuroproperties);\n"
352        "var i;\n"
353        "for(i=0;i<iobj.size;i++)\n"
354        " Simulator.print(iobj.getId(i)+\" (\"+iobj.getName(i)+\")\");", },
355        { "def", 0, PARAM_READONLY, "Neuron definition from which this live neuron was built", "oNeuroDef", GETONLY(neurodef), },
356        { "classObject", 0, PARAM_READONLY, "Neuron class for this neuron", "oNeuroClass", GETONLY(classObject), },
357#ifdef NEURO_SIGNALS
358        { "signals", 0, PARAM_READONLY, "Signals", "oNeuroSignals", FIELD(sigs_obj), },
359#endif
360
361        { 0, 0, 0, },
362};
363#undef FIELDSTRUCT
364
365#ifdef NEURO_SIGNALS
366ParamEntry neurosignals_paramtab[] =
367{
368        { "NeuroSignals", 1, 8, "NeuroSignals", "Signals attached to a 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.", },
369
370#define FIELDSTRUCT NeuroSignals
371        SIGNPAR_ADD(""),
372        SIGNPAR_RECEIVE(""),
373        SIGNPAR_RECEIVESET(""),
374        SIGNPAR_RECEIVEFILTER(""),
375        SIGNPAR_RECEIVESINGLE(""),
376#undef FIELDSTRUCT
377
378#define FIELDSTRUCT SignalSet
379        SIGNSETPAR_GET,
380        SIGNSETPAR_SIZE,
381        SIGNSETPAR_CLEAR,
382#undef FIELDSTRUCT
383        { 0, 0, 0, },
384};
385
386Param& NeuroSignals::getStaticParam()
387{
388        static Param p(neurosignals_paramtab, 0);
389        return p;
390}
391#endif
392
393#ifdef NEURO_SIGNALS
394class NeuroSigSource : public SigSource
395{
396protected:
397        NeuroImpl* owner;
398public:
399        NeuroSigSource(NeuroImpl *n, Creature *c) :SigSource(0, c), owner(n) {}
400        bool update();
401};
402
403bool NeuroSigSource::update()
404{
405        Pt3D p;
406        if (owner->getPosition(p))
407        {
408                setLocation(p);
409                return true;
410        }
411        return false;
412}
413
414Creature *NeuroSignals::getCreature()
415{
416        if (!cr)
417        {
418                cr = owner->getCreature();
419        }
420        return cr;
421}
422
423void NeuroSignals::p_add(PARAMPROCARGS)
424{
425        SigSource *s = new NeuroSigSource(owner, getCreature());
426        if (owner->owner->channels)
427        {
428                SigChannel *ch = owner->owner->channels->getChannel(args->getString(), true);
429                ch->addSource(s);
430        }
431        else
432                SigChannel::dummy_channel.addSource(s);
433        sigs += s;
434        s->setupObject(ret);
435}
436
437void NeuroSignals::p_receive(PARAMPROCARGS)
438{
439        SigChannel *ch; Pt3D p;
440        if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args->getString(), false)) && owner->getPosition(p))
441                ret->setDouble(ch->receive(&p, getCreature()));
442        else
443                ret->setDouble(0);
444}
445
446void NeuroSignals::p_receiveFilter(PARAMPROCARGS)
447{
448        SigChannel *ch; Pt3D p;
449        if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args[3].getString(), false)) && owner->getPosition(p))
450                ret->setDouble(ch->receive(&p, getCreature(), args[2].getDouble(), args[1].getDouble(), args[0].getDouble()));
451        else
452                ret->setDouble(0);
453}
454
455void NeuroSignals::p_receiveSet(PARAMPROCARGS)
456{
457        SigChannel *ch; Pt3D p;
458        SigVector *vec = new SigVector();
459        if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args[1].getString(), false)) && owner->getPosition(p))
460                ch->receiveSet(vec, &p, getCreature(), args[0].getDouble());
461        ret->setObject(vec->makeObject());
462}
463
464void NeuroSignals::p_receiveSingle(PARAMPROCARGS)
465{
466        SigChannel *ch; Pt3D p;
467        if (owner->owner->channels && (ch = owner->owner->channels->getChannel(args[1].getString(), false)) && owner->getPosition(p))
468        {
469                SigSource *src = ch->receiveSingle(&p, getCreature(), args[0].getDouble(), 0, 1e99);
470                if (src)
471                {
472                        src->setupObject(ret);
473                        return;
474                }
475        }
476        ret->setEmpty();
477}
478#endif
479
480#ifndef SDK_WITHOUT_FRAMS
481extern ParamEntry creature_paramtab[];
482static Param creature_param(creature_paramtab, 0);
483#endif
484
485Creature* NeuroImpl::getCreature()
486{
487#ifndef SDK_WITHOUT_FRAMS
488        CreatMechObject *cmo = (CreatMechObject *)neuro->owner->userdata[CreatMechObject::modeltags_id];
489        return cmo->creature;
490#else
491        return 0;
492#endif
493}
494
495void NeuroImpl::get_creature(ExtValue *ret)
496{
497#ifndef SDK_WITHOUT_FRAMS
498        ret->setObject(ExtObject(&creature_param, getCreature()));
499#endif
500}
501
502void NeuroImpl::get_part(ExtValue *ret)
503{
504#ifndef SDK_WITHOUT_FRAMS
505        Part *pa;
506        if (pa = neuro->getPart())
507                ret->setObject(ExtObject(&MechPart::getStaticParam(), ((MechPart *)pa->userdata[CreatMechObject::modeltags_id])));
508        else
509                ret->setEmpty();
510#endif
511}
512
513void NeuroImpl::get_joint(ExtValue *ret)
514{
515#ifndef SDK_WITHOUT_FRAMS
516        Joint *jo;
517        if (jo = neuro->getJoint())
518                ret->setObject(ExtObject(&MechJoint::getStaticParam(), ((MechJoint*)jo->userdata[CreatMechObject::modeltags_id])));
519        else
520                ret->setEmpty();
521#endif
522}
523
524bool NeuroImpl::getPosition(Pt3D &pos)
525{
526#ifndef SDK_WITHOUT_FRAMS
527        Part *pa; Joint *jo;
528        if (pa = neuro->getPart())
529        {
530                pos = ((MechPart *)pa->userdata[CreatMechObject::modeltags_id])->p;
531                return true;
532        }
533        if (jo = neuro->getJoint())
534        {
535                if (neuro->getClass()->getVisualHints() & NeuroClass::AtFirstPart)
536                        pos = ((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p;
537                else if (neuro->getClass()->getVisualHints() & NeuroClass::AtSecondPart)
538                        pos = ((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p;
539                else pos = (((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p
540                        + ((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p) / 2;
541                return true;
542        }
543#endif
544        return false;
545}
546
547void NeuroImpl::get_position_x(ExtValue *ret)
548{
549        Pt3D pos;
550        if (getPosition(pos)) ret->setDouble(pos.x); else ret->setEmpty();
551}
552void NeuroImpl::get_position_y(ExtValue *ret)
553{
554        Pt3D pos;
555        if (getPosition(pos)) ret->setDouble(pos.y); else ret->setEmpty();
556}
557void NeuroImpl::get_position_z(ExtValue *ret)
558{
559        Pt3D pos;
560        if (getPosition(pos)) ret->setDouble(pos.z); else ret->setEmpty();
561}
562
563void NeuroImpl::get_relative_pos(ExtValue *ret)
564{
565        ret->setObject(Pt3D_Ext::makeDynamicObject(getRelativePosition()));
566}
567
568void NeuroImpl::get_relative_orient(ExtValue *ret)
569{
570        ret->setObject(Orient_Ext::makeDynamicObject(new Orient_Ext(getRelativeOrientation())));
571}
572
573void NeuroImpl::createFieldsObject()
574{
575        fields_param = new Param(paramentries ? paramentries : (ParamEntry*)&empty_paramtab, this, "NeuroProperties");
576        fields_object = new ExtObject(fields_param);
577}
578
579void NeuroImpl::get_fields(ExtValue *ret)
580{
581        if (!fields_object)
582                createFieldsObject();
583        ret->setObject(*fields_object);
584}
585
586void NeuroImpl::get_neurodef(ExtValue *ret)
587{
588        ret->setObject(ExtObject(&Neuro::getStaticParam(), neuro));
589}
590
591void NeuroImpl::get_classObject(ExtValue *ret)
592{
593#ifndef SDK_WITHOUT_FRAMS
594        NeuroClassExt::makeStaticObject(ret, neuroclass);
595#endif
596}
597
598NeuroImpl::~NeuroImpl()
599{
600        if (fields_param)
601        {
602                delete fields_param;
603                delete fields_object;
604        }
605}
Note: See TracBrowser for help on using the repository browser.