static QByteArray createRandomBytes(int minimumSize, int maximumSize) { QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0); for (int i = 0; i < bytes.size(); i++) { bytes[i] = rand(); } return bytes; }
void doBuildStreet() { if (roadInitialized) { return; } PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully! static VoxelDetail details[BRICKS_PER_PACKET]; for (int z = 0; z < ROAD_LENGTH; z++) { for (int x = 0; x < ROAD_WIDTH; x++) { int nthVoxel = ((z * ROAD_WIDTH) + x); int item = nthVoxel % BRICKS_PER_PACKET; glm::vec3 brick = roadPosition + glm::vec3(x * ROAD_BRICK_SIZE, 0, z * ROAD_BRICK_SIZE); details[item].s = ROAD_BRICK_SIZE; details[item].x = brick.x; details[item].y = brick.y; details[item].z = brick.z; unsigned char randomTone = randIntInRange(118,138); details[item].red = randomTone; details[item].green = randomTone; details[item].blue = randomTone; if (item == BRICKS_PER_PACKET - 1) { ::voxelEditPacketSender->queueVoxelEditMessages(message, BRICKS_PER_PACKET, (VoxelDetail*)&details); } } } roadInitialized = true; }
void Endpoint::sendDatagram(const QByteArray& datagram) { datagramsSent++; // some datagrams are dropped const float DROP_PROBABILITY = 0.1f; if (randFloat() < DROP_PROBABILITY) { return; } // some are received out of order const float REORDER_PROBABILITY = 0.1f; if (randFloat() < REORDER_PROBABILITY) { const int MIN_DELAY = 1; const int MAX_DELAY = 5; // have to copy the datagram; the one we're passed is a reference to a shared buffer _delayedDatagrams.append(QPair<QByteArray, int>(QByteArray(datagram.constData(), datagram.size()), randIntInRange(MIN_DELAY, MAX_DELAY))); // and some are duplicated const float DUPLICATE_PROBABILITY = 0.01f; if (randFloat() > DUPLICATE_PROBABILITY) { return; } } _other->_sequencer->receivedDatagram(datagram); datagramsReceived++; }
static TestSharedObjectA::TestEnum getRandomTestEnum() { switch (randIntInRange(0, 2)) { case 0: return TestSharedObjectA::FIRST_TEST_ENUM; case 1: return TestSharedObjectA::SECOND_TEST_ENUM; case 2: default: return TestSharedObjectA::THIRD_TEST_ENUM; } }
static SharedObjectPointer createRandomSharedObject() { switch (randIntInRange(0, 2)) { case 0: return new TestSharedObjectA(randFloat(), getRandomTestEnum(), getRandomTestFlags()); case 1: return new TestSharedObjectB(); case 2: default: return SharedObjectPointer(); } }
static QVariant createRandomMessage() { switch (randIntInRange(0, 2)) { case 0: { TestMessageA message = { randomBoolean(), rand(), randFloat() }; return QVariant::fromValue(message); } case 1: { TestMessageB message = { createRandomBytes(), createRandomSharedObject(), getRandomTestEnum() }; return QVariant::fromValue(message); } default: { return QVariant::fromValue(createRandomMessageC()); } } }
static QVariant createRandomMessage() { switch (randIntInRange(0, 2)) { case 0: { TestMessageA message = { randomBoolean(), rand(), randFloat() }; return QVariant::fromValue(message); } case 1: { TestMessageB message = { createRandomBytes() }; return QVariant::fromValue(message); } case 2: default: { TestMessageC message; message.foo = randomBoolean(); message.bar = rand(); message.baz = randFloat(); message.bong.foo = createRandomBytes(); return QVariant::fromValue(message); } } }
static SharedObjectPointer mutate(const SharedObjectPointer& state) { switch(randIntInRange(0, 3)) { case 0: { SharedObjectPointer newState = state->clone(true); static_cast<TestSharedObjectA*>(newState.data())->setFoo(randFloat()); objectMutationsPerformed++; return newState; } case 1: { SharedObjectPointer newState = state->clone(true); static_cast<TestSharedObjectA*>(newState.data())->setBaz(getRandomTestEnum()); objectMutationsPerformed++; return newState; } case 2: { SharedObjectPointer newState = state->clone(true); static_cast<TestSharedObjectA*>(newState.data())->setBong(getRandomTestFlags()); objectMutationsPerformed++; return newState; } default: return state; } }
void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float voxelSize, bool solid, creationMode mode, bool destructive, bool debug) { bool wantColorRandomizer = (mode == RANDOM); bool wantNaturalSurface = (mode == NATURAL); bool wantNaturalColor = (mode == NATURAL); // About the color of the sphere... we're going to make this sphere be a mixture of two colors // in NATURAL mode, those colors will be green dominant and blue dominant. In GRADIENT mode we // will randomly pick which color family red, green, or blue to be dominant. In RANDOM mode we // ignore these dominant colors and make every voxel a completely random color. unsigned char r1, g1, b1, r2, g2, b2; if (wantNaturalColor) { r1 = r2 = b2 = g1 = 0; b1 = g2 = 255; } else if (!wantColorRandomizer) { unsigned char dominantColor1 = randIntInRange(1, 3); //1=r, 2=g, 3=b dominant unsigned char dominantColor2 = randIntInRange(1, 3); if (dominantColor1 == dominantColor2) { dominantColor2 = dominantColor1 + 1 % 3; } r1 = (dominantColor1 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); g1 = (dominantColor1 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); b1 = (dominantColor1 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); r2 = (dominantColor2 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); g2 = (dominantColor2 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); b2 = (dominantColor2 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); } // We initialize our rgb to be either "grey" in case of randomized surface, or // the average of the gradient, in the case of the gradient sphere. unsigned char red = wantColorRandomizer ? 128 : (r1 + r2) / 2; // average of the colors unsigned char green = wantColorRandomizer ? 128 : (g1 + g2) / 2; unsigned char blue = wantColorRandomizer ? 128 : (b1 + b2) / 2; // I want to do something smart like make these inside circles with bigger voxels, but this doesn't seem to work. float thisVoxelSize = voxelSize; // radius / 2.0f; float thisRadius = 0.0; if (!solid) { thisRadius = radius; // just the outer surface thisVoxelSize = voxelSize; } // If you also iterate form the interior of the sphere to the radius, making // larger and larger spheres you'd end up with a solid sphere. And lots of voxels! bool lastLayer = false; while (!lastLayer) { lastLayer = (thisRadius + (voxelSize * 2.0) >= radius); // We want to make sure that as we "sweep" through our angles we use a delta angle that voxelSize // small enough to not skip any voxels we can calculate theta from our desired arc length // lenArc = ndeg/360deg * 2pi*R ---> lenArc = theta/2pi * 2pi*R // lenArc = theta*R ---> theta = lenArc/R ---> theta = g/r float angleDelta = (thisVoxelSize / thisRadius); if (debug) { int percentComplete = 100 * (thisRadius/radius); qDebug("percentComplete=%d\n",percentComplete); } for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) { for (float phi=0.0; phi <= M_PI; phi += angleDelta) { bool naturalSurfaceRendered = false; float x = xc + thisRadius * cos(theta) * sin(phi); float y = yc + thisRadius * sin(theta) * sin(phi); float z = zc + thisRadius * cos(phi); // if we're on the outer radius, then we do a couple of things differently. // 1) If we're in NATURAL mode we will actually draw voxels from our surface outward (from the surface) up // some random height. This will give our sphere some contours. // 2) In all modes, we will use our "outer" color to draw the voxels. Otherwise we will use the average color if (lastLayer) { if (false && debug) { qDebug("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n", theta, phi, thisRadius,radius); } switch (mode) { case RANDOM: { red = randomColorValue(165); green = randomColorValue(165); blue = randomColorValue(165); } break; case GRADIENT: { float gradient = (phi / M_PI); red = r1 + ((r2 - r1) * gradient); green = g1 + ((g2 - g1) * gradient); blue = b1 + ((b2 - b1) * gradient); } break; case NATURAL: { glm::vec3 position = glm::vec3(theta,phi,radius); float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + .125f * glm::perlin(position * 16.f); float gradient = (1.0f + perlin)/ 2.0f; red = (unsigned char)std::min(255, std::max(0, (int)(r1 + ((r2 - r1) * gradient)))); green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient)))); blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient)))); if (debug) { qDebug("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue); } } break; } if (wantNaturalSurface) { // for natural surfaces, we will render up to 16 voxel's above the surface of the sphere glm::vec3 position = glm::vec3(theta,phi,radius); float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + .125f * glm::perlin(position * 16.f); float gradient = (1.0f + perlin)/ 2.0f; int height = (4 * gradient)+1; // make it at least 4 thick, so we get some averaging float subVoxelScale = thisVoxelSize; for (int i = 0; i < height; i++) { x = xc + (thisRadius + i * subVoxelScale) * cos(theta) * sin(phi); y = yc + (thisRadius + i * subVoxelScale) * sin(theta) * sin(phi); z = zc + (thisRadius + i * subVoxelScale) * cos(phi); this->createVoxel(x, y, z, subVoxelScale, red, green, blue, destructive); } naturalSurfaceRendered = true; } } if (!naturalSurfaceRendered) { this->createVoxel(x, y, z, thisVoxelSize, red, green, blue, destructive); } } } thisRadius += thisVoxelSize; thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f); } }
int main(int argc, const char * argv[]) { pthread_mutex_init(&::treeLock, NULL); qInstallMessageHandler(sharedMessageHandler); NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT); setvbuf(stdout, NULL, _IOLBF, 0); // Handle Local Domain testing with the --local command line const char* local = "--local"; ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode; nodeList->startSilentNodeRemovalThread(); srand((unsigned)time(0)); const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats"; ::displayVoxelStats = cmdOptionExists(argc, argv, DISPLAY_VOXEL_STATS); printf("displayVoxelStats=%s\n", debug::valueOf(::displayVoxelStats)); const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; ::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING); printf("debugVoxelSending=%s\n", debug::valueOf(::debugVoxelSending)); const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving"; ::debugVoxelReceiving = cmdOptionExists(argc, argv, DEBUG_VOXEL_RECEIVING); printf("debugVoxelReceiving=%s\n", debug::valueOf(::debugVoxelReceiving)); const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug"; ::shouldShowAnimationDebug = cmdOptionExists(argc, argv, WANT_ANIMATION_DEBUG); printf("shouldShowAnimationDebug=%s\n", debug::valueOf(::shouldShowAnimationDebug)); const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer"; ::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER); printf("wantColorRandomizer=%s\n", debug::valueOf(::wantColorRandomizer)); // By default we will voxel persist, if you want to disable this, then pass in this parameter const char* NO_VOXEL_PERSIST = "--NoVoxelPersist"; if (cmdOptionExists(argc, argv, NO_VOXEL_PERSIST)) { ::wantVoxelPersist = false; } printf("wantVoxelPersist=%s\n", debug::valueOf(::wantVoxelPersist)); // if we want Voxel Persistance, load the local file now... bool persistantFileRead = false; if (::wantVoxelPersist) { printf("loading voxels from file...\n"); persistantFileRead = ::serverTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); if (persistantFileRead) { PerformanceWarning warn(::shouldShowAnimationDebug, "persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug); // after done inserting all these voxels, then reaverage colors serverTree.reaverageVoxelColors(serverTree.rootNode); printf("Voxels reAveraged\n"); } ::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); unsigned long nodeCount = ::serverTree.rootNode->getSubTreeNodeCount(); unsigned long internalNodeCount = ::serverTree.rootNode->getSubTreeInternalNodeCount(); unsigned long leafNodeCount = ::serverTree.rootNode->getSubTreeLeafNodeCount(); printf("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); } // Check to see if the user passed in a command line option for loading an old style local // Voxel File. If so, load it now. This is not the same as a voxel persist file const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); if (voxelsFilename) { serverTree.readFromSVOFile(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate const char* PACKETS_PER_SECOND = "--packetsPerSecond"; const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND); if (packetsPerSecond) { PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10; if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) { PACKETS_PER_CLIENT_PER_INTERVAL = 1; } printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL); } const char* ADD_RANDOM_VOXELS = "--AddRandomVoxels"; if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) { // create an octal code buffer and load it with 0 so that the recursive tree fill can give // octal codes to the tree nodes that it is creating randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, serverTree.rootNode); } const char* ADD_SCENE = "--AddScene"; bool addScene = cmdOptionExists(argc, argv, ADD_SCENE); const char* NO_ADD_SCENE = "--NoAddScene"; bool noAddScene = cmdOptionExists(argc, argv, NO_ADD_SCENE); if (addScene && noAddScene) { printf("WARNING! --AddScene and --NoAddScene are mutually exclusive. We will honor --NoAddScene\n"); } // We will add a scene if... // 1) we attempted to load a persistant file and it wasn't there // 2) you asked us to add a scene // HOWEVER -- we will NEVER add a scene if you explicitly tell us not to! // // TEMPORARILY DISABLED!!! bool actuallyAddScene = false; // !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead)); if (actuallyAddScene) { addSphereScene(&serverTree); } // for now, initialize the environments with fixed values environmentData[1].setID(1); environmentData[1].setGravity(1.0f); environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE); environmentData[1].setAtmosphereInnerRadius(0.030625f * TREE_SCALE); environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f); environmentData[2].setID(2); environmentData[2].setGravity(1.0f); environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE); environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE); environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f); environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue pthread_t sendVoxelThread; pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL); sockaddr nodePublicAddress; unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t receivedBytes; timeval lastDomainServerCheckIn = {}; // loop to send to nodes requesting data while (true) { // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); NodeList::getInstance()->sendDomainServerCheckIn(); } // check to see if we need to persist our voxel state persistVoxelsWhenDirty(); if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes) && packetVersionMatch(packetData)) { int numBytesPacketHeader = numBytesForPacketHeader(packetData); if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) { bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE); PerformanceWarning warn(::shouldShowAnimationDebug, destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", ::shouldShowAnimationDebug); ::receivedPacketCount++; unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader))); if (::shouldShowAnimationDebug) { printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", receivedBytes,itemNumber); } if (::debugVoxelReceiving) { printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", ::receivedPacketCount, receivedBytes,itemNumber); } int atByte = numBytesPacketHeader + sizeof(itemNumber); unsigned char* voxelData = (unsigned char*)&packetData[atByte]; while (atByte < receivedBytes) { unsigned char octets = (unsigned char)*voxelData; const int COLOR_SIZE_IN_BYTES = 3; int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES; int voxelCodeSize = bytesRequiredForCodeLength(octets); // color randomization on insert int colorRandomizer = ::wantColorRandomizer ? randIntInRange (-50, 50) : 0; int red = voxelData[voxelCodeSize + 0]; int green = voxelData[voxelCodeSize + 1]; int blue = voxelData[voxelCodeSize + 2]; if (::shouldShowAnimationDebug) { printf("insert voxels - wantColorRandomizer=%s old r=%d,g=%d,b=%d \n", (::wantColorRandomizer?"yes":"no"),red,green,blue); } red = std::max(0, std::min(255, red + colorRandomizer)); green = std::max(0, std::min(255, green + colorRandomizer)); blue = std::max(0, std::min(255, blue + colorRandomizer)); if (::shouldShowAnimationDebug) { printf("insert voxels - wantColorRandomizer=%s NEW r=%d,g=%d,b=%d \n", (::wantColorRandomizer?"yes":"no"),red,green,blue); } voxelData[voxelCodeSize + 0] = red; voxelData[voxelCodeSize + 1] = green; voxelData[voxelCodeSize + 2] = blue; if (::shouldShowAnimationDebug) { float* vertices = firstVertexForCode(voxelData); printf("inserting voxel at: %f,%f,%f\n", vertices[0], vertices[1], vertices[2]); delete []vertices; } serverTree.readCodeColorBufferToTree(voxelData, destructive); // skip to next voxelData += voxelDataSize; atByte += voxelDataSize; } } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) { // Send these bits off to the VoxelTree class to process them pthread_mutex_lock(&::treeLock); serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes); pthread_mutex_unlock(&::treeLock); } else if (packetData[0] == PACKET_TYPE_Z_COMMAND) { // the Z command is a special command that allows the sender to send the voxel server high level semantic // requests, like erase all, or add sphere scene char* command = (char*) &packetData[numBytesPacketHeader]; // start of the command int commandLength = strlen(command); // commands are null terminated strings int totalLength = numBytesPacketHeader + commandLength + 1; // 1 for null termination printf("got Z message len(%ld)= %s\n", receivedBytes, command); bool rebroadcast = true; // by default rebroadcast while (totalLength <= receivedBytes) { if (strcmp(command, ERASE_ALL_COMMAND) == 0) { printf("got Z message == erase all\n"); eraseVoxelTreeAndCleanupNodeVisitData(); rebroadcast = false; } if (strcmp(command, ADD_SCENE_COMMAND) == 0) { printf("got Z message == add scene\n"); addSphereScene(&serverTree); rebroadcast = false; } if (strcmp(command, TEST_COMMAND) == 0) { printf("got Z message == a message, nothing to do, just report\n"); } totalLength += commandLength + 1; // 1 for null termination } if (rebroadcast) { // Now send this to the connected nodes so they can also process these messages printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n"); nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1); } } else if (packetData[0] == PACKET_TYPE_HEAD_DATA) { // If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. uint16_t nodeID = 0; unpackNodeId(packetData + numBytesPacketHeader, &nodeID); Node* node = nodeList->addOrUpdateNode(&nodePublicAddress, &nodePublicAddress, NODE_TYPE_AGENT, nodeID); nodeList->updateNodeWithData(node, packetData, receivedBytes); } else if (packetData[0] == PACKET_TYPE_PING) { // If the packet is a ping, let processNodeData handle it. nodeList->processNodeData(&nodePublicAddress, packetData, receivedBytes); } } } pthread_join(sendVoxelThread, NULL); pthread_mutex_destroy(&::treeLock); return 0; }
void sendDanceFloor() { PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully! float lightScale = DANCE_FLOOR_LIGHT_SIZE; static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; // first initialized the billboard of lights if needed... if (!::danceFloorInitialized) { for (int i = 0; i < DANCE_FLOOR_WIDTH; i++) { for (int j = 0; j < DANCE_FLOOR_LENGTH; j++) { int randomColorIndex = randIntInRange(-DANCE_FLOOR_COLORS, DANCE_FLOOR_COLORS); ::danceFloorColors[i][j] = randomColorIndex; ::danceFloorLights[i][j] = ::danceFloorPosition + glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); } } ::danceFloorInitialized = true; } ::danceFloorGradient += ::danceFloorGradientIncrement; if (::danceFloorGradient >= DANCE_FLOOR_MAX_GRADIENT) { ::danceFloorGradient = DANCE_FLOOR_MAX_GRADIENT; ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; } if (::danceFloorGradient <= DANCE_FLOOR_MIN_GRADIENT) { ::danceFloorGradient = DANCE_FLOOR_MIN_GRADIENT; ::danceFloorGradientIncrement = -::danceFloorGradientIncrement; } for (int i = 0; i < DANCE_FLOOR_LENGTH; i++) { for (int j = 0; j < DANCE_FLOOR_WIDTH; j++) { int nthVoxel = ((i * DANCE_FLOOR_WIDTH) + j); int item = nthVoxel % DANCE_FLOOR_VOXELS_PER_PACKET; ::danceFloorLights[i][j] = ::danceFloorPosition + glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE); details[item].s = lightScale; details[item].x = ::danceFloorLights[i][j].x; details[item].y = ::danceFloorLights[i][j].y; details[item].z = ::danceFloorLights[i][j].z; if (danceFloorColors[i][j] > 0) { int color = danceFloorColors[i][j] - 1; details[item].red = (::danceFloorOnColorA[color][0] + ((::danceFloorOnColorB[color][0] - ::danceFloorOnColorA[color][0]) * ::danceFloorGradient)); details[item].green = (::danceFloorOnColorA[color][1] + ((::danceFloorOnColorB[color][1] - ::danceFloorOnColorA[color][1]) * ::danceFloorGradient)); details[item].blue = (::danceFloorOnColorA[color][2] + ((::danceFloorOnColorB[color][2] - ::danceFloorOnColorA[color][2]) * ::danceFloorGradient)); } else if (::danceFloorColors[i][j] < 0) { int color = -(::danceFloorColors[i][j] + 1); details[item].red = (::danceFloorOnColorB[color][0] + ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) * ::danceFloorGradient)); details[item].green = (::danceFloorOnColorB[color][1] + ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) * ::danceFloorGradient)); details[item].blue = (::danceFloorOnColorB[color][2] + ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) * ::danceFloorGradient)); } else { int color = 0; details[item].red = (::danceFloorOnColorB[color][0] + ((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0]) * ::danceFloorGradient)); details[item].green = (::danceFloorOnColorB[color][1] + ((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1]) * ::danceFloorGradient)); details[item].blue = (::danceFloorOnColorB[color][2] + ((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2]) * ::danceFloorGradient)); } if (item == DANCE_FLOOR_VOXELS_PER_PACKET - 1) { ::voxelEditPacketSender->queueVoxelEditMessages(message, DANCE_FLOOR_VOXELS_PER_PACKET, (VoxelDetail*)&details); } } } }