/* bzflag * Copyright (c) 1993 - 2006 Tim Riker * * This package is free software; you can redistribute it and/or * modify it under the terms of the license found in the file * named COPYING that should have accompanied this file. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* interface header */ #include "DynamicColor.h" /* system implementation headers */ #include #include #include /* common implementation headers */ #include "GameTime.h" #include "Pack.h" // this applies to all function periods const float DynamicColor::minPeriod = 0.01f; // // Dynamic Color Manager // DynamicColorManager DYNCOLORMGR; DynamicColorManager::DynamicColorManager() { return; } DynamicColorManager::~DynamicColorManager() { clear(); return; } void DynamicColorManager::clear() { std::vector::iterator it; for (it = colors.begin(); it != colors.end(); it++) { delete *it; } colors.clear(); return; } void DynamicColorManager::update() { const double gameTime = GameTime::getStepTime(); std::vector::iterator it; for (it = colors.begin(); it != colors.end(); it++) { DynamicColor* color = *it; color->update(gameTime); } return; } int DynamicColorManager::addColor(DynamicColor* color) { colors.push_back (color); return ((int)colors.size() - 1); } int DynamicColorManager::findColor(const std::string& dyncol) const { if (dyncol.size() <= 0) { return -1; } else if ((dyncol[0] >= '0') && (dyncol[0] <= '9')) { int index = atoi (dyncol.c_str()); if ((index < 0) || (index >= (int)colors.size())) { return -1; } else { return index; } } else { for (int i = 0; i < (int)colors.size(); i++) { if (colors[i]->getName() == dyncol) { return i; } } return -1; } } const DynamicColor* DynamicColorManager::getColor(int id) const { if ((id >= 0) && (id < (int)colors.size())) { return colors[id]; } else { return NULL; } } void * DynamicColorManager::pack(void *buf) const { std::vector::const_iterator it; buf = nboPackUInt(buf, (int)colors.size()); for (it = colors.begin(); it != colors.end(); it++) { const DynamicColor* color = *it; buf = color->pack(buf); } return buf; } void * DynamicColorManager::unpack(void *buf) { unsigned int i; uint32_t count; buf = nboUnpackUInt (buf, count); for (i = 0; i < count; i++) { DynamicColor* color = new DynamicColor; buf = color->unpack(buf); addColor(color); } return buf; } int DynamicColorManager::packSize() const { int fullSize = sizeof (uint32_t); std::vector::const_iterator it; for (it = colors.begin(); it != colors.end(); it++) { DynamicColor* color = *it; fullSize = fullSize + color->packSize(); } return fullSize; } void DynamicColorManager::print(std::ostream& out, const std::string& indent) const { std::vector::const_iterator it; for (it = colors.begin(); it != colors.end(); it++) { DynamicColor* color = *it; color->print(out, indent); } return; } // // Dynamic Color // DynamicColor::DynamicColor() { // setup the channels for (int c = 0; c < 4; c++) { // the parameters are setup so that all channels // are at 1.0f, and that there are no variations color[c] = 1.0f; channels[c].minValue = 0.0f; channels[c].maxValue = 1.0f; channels[c].sequence.count = 0; channels[c].sequence.list = NULL; } possibleAlpha = false; name = ""; return; } DynamicColor::~DynamicColor() { // sanitize the sequence value for (int c = 0; c < 4; c++) { sequenceParams& seq = channels[c].sequence; delete[] seq.list; } return; } void DynamicColor::finalize() { // sanitize the sequence value, and check for alpha middle values bool noAlphaSeqMid = true; for (int c = 0; c < 4; c++) { sequenceParams& seq = channels[c].sequence; for (unsigned int i = 0; i < seq.count; i++) { if (seq.list[i] < colorMin) { seq.list[i] = colorMin; } else if (seq.list[i] > colorMax) { seq.list[i] = colorMax; } else if ((c == 3) && (seq.list[i] == colorMid)) { noAlphaSeqMid = false; } } } // check if there might be translucency possibleAlpha = true; const ChannelParams& p = channels[3]; // the alpha channel if ((p.minValue == 1.0f) && (p.maxValue == 1.0f)) { // opaque regardless of functions possibleAlpha = false; } else { // check the a special sequence case const sequenceParams& seq = p.sequence; if ((seq.count > 0) && (noAlphaSeqMid && (p.minValue == 0.0f) && (p.maxValue == 1.0f))) { // transparency, not translucency possibleAlpha = false; } else { // check for the common case if ((p.sinusoids.size() == 0) && (p.clampUps.size() == 0) && (p.clampDowns.size() == 0) && (p.sequence.count == 0)) { // not using any functions if (p.maxValue == 1.0f) { possibleAlpha = false; } } } } return; } bool DynamicColor::setName(const std::string& dyncol) { if (dyncol.size() <= 0) { name = ""; return false; } else if ((dyncol[0] >= '0') && (dyncol[0] <= '9')) { name = ""; return false; } else { name = dyncol; } return true; } const std::string& DynamicColor::getName() const { return name; } void DynamicColor::setLimits(int channel, float min, float max) { if (min < 0.0f) { min = 0.0f; } else if (min > 1.0f) { min = 1.0f; } if (max < 0.0f) { max = 0.0f; } else if (max > 1.0f) { max = 1.0f; } channels[channel].minValue = min; channels[channel].maxValue = max; return; } void DynamicColor::setSequence(int channel,float period, float offset, std::vector& list) { sequenceParams& seq = channels[channel].sequence; delete[] seq.list; seq.list = NULL; seq.count = 0; if (period >= minPeriod) { seq.period = period; seq.offset = offset; seq.count = (unsigned int)list.size(); seq.list = new char[seq.count]; for (unsigned int i = 0; i < seq.count; i++) { seq.list[i] = list[i]; } } return; } void DynamicColor::addSinusoid(int channel, const float sinusoid[3]) { sinusoidParams params; // check period and weight if ((sinusoid[0] >= minPeriod) && (sinusoid[2] > 0.0f)) { params.period = sinusoid[0]; params.offset = sinusoid[1]; params.weight = sinusoid[2]; channels[channel].sinusoids.push_back(params); } return; } void DynamicColor::addClampUp(int channel, const float clampUp[3]) { clampParams params; // check period and width if ((clampUp[0] >= minPeriod) && (clampUp[2] > 0.0f)) { params.period = clampUp[0]; params.offset = clampUp[1]; params.width = clampUp[2]; channels[channel].clampUps.push_back(params); } return; } void DynamicColor::addClampDown(int channel, const float clampDown[3]) { clampParams params; // check period and width if ((clampDown[0] >= minPeriod) && (clampDown[2] > 0.0f)) { params.period = clampDown[0]; params.offset = clampDown[1]; params.width = clampDown[2]; channels[channel].clampDowns.push_back(params); } return; } void DynamicColor::update (double t) { for (int c = 0; c < 4; c++) { const ChannelParams& channel = channels[c]; unsigned int i; bool clampUp = false; bool clampDown = false; // sequence rules over the clamps const sequenceParams& seq = channel.sequence; if (seq.count > 0) { const double seqPeriod = (double)seq.period; const double fullPeriod = (double)seq.count * seqPeriod; double indexTime = (t - (double)seq.offset); if (indexTime < 0.0) { indexTime -= fullPeriod * floor(indexTime / fullPeriod); } indexTime = fmod (indexTime, fullPeriod); const unsigned int index = (unsigned int)(indexTime / seqPeriod); if (seq.list[index] == colorMin) { clampDown = true; } else if (seq.list[index] == colorMax) { clampUp = true; } } else { // check for active clampUp for (i = 0; i < channel.clampUps.size(); i++) { const clampParams& clamp = channel.clampUps[i]; double upTime = (t - (double)clamp.offset); const double clampPeriod = (double)clamp.period; if (upTime < 0.0) { upTime -= (double)clamp.period * floor(upTime / clampPeriod); } upTime = fmod (upTime, clampPeriod); if (upTime < (double)clamp.width) { clampUp = true; break; } } // check for active clampDown for (i = 0; i < channel.clampDowns.size(); i++) { const clampParams& clamp = channel.clampDowns[i]; double downTime = (t - (double)clamp.offset); const double clampPeriod = (double)clamp.period; if (downTime < 0.0) { downTime -= clampPeriod * floor(downTime / clampPeriod); } downTime = fmod (downTime, clampPeriod); if (downTime < (double)clamp.width) { clampDown = true; break; } } } // the amount of 'max' in the resultant channel's value float factor = 1.0f; // check the clamps if (clampUp && clampDown) { factor = 0.5f; } else if (clampUp) { factor = 1.0f; } else if (clampDown) { factor = 0.0f; } // no clamps, try sinusoids else if (channel.sinusoids.size() > 0) { float value = 0.0f; for (i = 0; i < channel.sinusoids.size(); i++) { const sinusoidParams& s = channel.sinusoids[i]; const double phase = ((t - (double)s.offset) / (double)s.period); const double clampedPhase = fmod(phase, 1.0); value += s.weight * (float)cos(clampedPhase * (M_PI * 2.0)); } // center the factor factor = 0.5f + (0.5f * value); if (factor < 0.0f) { factor = 0.0f; } else if (factor > 1.0f) { factor = 1.0f; } } color[c] = (channel.minValue * (1.0f - factor)) + (channel.maxValue * factor); } return; } void * DynamicColor::pack(void *buf) const { buf = nboPackStdString(buf, name); for (int c = 0; c < 4; c++) { const ChannelParams& p = channels[c]; unsigned int i; buf = nboPackFloat (buf, p.minValue); buf = nboPackFloat (buf, p.maxValue); // sinusoids buf = nboPackUInt (buf, (unsigned int)p.sinusoids.size()); for (i = 0; i < p.sinusoids.size(); i++) { buf = nboPackFloat (buf, p.sinusoids[i].period); buf = nboPackFloat (buf, p.sinusoids[i].offset); buf = nboPackFloat (buf, p.sinusoids[i].weight); } // clampUps buf = nboPackUInt (buf, (unsigned int)p.clampUps.size()); for (i = 0; i < p.clampUps.size(); i++) { buf = nboPackFloat (buf, p.clampUps[i].period); buf = nboPackFloat (buf, p.clampUps[i].offset); buf = nboPackFloat (buf, p.clampUps[i].width); } // clampDowns buf = nboPackUInt (buf, (unsigned int)p.clampDowns.size()); for (i = 0; i < p.clampDowns.size(); i++) { buf = nboPackFloat (buf, p.clampDowns[i].period); buf = nboPackFloat (buf, p.clampDowns[i].offset); buf = nboPackFloat (buf, p.clampDowns[i].width); } // sequence const sequenceParams& seq = p.sequence; buf = nboPackUInt (buf, seq.count); if (seq.count > 0) { buf = nboPackFloat (buf, seq.period); buf = nboPackFloat (buf, seq.offset); for (i = 0; i < seq.count; i++) { buf = nboPackUByte (buf, (uint8_t)seq.list[i]); } } } return buf; } void * DynamicColor::unpack(void *buf) { buf = nboUnpackStdString(buf, name); for (int c = 0; c < 4; c++) { ChannelParams& p = channels[c]; unsigned int i; uint32_t size; buf = nboUnpackFloat (buf, p.minValue); buf = nboUnpackFloat (buf, p.maxValue); // sinusoids buf = nboUnpackUInt (buf, size); p.sinusoids.resize(size); for (i = 0; i < size; i++) { buf = nboUnpackFloat (buf, p.sinusoids[i].period); buf = nboUnpackFloat (buf, p.sinusoids[i].offset); buf = nboUnpackFloat (buf, p.sinusoids[i].weight); } // clampUps buf = nboUnpackUInt (buf, size); p.clampUps.resize(size); for (i = 0; i < size; i++) { buf = nboUnpackFloat (buf, p.clampUps[i].period); buf = nboUnpackFloat (buf, p.clampUps[i].offset); buf = nboUnpackFloat (buf, p.clampUps[i].width); } // clampDowns buf = nboUnpackUInt (buf, size); p.clampDowns.resize(size); for (i = 0; i < size; i++) { buf = nboUnpackFloat (buf, p.clampDowns[i].period); buf = nboUnpackFloat (buf, p.clampDowns[i].offset); buf = nboUnpackFloat (buf, p.clampDowns[i].width); } // sequence buf = nboUnpackUInt (buf, size); sequenceParams& seq = p.sequence; seq.count = size; if (size > 0) { buf = nboUnpackFloat (buf, seq.period); buf = nboUnpackFloat (buf, seq.offset); seq.list = new char[size]; for (i = 0; i < size; i++) { uint8_t value; buf = nboUnpackUByte (buf, value); seq.list[i] = value; } } else { seq.list = NULL; } } finalize(); return buf; } int DynamicColor::packSize() const { int fullSize = nboStdStringPackSize(name); for (int c = 0; c < 4; c++) { fullSize += sizeof(float) * 2; // the limits fullSize += sizeof(uint32_t); fullSize += (int)(channels[c].sinusoids.size() * (sizeof(sinusoidParams))); fullSize += sizeof(uint32_t); fullSize += (int)(channels[c].clampUps.size() * (sizeof(clampParams))); fullSize += sizeof(uint32_t); fullSize += (int)(channels[c].clampDowns.size() * (sizeof(clampParams))); fullSize += sizeof(uint32_t); const sequenceParams& seq = channels[c].sequence; if (seq.count > 0) { fullSize += sizeof(float) * 2; // period and offset fullSize += seq.count * sizeof(char); } } return fullSize; } void DynamicColor::print(std::ostream& out, const std::string& indent) const { const char *colorStrings[4] = { "red", "green", "blue", "alpha" }; out << indent << "dynamicColor" << std::endl; if (name.size() > 0) { out << indent << " name " << name << std::endl; } for (int c = 0; c < 4; c++) { const char *colorStr = colorStrings[c]; const ChannelParams& p = channels[c]; if ((p.minValue != 0.0f) || (p.maxValue != 1.0f)) { out << indent << " " << colorStr << " limits " << p.minValue << " " << p.maxValue << std::endl; } unsigned int i; if (p.sequence.count > 0) { out << indent << " " << colorStr << " sequence " << p.sequence.period << " " << p.sequence.offset; for (i = 0; i < p.sequence.count; i++) { out << " " << (int)p.sequence.list[i]; } out << std::endl; } for (i = 0; i < p.sinusoids.size(); i++) { const sinusoidParams& f = p.sinusoids[i]; out << indent << " " << colorStr << " sinusoid " << f.period << " " << f.offset << " " << f.weight << std::endl; } for (i = 0; i < p.clampUps.size(); i++) { const clampParams& f = p.clampUps[i]; out << indent << " " << colorStr << " clampup " << f.period << " " << f.offset << " " << f.width << std::endl; } for (i = 0; i < p.clampDowns.size(); i++) { const clampParams& f = p.clampDowns[i]; out << indent << " " << colorStr << " clampdown " << f.period << " " << f.offset << " " << f.width << std::endl; } } out << indent << "end" << std::endl << std::endl; return; } // Local Variables: *** // mode:C++ *** // tab-width: 8 *** // c-basic-offset: 2 *** // indent-tabs-mode: t *** // End: *** // ex: shiftwidth=2 tabstop=8