diff --git a/creature-monitor/main.cpp b/creature-monitor/main.cpp index ff9f45f3..5f5c049d 100644 --- a/creature-monitor/main.cpp +++ b/creature-monitor/main.cpp @@ -50,11 +50,20 @@ void writeText(int x, int y, const char * text, size_t len) { } } -void fillRect(const SDL_Rect rect, uint32_t colour) { +static void setDrawColour(uint32_t colour) { SDL_SetRenderDrawColor(gRenderer, (colour >> 16) & 0xFF, (colour >> 8) & 0xFF, colour & 0xFF, (colour >> 24) & 0xFF); +} + +void fillRect(const SDL_Rect rect, uint32_t colour) { + setDrawColour(colour); SDL_RenderFillRect(gRenderer, &rect); } +void drawLine(const SDL_Point a, const SDL_Point b, uint32_t colour) { + setDrawColour(colour); + SDL_RenderDrawLine(gRenderer, a.x, a.y, b.x, b.y); +} + void setState(CMState * state) { if (gCurrentState != NULL) gCurrentState->queueDelete(); diff --git a/creature-monitor/main.h b/creature-monitor/main.h index 6b34ec4f..2b0a4f42 100644 --- a/creature-monitor/main.h +++ b/creature-monitor/main.h @@ -22,6 +22,11 @@ void writeText(int x, int y, const char * text); void writeText(int x, int y, const CMSlice & text); void writeText(int x, int y, const char * text, size_t len); void fillRect(const SDL_Rect rect, uint32_t colour); +void drawLine(const SDL_Point a, const SDL_Point b, uint32_t colour); + +inline static SDL_Point rectCentre(const SDL_Rect a) { + return {a.x + (a.w / 2), a.y + (a.h / 2)}; +} inline static SDL_Rect marginRect(const SDL_Rect basis, int amount) { int a2 = amount * 2; diff --git a/creature-monitor/state_brain.cpp b/creature-monitor/state_brain.cpp index 103e5400..47ec7e53 100644 --- a/creature-monitor/state_brain.cpp +++ b/creature-monitor/state_brain.cpp @@ -23,12 +23,19 @@ typedef struct { typedef struct { float input; - int b; + int id; // always equal to neuron index float values[8]; } neuron_t; typedef struct { - int a; + int id; + int srcNeuron; + int dstNeuron; + float values[8]; +} dendrite_t; + +typedef struct { + int id; int decisionIndex; char name[4]; int d; @@ -37,21 +44,66 @@ typedef struct { ruleset_t init; ruleset_t update; // neurons follow - // then another random thing + neuron_t neurons[]; + // then lobefoot_t } lobehdr_t; +typedef struct { + int a; + int b; + int srcLobe; + int srcMin; + int srcUnk; + char srcUnk2; + int dstLobe; + int dstMin; + int dstUnk; + char dstUnk2; + bool flagA; + bool flagB; + ruleset_t init; + ruleset_t update; + int dendriteCount; + // dendrites follow + // then lobefoot_t +} tracthdr_t; + typedef struct { char footer[10]; } lobefoot_t; #pragma pack(pop) #define BRN_GRIDW 16 -#define BRN_GRIDH 16 +#define BRN_GRIDH 12 static SDL_Rect getCellRegion(int ofsX, int ofsY, int x, int y, int w, int h) { return {ofsX + (x * BRN_GRIDW), ofsY + (y * BRN_GRIDH), w * BRN_GRIDW, h * BRN_GRIDH}; } +static SDL_Rect getCellRegion(int ofsX, int ofsY, lobehdr_t * lobe, int i) { + return getCellRegion(ofsX, ofsY, lobe->x + (i % lobe->w), lobe->y + (i / lobe->w), 1, 1); +} + +static int decideColour(float f) { + float datums[] = { + f * -16, + fabs(f), + f * 16, + }; + int col = 0; + for (int k = 0; k < 3; k++) { + int subCol = (int) (datums[k] * 255); + if (subCol < 0) + subCol = 0; + if (subCol > 255) + subCol = 255; + col <<= 8; + col |= subCol; + } + col |= 0xFF000000; + return col; +} + class CMBrainState : public CMState { public: CPXRequestResult * result = NULL; @@ -59,6 +111,7 @@ class CMBrainState : public CMState { CMBuffer moniker; char * stateNameDetail; int lobes, tracts; + bool dendritesView = false; CMBrainState(const CMSlice & moniker, int l, int t) : moniker(moniker), lobes(l), tracts(t) { stateNameDetail = (CMSlice("brain:") + moniker + CMSlice(" L") + cmItoB(l) + CMSlice(" T") + cmItoB(t)).dupCStr(); @@ -78,8 +131,11 @@ class CMBrainState : public CMState { // cmDumpSliceToFile(cursor, "lobedump.bin"); int ofsX = 32; int ofsY = 32; + lobehdr_t * lobeHeaders[lobes]; for (int i = 0; i < lobes; i++) { lobehdr_t * lobehdr = (lobehdr_t *) cursor.grab(sizeof(lobehdr_t)); + // store for later access + lobeHeaders[i] = lobehdr; // printf("%c%c%c%c %i %i %i %i\n", lobehdr->name[0], lobehdr->name[1], lobehdr->name[2], lobehdr->name[3], lobehdr->x, lobehdr->y, lobehdr->w, lobehdr->h); int neuronCount = lobehdr->w * lobehdr->h; @@ -99,30 +155,49 @@ class CMBrainState : public CMState { // printf(" end at %i\n", (int) (cursor.data - result->content.data)); for (int j = 0; j < neuronCount; j++) { - int nX = j % lobehdr->w; - int nY = j / lobehdr->w; - SDL_Rect nbox = getCellRegion(ofsX, ofsY, lobehdr->x + nX, lobehdr->y + nY, 1, 1); + SDL_Rect nbox = getCellRegion(ofsX, ofsY, lobehdr, j); SDL_Rect nboxInner = marginRect(nbox, 4); - int col = 0; - float datums[] = { - neurons[j].values[0] * -16, - fabs(neurons[j].values[0]), - neurons[j].values[0] * 16, - }; - for (int k = 0; k < 3; k++) { - int subCol = (int) (datums[k] * 255); - if (subCol < 0) - subCol = 0; - if (subCol > 255) - subCol = 255; - col <<= 8; - col |= subCol; - } - col |= 0xFF000000; if (lobehdr->decisionIndex == j) fillRect(nbox, 0xFF808080); - fillRect(nboxInner, col); + fillRect(nboxInner, decideColour(neurons[j].values[0])); + } + } + + for (int i = 0; i < tracts; i++) { + tracthdr_t * tracthdr = (tracthdr_t *) cursor.grab(sizeof(tracthdr_t)); + + dendrite_t * dendrites = (dendrite_t *) cursor.grab(tracthdr->dendriteCount * sizeof(dendrite_t)); + + // need to find lobe + lobehdr_t * srcLobeHdr = NULL; + lobehdr_t * dstLobeHdr = NULL; + for (int j = 0; j < lobes; j++) { + if (lobeHeaders[j]->id == tracthdr->srcLobe) + srcLobeHdr = lobeHeaders[j]; + if (lobeHeaders[j]->id == tracthdr->dstLobe) + dstLobeHdr = lobeHeaders[j]; + } + + if (srcLobeHdr && dstLobeHdr) { + int srcLobeHdrNC = srcLobeHdr->w * srcLobeHdr->h; + int dstLobeHdrNC = dstLobeHdr->w * dstLobeHdr->h; + // have both lobes! + for (int j = 0; j < tracthdr->dendriteCount; j++) { + int sni = dendrites[j].srcNeuron; + if (sni < 0 || sni >= srcLobeHdrNC) { + continue; + } + if (dendritesView) { + SDL_Rect srcNeuron = getCellRegion(ofsX, ofsY, srcLobeHdr, sni); + SDL_Rect dstNeuron = getCellRegion(ofsX, ofsY, dstLobeHdr, dendrites[j].dstNeuron); + float f = dendrites[j].values[0] * srcLobeHdr->neurons[sni].values[0]; + drawLine(rectCentre(srcNeuron), rectCentre(dstNeuron), decideColour(f)); + } + } } + + // footer + cursor.grab(sizeof(lobefoot_t)); } } else { writeText(0, 0, result->content.data, result->content.length); @@ -154,6 +229,8 @@ class CMBrainState : public CMState { if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_BACKSPACE) { setSelectorState(); + } else if (event.key.keysym.sym == SDLK_d) { + dendritesView = !dendritesView; } else if (event.key.keysym.sym == SDLK_RETURN) { setChemState(moniker); }