2012-01-29 17:39:56 +00:00
|
|
|
#include "textures.h"
|
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2012-01-03 15:40:50 +00:00
|
|
|
#include <assert.h>
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-12-09 17:49:28 +00:00
|
|
|
#include "terrain/public.h"
|
2013-01-19 22:42:50 +00:00
|
|
|
#include "tools/lighting.h"
|
2012-12-09 17:49:28 +00:00
|
|
|
#include "renderer.h"
|
2012-01-29 17:39:56 +00:00
|
|
|
#include "tools.h"
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-08-26 13:06:42 +00:00
|
|
|
#define TEXTURES_MAX_LAYERS 50
|
2012-01-03 15:40:50 +00:00
|
|
|
|
2012-05-06 08:49:12 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
double thickness;
|
2012-05-06 08:49:12 +00:00
|
|
|
Vector3 location;
|
|
|
|
Vector3 normal;
|
2012-05-07 08:56:22 +00:00
|
|
|
TextureLayerDefinition* definition;
|
2012-05-06 08:49:12 +00:00
|
|
|
} TextureResult;
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
TexturesDefinition texturesCreateDefinition()
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
TexturesDefinition result;
|
|
|
|
|
2012-08-26 13:06:42 +00:00
|
|
|
result.layers = layersCreate(texturesGetLayerType(), TEXTURES_MAX_LAYERS);
|
2012-01-23 23:45:33 +00:00
|
|
|
|
|
|
|
return result;
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void texturesDeleteDefinition(TexturesDefinition* definition)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-08-26 13:06:42 +00:00
|
|
|
layersDelete(definition->layers);
|
2012-01-23 23:45:33 +00:00
|
|
|
}
|
2012-01-18 18:47:46 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void texturesCopyDefinition(TexturesDefinition* source, TexturesDefinition* destination)
|
|
|
|
{
|
2012-08-26 13:06:42 +00:00
|
|
|
layersCopy(source->layers, destination->layers);
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void texturesValidateDefinition(TexturesDefinition* definition)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-08-26 13:06:42 +00:00
|
|
|
layersValidate(definition->layers);
|
|
|
|
}
|
|
|
|
|
|
|
|
void texturesSave(PackStream* stream, TexturesDefinition* definition)
|
|
|
|
{
|
|
|
|
layersSave(stream, definition->layers);
|
|
|
|
}
|
|
|
|
|
|
|
|
void texturesLoad(PackStream* stream, TexturesDefinition* definition)
|
|
|
|
{
|
|
|
|
layersLoad(stream, definition->layers);
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureLayerDefinition* texturesLayerCreateDefinition()
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-08-26 13:06:42 +00:00
|
|
|
TextureLayerDefinition* result;
|
|
|
|
|
|
|
|
result = malloc(sizeof(TextureLayerDefinition));
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-08-26 13:06:42 +00:00
|
|
|
result->zone = zoneCreate();
|
|
|
|
result->bump_noise = noiseCreateGenerator();
|
2013-01-27 19:57:43 +00:00
|
|
|
noiseAddLevelsSimple(result->bump_noise, 8, 1.0, -0.5, 0.5);
|
2012-08-26 13:06:42 +00:00
|
|
|
result->bump_height = 0.1;
|
|
|
|
result->bump_scaling = 0.1;
|
|
|
|
result->material.base = COLOR_WHITE;
|
|
|
|
result->material.reflection = 0.0;
|
|
|
|
result->material.shininess = 0.0;
|
|
|
|
result->thickness = 0.0;
|
|
|
|
result->slope_range = 0.001;
|
|
|
|
result->thickness_transparency = 0.0;
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-01-03 15:40:50 +00:00
|
|
|
return result;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void texturesLayerDeleteDefinition(TextureLayerDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-24 13:16:20 +00:00
|
|
|
zoneDelete(definition->zone);
|
|
|
|
noiseDeleteGenerator(definition->bump_noise);
|
2012-08-26 13:06:42 +00:00
|
|
|
free(definition);
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void texturesLayerCopyDefinition(TextureLayerDefinition* source, TextureLayerDefinition* destination)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-04-03 19:33:40 +00:00
|
|
|
destination->material = source->material;
|
|
|
|
destination->bump_height = source->bump_height;
|
|
|
|
destination->bump_scaling = source->bump_scaling;
|
2012-05-05 22:07:02 +00:00
|
|
|
destination->thickness = source->thickness;
|
|
|
|
destination->slope_range = source->slope_range;
|
2012-05-06 08:49:12 +00:00
|
|
|
destination->thickness_transparency = source->thickness_transparency;
|
2012-01-24 13:16:20 +00:00
|
|
|
noiseCopy(source->bump_noise, destination->bump_noise);
|
|
|
|
zoneCopy(source->zone, destination->zone);
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void texturesLayerValidateDefinition(TextureLayerDefinition* definition)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-04-27 20:52:05 +00:00
|
|
|
if (definition->bump_scaling < 0.000001)
|
|
|
|
{
|
|
|
|
definition->bump_scaling = 0.000001;
|
|
|
|
}
|
2012-05-05 22:07:02 +00:00
|
|
|
if (definition->slope_range < 0.001)
|
|
|
|
{
|
|
|
|
definition->slope_range = 0.001;
|
|
|
|
}
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-08-26 13:36:46 +00:00
|
|
|
static void _texturesLayerSave(PackStream* stream, TextureLayerDefinition* layer)
|
|
|
|
{
|
|
|
|
zoneSave(stream, layer->zone);
|
|
|
|
noiseSaveGenerator(stream, layer->bump_noise);
|
|
|
|
packWriteDouble(stream, &layer->bump_height);
|
|
|
|
packWriteDouble(stream, &layer->bump_scaling);
|
|
|
|
materialSave(stream, &layer->material);
|
|
|
|
packWriteDouble(stream, &layer->thickness);
|
|
|
|
packWriteDouble(stream, &layer->slope_range);
|
|
|
|
packWriteDouble(stream, &layer->thickness_transparency);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _texturesLayerLoad(PackStream* stream, TextureLayerDefinition* layer)
|
|
|
|
{
|
|
|
|
zoneLoad(stream, layer->zone);
|
|
|
|
noiseLoadGenerator(stream, layer->bump_noise);
|
|
|
|
packReadDouble(stream, &layer->bump_height);
|
|
|
|
packReadDouble(stream, &layer->bump_scaling);
|
|
|
|
materialLoad(stream, &layer->material);
|
|
|
|
packReadDouble(stream, &layer->thickness);
|
|
|
|
packReadDouble(stream, &layer->slope_range);
|
|
|
|
packReadDouble(stream, &layer->thickness_transparency);
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerType texturesGetLayerType()
|
|
|
|
{
|
|
|
|
LayerType result;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-08-26 13:36:46 +00:00
|
|
|
result.callback_create = (LayerCallbackCreate)texturesLayerCreateDefinition;
|
|
|
|
result.callback_delete = (LayerCallbackDelete)texturesLayerDeleteDefinition;
|
|
|
|
result.callback_copy = (LayerCallbackCopy)texturesLayerCopyDefinition;
|
|
|
|
result.callback_validate = (LayerCallbackValidate)texturesLayerValidateDefinition;
|
|
|
|
result.callback_save = (LayerCallbackSave)_texturesLayerSave;
|
|
|
|
result.callback_load = (LayerCallbackLoad)_texturesLayerLoad;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-08-26 13:36:46 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west)
|
2012-04-30 19:04:39 +00:00
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
Vector3 dnorth, deast, dsouth, dwest, normal;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
dnorth = v3Sub(north, center);
|
|
|
|
deast = v3Sub(east, center);
|
|
|
|
dsouth = v3Sub(south, center);
|
|
|
|
dwest = v3Sub(west, center);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
normal = v3Cross(deast, dnorth);
|
|
|
|
normal = v3Add(normal, v3Cross(dsouth, deast));
|
|
|
|
normal = v3Add(normal, v3Cross(dwest, dsouth));
|
|
|
|
normal = v3Add(normal, v3Cross(dnorth, dwest));
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
return v3Normalize(normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Vector3 _getNormal2(Vector3 center, Vector3 east, Vector3 south)
|
|
|
|
{
|
|
|
|
return v3Normalize(v3Cross(v3Sub(south, center), v3Sub(east, center)));
|
2012-04-30 19:04:39 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
static inline TextureResult _getTerrainResult(Renderer* renderer, double x, double z, double detail)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
TextureResult result;
|
|
|
|
Vector3 center, north, east, south, west;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-04-30 19:04:39 +00:00
|
|
|
/* TODO This method is better suited in terrain.c */
|
2012-01-03 15:40:50 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
center.x = x;
|
|
|
|
center.z = z;
|
2013-01-14 12:08:38 +00:00
|
|
|
center.y = renderer->terrain->getHeight(renderer, center.x, center.z, 1);
|
2012-01-03 15:40:50 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
east.x = x + detail;
|
|
|
|
east.z = z;
|
2013-01-14 12:08:38 +00:00
|
|
|
east.y = renderer->terrain->getHeight(renderer, east.x, east.z, 1);
|
2012-01-03 15:40:50 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
south.x = x;
|
|
|
|
south.z = z + detail;
|
2013-01-14 12:08:38 +00:00
|
|
|
south.y = renderer->terrain->getHeight(renderer, south.x, south.z, 1);
|
2012-01-03 15:40:50 +00:00
|
|
|
|
2012-04-30 19:04:39 +00:00
|
|
|
if (renderer->render_quality > 5)
|
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
west.x = x - detail;
|
|
|
|
west.z = z;
|
2013-01-14 12:08:38 +00:00
|
|
|
west.y = renderer->terrain->getHeight(renderer, west.x, west.z, 1);
|
2012-05-05 22:07:02 +00:00
|
|
|
|
|
|
|
north.x = x;
|
|
|
|
north.z = z - detail;
|
2013-01-14 12:08:38 +00:00
|
|
|
north.y = renderer->terrain->getHeight(renderer, north.x, north.z, 1);
|
2012-05-05 22:07:02 +00:00
|
|
|
|
|
|
|
result.normal = _getNormal4(center, north, east, south, west);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result.normal = _getNormal2(center, east, south);
|
2012-04-30 19:04:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
result.location = center;
|
|
|
|
result.thickness = -100.0;
|
2012-05-07 08:56:22 +00:00
|
|
|
result.definition = NULL;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
return result;
|
2012-04-30 19:04:39 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
static inline void _getLayerThickness(TextureLayerDefinition* definition, Renderer* renderer, double x, double z, TextureResult* result)
|
2012-04-30 19:04:39 +00:00
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
TextureResult base;
|
2012-06-17 09:40:40 +00:00
|
|
|
double coverage;
|
2012-05-05 22:07:02 +00:00
|
|
|
|
|
|
|
base = _getTerrainResult(renderer, x, z, definition->slope_range);
|
|
|
|
coverage = zoneGetValue(definition->zone, base.location, base.normal);
|
|
|
|
if (coverage > 0.0)
|
|
|
|
{
|
|
|
|
result->thickness = coverage * definition->thickness;
|
|
|
|
result->thickness += noiseGet2DTotal(definition->bump_noise, base.location.x / definition->bump_scaling, base.location.z / definition->bump_scaling) * definition->bump_height;
|
|
|
|
|
|
|
|
result->location = v3Add(base.location, v3Scale(base.normal, result->thickness));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result->thickness = -1000.0;
|
|
|
|
result->location = base.location;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
static inline TextureResult _getLayerResult(TextureLayerDefinition* definition, Renderer* renderer, double x, double z, double detail)
|
2012-05-05 22:07:02 +00:00
|
|
|
{
|
|
|
|
TextureResult result_center, result_north, result_east, result_south, result_west;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
_getLayerThickness(definition, renderer, x, z, &result_center);
|
|
|
|
_getLayerThickness(definition, renderer, x + detail, z, &result_east);
|
|
|
|
_getLayerThickness(definition, renderer, x, z + detail, &result_south);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-04-30 19:04:39 +00:00
|
|
|
if (renderer->render_quality > 5)
|
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
_getLayerThickness(definition, renderer, x - detail, z, &result_west);
|
|
|
|
_getLayerThickness(definition, renderer, x, z - detail, &result_north);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
result_center.normal = _getNormal4(result_center.location, result_north.location, result_east.location, result_south.location, result_west.location);
|
2012-04-30 19:04:39 +00:00
|
|
|
}
|
2012-05-05 22:07:02 +00:00
|
|
|
else
|
2012-04-30 19:04:39 +00:00
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
result_center.normal = _getNormal2(result_center.location, result_east.location, result_south.location);
|
2012-04-30 19:04:39 +00:00
|
|
|
}
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-07 08:56:22 +00:00
|
|
|
result_center.definition = definition;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
return result_center;
|
|
|
|
}
|
2012-04-30 19:04:39 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
static int _cmpResults(const void* result1, const void* result2)
|
|
|
|
{
|
|
|
|
return ((TextureResult*)result1)->thickness > ((TextureResult*)result2)->thickness;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
double texturesGetLayerCoverage(TextureLayerDefinition* definition, Renderer* renderer, Vector3 location, double detail)
|
2012-04-05 17:47:43 +00:00
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
TextureResult base = _getTerrainResult(renderer, location.x, location.z, definition->slope_range);
|
|
|
|
return zoneGetValue(definition->zone, base.location, base.normal);
|
2012-04-05 17:47:43 +00:00
|
|
|
}
|
|
|
|
|
2013-01-19 22:42:50 +00:00
|
|
|
static inline Color _getLayerColor(Renderer* renderer, TextureResult texture)
|
2012-05-07 08:56:22 +00:00
|
|
|
{
|
2013-01-22 13:32:39 +00:00
|
|
|
return renderer->applyLightingToSurface(renderer, texture.location, texture.normal, &texture.definition->material);
|
2012-05-07 08:56:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
Color texturesGetLayerColor(TextureLayerDefinition* definition, Renderer* renderer, Vector3 location, double detail)
|
2012-05-06 10:13:34 +00:00
|
|
|
{
|
2012-06-08 19:06:16 +00:00
|
|
|
TextureResult result = _getLayerResult(definition, renderer, location.x, location.z, detail);
|
2013-01-19 22:42:50 +00:00
|
|
|
return _getLayerColor(renderer, result);
|
2012-05-06 10:13:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
Color texturesGetColor(TexturesDefinition* definition, Renderer* renderer, double x, double z, double detail)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-05-05 22:07:02 +00:00
|
|
|
TextureResult results[TEXTURES_MAX_LAYERS + 1];
|
2012-05-07 08:56:22 +00:00
|
|
|
Color result, color;
|
2012-06-17 09:40:40 +00:00
|
|
|
double thickness, last_height;
|
2012-08-26 13:06:42 +00:00
|
|
|
int i, start, nblayers;
|
2012-01-18 18:47:46 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
detail *= 0.1;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-05 22:07:02 +00:00
|
|
|
results[0] = _getTerrainResult(renderer, x, z, detail);
|
2012-01-03 15:40:50 +00:00
|
|
|
|
2012-08-26 13:06:42 +00:00
|
|
|
nblayers = layersCount(definition->layers);
|
|
|
|
for (i = 0; i < nblayers; i++)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-08-26 13:06:42 +00:00
|
|
|
results[i + 1] = _getLayerResult(layersGetLayer(definition->layers, i), renderer, x, z, detail);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-08-26 13:06:42 +00:00
|
|
|
qsort(results, nblayers + 1, sizeof(TextureResult), _cmpResults);
|
2012-01-18 18:47:46 +00:00
|
|
|
|
2012-05-07 08:56:22 +00:00
|
|
|
/* Pre compute alpha channel */
|
|
|
|
start = 0;
|
2012-05-06 08:49:12 +00:00
|
|
|
last_height = results[0].thickness;
|
2012-07-10 19:39:12 +00:00
|
|
|
results[0].thickness = 1.0;
|
2012-08-26 13:06:42 +00:00
|
|
|
for (i = 1; i <= nblayers; i++)
|
2012-01-03 15:40:50 +00:00
|
|
|
{
|
2012-05-06 08:49:12 +00:00
|
|
|
thickness = results[i].thickness - last_height;
|
|
|
|
last_height = results[i].thickness;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-07 08:56:22 +00:00
|
|
|
if (results[i].definition)
|
|
|
|
{
|
|
|
|
if (thickness < results[i].definition->thickness_transparency)
|
|
|
|
{
|
|
|
|
results[i].thickness = thickness / results[i].definition->thickness_transparency;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
results[i].thickness = (thickness > 0.0) ? 1.0 : 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
results[i].thickness = 1.0;
|
|
|
|
}
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-07 08:56:22 +00:00
|
|
|
if (results[i].thickness >= 0.999999)
|
2012-05-06 08:49:12 +00:00
|
|
|
{
|
2012-05-07 08:56:22 +00:00
|
|
|
start = i;
|
2012-05-06 08:49:12 +00:00
|
|
|
}
|
2012-01-03 15:40:50 +00:00
|
|
|
}
|
2012-01-18 18:47:46 +00:00
|
|
|
|
2012-05-07 08:56:22 +00:00
|
|
|
/* Apply colors and alphas */
|
|
|
|
if (results[start].definition)
|
|
|
|
{
|
2013-01-19 22:42:50 +00:00
|
|
|
result = _getLayerColor(renderer, results[start]);
|
2012-05-07 08:56:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = COLOR_GREEN;
|
|
|
|
}
|
2012-08-26 13:06:42 +00:00
|
|
|
for (i = start + 1; i <= nblayers; i++)
|
2012-05-07 08:56:22 +00:00
|
|
|
{
|
|
|
|
if (results[i].thickness)
|
|
|
|
{
|
|
|
|
if (results[i].definition)
|
|
|
|
{
|
2013-01-19 22:42:50 +00:00
|
|
|
color = _getLayerColor(renderer, results[i]);
|
2012-05-07 08:56:22 +00:00
|
|
|
color.a = results[i].thickness;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
color = COLOR_GREEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
colorMask(&result, &color);
|
|
|
|
}
|
|
|
|
}
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
return result;
|
|
|
|
}
|